---
title: "Connect storage locations"
description: "Connect S3, Google Cloud Storage, or Azure Blob Storage to Tilebox and receive notifications when new objects arrive."
image: "https://tilebox.com/images/tilebox-docs-social-preview.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://tilebox.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Connect storage locations

Add your bucket or container to the Tilebox Console as a storage location, then set up notifications from your cloud provider. You can use these notifications to trigger workflows when new objects arrive.

You need permission to add storage locations and subscriptions in Tilebox, and to configure notifications in your cloud account. Tilebox does not create cloud resources or ask for credentials to manage them or read your objects.

## Add a storage location

In the Console, open **Workflows → Storage → Connect bucket**. Select the provider, give the location a display name, and enter the details of your existing bucket or container:

| Provider | Bucket or container details |
| --- | --- |
| Amazon S3 | Bucket name and AWS region. Enter the name, not an `s3://` URL. |
| Google Cloud Storage | Bucket name and the project ID that owns the bucket. |
| Azure Blob Storage | Container name and the full storage-account resource ID. Copy the resource ID from the storage account's **Overview → JSON View**. |

Save the location. You can rename it later, but connecting a different bucket or container requires a new location.

## Prepare resources before adding a subscription

Your cloud provider needs a destination for its notifications. To get that destination, open the storage location in Tilebox and choose **Subscriptions → Add subscription**. This creates a Tilebox subscription and gives you a URL to use when configuring your cloud provider.

The dialog asks for different information depending on your provider. Follow the instructions below to get it:

