Pixxel

Delivery Bucket Setup

Set up a bucket to receive your data

How to create credentials on AWS, Google Cloud, or Azure, and the exact permissions to grant so we can deliver data to your own storage.

Where to set this up

If you are using static credentials, meaning a key and a secret or a key file, you can set this up yourself in the Aurora UI at aurora.pixxel.space. That works today for all three providers.

The AWS IAM role option is different. It needs a workspace ID from us, so check with your Pixxel contact for that one.

Either way, grant the permissions in this guide first. Aurora checks your credentials when you save.

One naming note. What this guide calls a delivery bucket is called a cloud store in Aurora. They are the same thing.


What we do with your bucket

We write files into your bucket. We also read back and list what we wrote, so we can confirm a delivery arrived complete. We do not delete your files. The permissions stay small, and every section below shows the smallest set that works.

  1. You create the bucket or container in your own cloud account. It stays yours.
  2. You create credentials that can write to it and read back what was written.
  3. You send them to us once. We encrypt them before storing them.
  4. We write files in, then check they all arrived, under the path prefix you chose.

If you would rather we could not see anything else in the bucket, point the permissions at one folder and tell us to use that folder as the path prefix. Each provider section shows how.


What you send us

Four things, whichever provider you use.

FieldRequiredWhat it means
TypeYesS3, GCS, or AZBLOB
BucketYesThe bucket name, or the container name on Azure
RegionYesThe region your bucket lives in
Path prefixNoA folder we put every file under, for example pixxel/deliveries/
CredentialsYesThe secret values listed in your provider's section below

About region

On AWS the region must match the real region of your bucket, or writes will fail. On Google Cloud and Azure we do not use it to find your bucket, but we still ask for it so your records stay accurate.


Login methods we support

Pick one method per bucket. Send us only the fields for that method.

ProviderMethodNotes
AWS S3IAM role we assumeBest choice. No secret leaves your account, nothing to rotate
AWS S3IAM user access keyWorks. You have to rotate it yourself
AWS S3Temporary session credentialsExpires in hours. Good for a test only
Google Cloud StorageService account key fileThe only method we support on Google Cloud
Azure Blob StorageEntra service principalBest choice. The only Azure option you can limit to one container
Azure Blob StorageStorage account keyWorks. Grants full access to the whole storage account
Azure Blob StorageConnection stringSame full access as an account key

AWS S3 — three methods

Option 1: IAM role

This is the option we recommend. You create a role in your AWS account and let our account assume it. No secret ever leaves your account, and there are no keys for you to rotate.

Ask us first

You need one thing from us before you start: your workspace ID. It is unique to you, and it stops anyone else from using your role by mistake. Our AWS account ID is 375894565286, and it is already filled in below.

1. Create the permission policy

This is the smallest policy that works. Replace YOUR-BUCKET with your bucket name.

PermissionWhy we need it
s3:PutObjectWrites the files. Big files upload in parts, and this covers every part
s3:AbortMultipartUploadCleans up those parts when an upload fails partway. Without it, failed uploads leave hidden parts behind that you still pay for
s3:GetObjectReads back a delivered file to confirm it arrived whole
s3:ListBucketLists what we delivered, so we can check nothing is missing