- **[S3](#s3):** create or select an SNS topic, which receives notifications from your bucket. Enter its ARN in Tilebox.
- **[GCS](#gcs):** choose a Pub/Sub subscription name and create or select a service account for sending notifications. Enter the full subscription name and service-account email in Tilebox. You can create the cloud subscription after Tilebox gives you the destination URL.
- **[Azure](#azure):** create the Tilebox subscription first. Tilebox gives you the destination URL and a one-time secret to use in Event Grid.

After you save the subscription, Tilebox shows setup instructions for your provider. Copy the values shown there into your cloud configuration. Notifications start arriving only once you finish that cloud setup.

## S3

### Create or select the bucket and SNS topic

Use an existing S3 general purpose bucket, or create one in the AWS S3 console first. Record its name, region, and the bucket owner's 12-digit AWS account ID.

In Amazon SNS, select the bucket's region and open **Topics → Create topic**. Choose **Standard**, give the topic a name, and create it. You can also reuse a Standard topic in that region. Copy its ARN from the topic details into **SNS topic ARN** in Tilebox's **Add subscription** dialog, then save.

Your AWS identity needs permission to manage the topic policy, configure bucket notifications, and subscribe an HTTPS endpoint. These permissions stay in AWS; do not enter AWS access keys in Tilebox.

### Allow the bucket to publish to SNS

In the topic's access policy, add the following statement to the existing `Statement` array. Replace the placeholders with your topic ARN, bucket ARN, and verified bucket owner account ID. The bucket owner may differ from the topic owner; do not infer it from the topic ARN.

```json
{
  "Effect": "Allow",
  "Principal": { "Service": "s3.amazonaws.com" },
  "Action": "SNS:Publish",
  "Resource": "TOPIC_ARN",
  "Condition": {
    "ArnEquals": { "aws:SourceArn": "BUCKET_ARN" },
    "StringEquals": { "aws:SourceAccount": "BUCKET_OWNER_ACCOUNT_ID" }
  }
}
```

For the standard AWS partition, the bucket ARN is `arn:aws:s3:::BUCKET_NAME`. Use your partition's ARN when applicable. Do not replace the whole access policy with this statement or remove existing grants.

If the topic uses a customer-managed KMS key, its key policy must also allow the S3 service principal to use `kms:GenerateDataKey` and `kms:Decrypt`. See AWS's [destination permissions and KMS policy instructions](https://docs.aws.amazon.com/AmazonS3/latest/userguide/grant-destinations-permissions-to-s3.html).

### Send object-created events and subscribe the endpoint

1. In S3, open the bucket's **Properties → Event notifications**. Reuse a matching rule or add a rule for **All object create events** (`s3:ObjectCreated:*`) with your SNS topic as the destination.
2. Leave prefix and suffix filters empty unless you intentionally want to exclude events before they reach Tilebox. Preserve existing rules. If an overlapping rule already sends these events to a topic, reuse that route rather than adding a conflicting rule.
3. In SNS, open the topic and create a subscription with protocol **HTTPS**. Paste the **Endpoint** from Tilebox. Keep **raw message delivery disabled** so Tilebox receives the signed SNS envelope.
4. Tilebox handles SNS subscription confirmation automatically. Check that SNS shows the subscription as confirmed, then [check delivery](#check-delivery-and-event-history).

:::warning
The S3 `PutBucketNotificationConfiguration` API, including `aws s3api put-bucket-notification-configuration`, replaces the entire bucket notification configuration. If using the CLI or infrastructure code, read the existing configuration and merge the intended change, preserving SNS, SQS, Lambda, and EventBridge destinations. Review the complete result before applying it. Do not paste a one-rule example over a live bucket's configuration.
:::

AWS documents this replacement behavior in [PutBucketNotificationConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketNotificationConfiguration.html).

## GCS

### Choose the cloud resources and get the two dialog values

Use an existing Cloud Storage bucket, or create one under **Cloud Storage → Buckets** first. Record its owning project ID. Enable the Pub/Sub API in the project that will host the Pub/Sub resources, then create or select a topic under **Pub/Sub → Topics**.

The bucket, topic, and subscription can belong to different projects. The commands below name each project explicitly. Run them in an authenticated Google Cloud CLI session with permission to make these changes, replacing the uppercase placeholders. Skip creation commands for resources you already have.

```bash
gcloud services enable pubsub.googleapis.com --project=SUBSCRIPTION_PROJECT_ID
gcloud services enable pubsub.googleapis.com --project=TOPIC_PROJECT_ID
gcloud pubsub topics create TOPIC_ID --project=TOPIC_PROJECT_ID
```

If both resources use the same project, enable the API once.

**Pub/Sub subscription resource name:** this is a Google Cloud resource name, not a Tilebox ID or a topic name. For an existing subscription, open **Pub/Sub → Subscriptions**, select it, and copy its full name. You can also retrieve it with:

```bash
gcloud pubsub subscriptions describe SUBSCRIPTION_ID \
  --project=SUBSCRIPTION_PROJECT_ID --format='value(name)'
```

For a new subscription, choose its project and subscription ID now. Enter `projects/SUBSCRIPTION_PROJECT_ID/subscriptions/SUBSCRIPTION_ID` in Tilebox, substituting those chosen values. For example, `projects/my-processing-project/subscriptions/tilebox-uploads`. The subscription need not exist yet: create it after Tilebox returns the push endpoint. Do not enter a topic name such as `projects/.../topics/...`.

**Push service-account email:** in Google Cloud, open **IAM & Admin → Service Accounts** and select or create a service account for push authentication. It must belong to the same project as the Pub/Sub subscription. Copy its email, such as `tilebox-push@my-processing-project.iam.gserviceaccount.com`, into Tilebox. To create and inspect one with the CLI:

```bash
gcloud iam service-accounts create tilebox-push \
  --project=SUBSCRIPTION_PROJECT_ID \
  --display-name="Tilebox Pub/Sub push"

gcloud iam service-accounts describe \
  tilebox-push@SUBSCRIPTION_PROJECT_ID.iam.gserviceaccount.com \
  --project=SUBSCRIPTION_PROJECT_ID --format='value(email)'
```

Do not create or upload a service-account key. This account identifies authenticated push requests; it does not need permission to read the bucket's objects.

Enter the full subscription name and push service-account email in **Add subscription**, then save in Tilebox. Keep the returned **Endpoint** and **Audience** for the push configuration below.

### Grant the two service agents their delivery permissions

Cloud Storage publishes to the topic using the **bucket project's Cloud Storage service agent**. Retrieve its email with:

```bash
gcloud storage service-agent --project=BUCKET_PROJECT_ID
```

This command creates the service agent if necessary. Copy the returned email into `STORAGE_SERVICE_AGENT_EMAIL` below. Grant it publisher access on the topic, without changing other bindings:

```bash
gcloud pubsub topics add-iam-policy-binding TOPIC_ID \
  --project=TOPIC_PROJECT_ID \
  --member="serviceAccount:STORAGE_SERVICE_AGENT_EMAIL" \
  --role=roles/pubsub.publisher
```

Pub/Sub signs push requests using the **subscription project's Pub/Sub service agent**. This is a different identity from both the Cloud Storage service agent and your push service account. Get the subscription project's number and, if needed, create its service identity:

```bash
gcloud projects describe SUBSCRIPTION_PROJECT_ID --format='value(projectNumber)'
gcloud beta services identity create \
  --service=pubsub.googleapis.com --project=SUBSCRIPTION_PROJECT_ID
```

Use that project number in the member below. Grant token creation on the specific push service account rather than across the whole project:

```bash
gcloud iam service-accounts add-iam-policy-binding PUSH_SERVICE_ACCOUNT_EMAIL \
  --project=SUBSCRIPTION_PROJECT_ID \
  --member="serviceAccount:service-SUBSCRIPTION_PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com" \
  --role=roles/iam.serviceAccountTokenCreator
```

The person or service account configuring authenticated push also needs `iam.serviceAccounts.actAs` on the push account, for example through `roles/iam.serviceAccountUser` scoped to that account. They also need permissions to create or update the subscription and attach it to the topic. The identity configuring bucket notifications needs permission to update the bucket notification configuration. Ask your cloud administrator for these permissions; do not grant broad project roles to the push account itself.

See Google's [notification permissions](https://cloud.google.com/storage/docs/reporting-changes) and [push authentication requirements](https://cloud.google.com/pubsub/docs/authenticate-push-subscriptions).

### Configure authenticated push with Tilebox's returned values

In **Pub/Sub → Subscriptions → Create subscription**, use the exact subscription ID and project entered in Tilebox. Select the topic, choose **Push**, enable authentication, and select the same push service account. Paste Tilebox's endpoint and audience exactly. Keep **payload unwrapping disabled**: Tilebox expects the standard Pub/Sub JSON envelope.

Set the expiration policy to **Never expire** so the subscription is not deleted after 31 days without activity.

For a new subscription, the equivalent CLI command is:

```bash
gcloud pubsub subscriptions create SUBSCRIPTION_ID \
  --project=SUBSCRIPTION_PROJECT_ID \
  --topic=projects/TOPIC_PROJECT_ID/topics/TOPIC_ID \
  --push-endpoint='ENDPOINT_COPIED_FROM_TILEBOX' \
  --push-auth-service-account=PUSH_SERVICE_ACCOUNT_EMAIL \
  --push-auth-token-audience='AUDIENCE_COPIED_FROM_TILEBOX' \
  --expiration-period=never
```

If the subscription already exists, edit its push configuration instead of creating another subscription. Confirm that its topic is the one receiving bucket notifications, unwrapping is disabled, and its expiration policy is **Never expire**. Do not change a subscription used by an unrelated consumer.

### Connect the bucket to the topic

List existing notification configurations first:

```bash
gcloud storage buckets notifications list gs://BUCKET_NAME
```

Reuse a matching notification. If none exists, add one for `OBJECT_FINALIZE` with `JSON_API_V1` payloads. The CLI calls this payload format `json`:

```bash
gcloud storage buckets notifications create gs://BUCKET_NAME \
  --topic=projects/TOPIC_PROJECT_ID/topics/TOPIC_ID \
  --event-types=OBJECT_FINALIZE \
  --payload-format=json \
  --skip-topic-setup
```

`--skip-topic-setup` keeps this step from creating a topic or changing topic IAM; those were configured above. Allow IAM changes to propagate before running it. Preserve other notification configurations and avoid adding a second matching one. Cloud Storage notification configuration uses the CLI, API, or infrastructure tooling, not the Google Cloud console. Then [check delivery](#check-delivery-and-event-history).

## Azure

### Prepare the storage account and container

Use an existing storage account that supports Event Grid, such as a general-purpose v2 account, or create one in Azure first. Under **Data storage → Containers**, create or select the container. General-purpose v1 accounts do not support this integration.

Copy the storage account's full resource ID from **Overview → JSON View**, not its name or Blob URL. Its shape is:

```text
/subscriptions/AZURE_SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/Microsoft.Storage/storageAccounts/ACCOUNT_NAME
```

Use this resource ID and the container name when [adding the Tilebox location](#add-a-storage-location). Your Azure identity needs `Microsoft.EventGrid/eventSubscriptions/write` on the source resource to create the Event Grid subscription. Have your Azure administrator register the `Microsoft.EventGrid` resource provider if it is not already registered.

### Create the Tilebox subscription and save the secret

Choose **Add subscription** in Tilebox. Tilebox returns the endpoint, delivery secret header name, and a secret shown only at creation. Save the secret securely before closing the instructions, switching tabs, or leaving the page. Do not place it in source control, logs, URLs, or shared agent prompts.

The secret cannot be retrieved later. If it is lost, [replace the subscription](#replace-or-remove-a-subscription); there is no separate secret-retrieval or rotation step.

### Configure Event Grid delivery

1. In the Azure storage account, open **Events** and add an event subscription.
2. Select **Event Grid Schema**, not CloudEvents. Select only `Microsoft.Storage.BlobCreated` as the event type.
3. Choose **Web Hook** as the endpoint type and paste the full endpoint returned by Tilebox.
4. Under subject filters, set **Subject Begins With** to `/blobServices/default/containers/CONTAINER_NAME/blobs/`, replacing the container name and preserving the trailing slash. Enable case-sensitive matching. Leave **Subject Ends With** empty unless you intentionally want a suffix filter.
5. In **Delivery Properties**, add the header name returned by Tilebox as a **Static** property. Paste the one-time secret as its value and enable **Is secret**. Use the returned header name rather than choosing your own.
6. Save the Event Grid subscription. Tilebox handles the endpoint validation handshake automatically. The secret header must be present for validation as well as subsequent event delivery. A validation failure is not a reason to remove authentication; check the endpoint, schema, header name, and secret.

See Azure's [Blob Storage events](https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blob-event-overview), [Event Grid access control](https://learn.microsoft.com/en-us/azure/event-grid/security-authorization), and [static delivery headers](https://learn.microsoft.com/en-us/azure/event-grid/delivery-properties). Then check delivery below.

## Check delivery and event history

Once provider configuration is complete, upload a small test object to the connected bucket or container. Use a key that matches any provider-side filters and, if testing an automation, its glob pattern. A test upload can trigger real jobs and cloud charges; use a suitable test location or coordinate it with your team.

Open the location's **Event history** in Tilebox and refresh. Check the object key, provider event time, received time, and triggered jobs in your organization. An event in history confirms receipt; it does not prove that a job finished or that a runner can read the object. Open the linked job to inspect execution separately.

If no event appears, inspect provider delivery diagnostics, source filters, permissions, and destination configuration. For SNS, check confirmation and raw delivery. For Pub/Sub, check the full subscription name, topic, push identity, exact audience, and wrapped payload. For Event Grid, check validation, schema, container filter, and secret delivery property. A saved Tilebox subscription alone does not establish cloud delivery.

Provider retries and overlapping subscriptions can produce duplicate events and jobs. Tilebox does not deduplicate or replay notifications. Do not assume exactly-once or ordered delivery; make tasks safe to retry. Provider retry and retention limits still apply, so Event history is not a complete inventory of bucket contents.

To submit jobs for received events, [configure a storage-event automation](/docs/guides/operations/configure-storage-event-automations) on the location and run an eligible task runner. Configure object-read access separately in the runner's environment. Notification delivery grants neither Tilebox nor the runner permission to download objects.

:::note
On macOS, a running Python task that discovers GCS or Azure credentials through the local cloud CLI may print gRPC fork diagnostics such as "Other threads are currently calling into gRPC, skipping fork() handlers" or "FD from fork parent still in poll list". Reads and RPCs can still succeed; these messages alone do not indicate authentication or read failure. Investigate any accompanying authentication or read errors separately.
:::

## Replace or remove a subscription

To change subscription configuration or recover a lost Azure secret:

1. Create a new Tilebox subscription on the same location.
2. Configure the cloud delivery with its returned endpoint and authentication values. For GCS, use a new Pub/Sub subscription name for an overlapping replacement; do not register the same cloud subscription twice.
3. Check delivery, then remove the old provider delivery and delete the old Tilebox subscription.

Automations keep referencing the location. During overlap, both subscriptions may deliver the same event and create duplicate jobs. Choose a cutover appropriate for your workload; replacement is not an exactly-once migration.

For removal without replacement, remove provider delivery before deleting the Tilebox subscription to avoid continued provider retries. Deleting in Tilebox does not delete any cloud resource:

- **S3:** remove the corresponding SNS HTTPS subscription. Remove the bucket notification rule and topic only if no other consumers need them; preserve the rest of the notification configuration and topic policy.
- **GCS:** remove the corresponding Pub/Sub subscription. Remove the bucket notification configuration, topic, service account, and IAM grants only when no other consumers need them.
- **Azure:** remove the corresponding Event Grid event subscription. Do not delete the storage account or container to stop notifications.

Remove automation references before deleting the storage location. Deleting a subscription or location does not cancel jobs already submitted.

Source: https://tilebox.com/docs/guides/operations/connect-storage/index.mdx