Note the two separate statements. s3:ListBucket acts on the bucket itself, so its resource ends at the bucket name with no /*. Putting it on the /* resource is a common mistake, and it fails quietly.

To limit us to one folder, point the first statement at that folder and add a matching condition to the second.

IAM permission policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PixxelWriteAndReadBack",
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:AbortMultipartUpload",
        "s3:GetObject"
      ],
      "Resource": "arn:aws:s3:::YOUR-BUCKET/*"
    },
    {
      "Sid": "PixxelListForDeliveryChecks",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::YOUR-BUCKET"
    }
  ]
}

Scoped to one folder:

{
  "Sid": "PixxelWriteAndReadBack",
  "Effect": "Allow",
  "Action": ["s3:PutObject", "s3:AbortMultipartUpload", "s3:GetObject"],
  "Resource": "arn:aws:s3:::YOUR-BUCKET/pixxel/*"
},
{
  "Sid": "PixxelListForDeliveryChecks",
  "Effect": "Allow",
  "Action": "s3:ListBucket",
  "Resource": "arn:aws:s3:::YOUR-BUCKET",
  "Condition": {
    "StringLike": {
      "s3:prefix": "pixxel/*"
    }
  }
}

Then tell us to use pixxel/ as the path prefix.

2. Create the trust policy

This says who is allowed to assume the role.

IAM trust policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::375894565286:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": "YOUR-WORKSPACE-ID"
        }
      }
    }
  ]
}

Please keep the workspace ID check. It is the thing that makes sure only your own deliveries can use this role. sts:ExternalId is what AWS calls the field. The value that goes in it is your workspace ID.

3. Send us the details

FieldValueAPI name
Role ARNThe ARN of the role you just maderole_arn
Workspace IDThe same one you put in the trust policyexternal_id

Both are required. A role sent without a workspace ID will not be accepted.

If you use our API:

{
  "name": "my-delivery-bucket",
  "type": "S3",
  "configs": {
    "bucket": "YOUR-BUCKET",
    "region": "us-west-2",
    "path_prefix": "pixxel/"
  },
  "secrets": {
    "role_arn": "arn:aws:iam::YOUR-ACCOUNT-ID:role/YourRoleName",
    "external_id": "YOUR-WORKSPACE-ID"
  }
}

Option 2: IAM user access key

Create an IAM user, attach the same permission policy from step 1 (both statements), and create an access key for it.

FieldValueAPI name
Access key IDStarts with AKIAaccess_key_id
Secret access keyThe secret shown once at creationsecret_access_key

These keys never expire on their own, so rotation is on you. Read the note on rotation further down before you pick this option.

Option 3: Temporary session credentials

If your security team issues short-lived credentials from AWS STS, we accept those too.

FieldValueAPI name
Access key IDStarts with ASIAaccess_key_id
Secret access keyThe matching secretsecret_access_key
Session tokenThe session tokensession_token

These stop working when the session expires, usually within a few hours. Deliveries start failing at that point. Use this for a short test only.

If your bucket uses KMS encryption

A bucket encrypted with a customer managed KMS key needs extra permissions, or writes are denied. Add these to the key policy, or to the role or user policy.

A bucket using the default S3 managed encryption needs nothing extra.

KMS statement:

{
  "Effect": "Allow",
  "Action": [
    "kms:GenerateDataKey",
    "kms:Encrypt"
  ],
  "Resource": "arn:aws:kms:REGION:YOUR-ACCOUNT-ID:key/YOUR-KEY-ID"
}

Google Cloud Storage — one method

We support one login method: a service account key file.

Not supported

We do not accept workload identity federation or any other credential type. If the JSON file does not say "type": "service_account", we reject it.

1. Create a service account

gcloud iam service-accounts create pixxel-delivery \
  --display-name="Pixxel delivery"

2. Grant it access to your bucket

Grant on the bucket, not the whole project. That keeps the access narrow.

gcloud storage buckets add-iam-policy-binding gs://YOUR-BUCKET \
  --member="serviceAccount:pixxel-delivery@YOUR-PROJECT.iam.gserviceaccount.com" \
  --role="roles/storage.objectUser"
RoleWhat it allows
roles/storage.objectUserCreate, read, list, and replace. One role that covers everything, and what we suggest
roles/storage.objectCreator plus roles/storage.objectViewerThe same, minus replace. Use this pair if you never want an existing file overwritten

The second option cannot overwrite. If a delivery ever rewrites a file at the same path, it fails with a permission error. If you expect repeat deliveries to the same paths, use objectUser.

roles/storage.objectCreator on its own is not enough any more. It cannot read or list, so we would have no way to confirm a delivery finished.

For a custom role, these are the permissions we need:

PermissionWhy we need it
storage.objects.createWrites the files
storage.objects.getReads back a delivered file to confirm it arrived whole
storage.objects.listLists what we delivered, so we can check nothing is missing
storage.objects.deleteOnly needed so a delivery can replace a file at a path that already exists. Google counts an overwrite as a delete

Grant these on the bucket, or on a single folder if you would rather keep us to one.

3. Create a key

gcloud iam service-accounts keys create key.json \
  --iam-account=pixxel-delivery@YOUR-PROJECT.iam.gserviceaccount.com

4. Send us the details

FieldValueAPI name
Project IDYour Google Cloud project IDproject_id
Service account keyThe full contents of key.jsonservice_account_credentials

Send the whole file contents. Not a file path, and not just the private key.

We ask Google only for read and write access to storage. We cannot use the key for anything else in your project.


Azure Blob Storage — three methods

We try these in the order below, so send us only the fields for the one you picked.

Option 1: Entra service principal

This is the option we recommend. It is the only Azure method you can limit to a single container. The other two give access to the whole storage account.

1. Create an app registration and service principal

az ad app create --display-name pixxel-delivery
az ad sp create --id <app-id>

2. Create a client secret

az ad app credential reset --id <app-id>

Note the secret value now. Azure shows it only once.

3. Grant access to the container

Set the scope to the container, not the storage account, so the access stays narrow.

az role assignment create \
  --assignee <app-id> \
  --role "Storage Blob Data Contributor" \
  --scope "/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<account-name>/blobServices/default/containers/<container-name>"

Storage Blob Data Contributor covers what we do, reading back and listing included. For a custom role instead, these are the data actions we need:

Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read
Microsoft.Storage/storageAccounts/blobServices/containers/blobs/write
Microsoft.Storage/storageAccounts/blobServices/containers/blobs/add/action

The read action covers both reading a blob back and listing the container.

4. Send us the details

FieldValueAPI name
Account nameYour storage account nameaccount_name
Tenant IDYour Entra tenant IDtenant_id
Client IDThe app registration IDclient_id
Client secretThe secret from step 2client_secret

Client secrets expire, and Azure sets a lifetime when you create one. Put a reminder in your calendar, and read the note on rotation below.

Option 2: Storage account key

FieldValueAPI name
Account nameYour storage account nameaccount_name
Account keyEither of the two account keysaccount_key

Know what this grants

A storage account key gives full control of every container in that account, including read and delete. It cannot be narrowed. We only write, but the key itself is not limited. Use option 1 if you can.

Option 3: Connection string

FieldValueAPI name
Connection stringAzure Portal, then Storage account, then Access keysconnection_string

A connection string contains an account key, so it carries the same full access as option 2. The same warning applies.


Things worth knowing

Saving credentials does not test your bucket

When you save a delivery bucket with us, we check that your credentials are real and well formed. We do not write a test file at that moment.

So a bucket can save cleanly and still fail on the first delivery, usually because a permission is missing or the bucket name is wrong. If that happens, check the permission policy first. We suggest running one small delivery right after setup to confirm the whole path works.

Credentials cannot be edited later

A delivery bucket is fixed once created. You can rename it and change its labels, but you cannot change the bucket, the region, or the credentials.

To rotate a key or a client secret, create a new delivery bucket with the new credentials, switch your deliveries over to it, then delete the old one. This is one more reason to prefer the AWS IAM role and the Azure service principal. With an IAM role there is nothing to rotate at all.

Paths and overwrites

Every file we write goes under the path prefix you gave us. Set the prefix to pixxel/ and a file named scene.tif lands at pixxel/scene.tif.

If a delivery writes to a path that already holds a file, the old file is replaced. If you do not want that, use a different path prefix for each delivery, or turn on object versioning on your bucket.

Your credentials are encrypted

We encrypt your credentials before storing them. They are never returned by our API, never shown in our interface, and are only decrypted at the moment a delivery runs.


Before you tell us you are ready

  • The bucket or container exists, and I know its exact name and region.
  • The credentials can write to that bucket, and read and list what was written.
  • AWS role only: the trust policy names the Pixxel account ID and my workspace ID.
  • AWS with a customer managed KMS key: the key permissions are added.
  • Google Cloud: the key file says "type": "service_account".
  • Azure: I picked one method and am sending only those fields.
  • I noted any expiry date, so I can plan a swap before it lapses.

If a delivery fails, send us the error message. It tells us which side the problem is on, and it usually points straight at the missing permission.

Please check with your Pixxel contact that you have the current version of this guide before you start.