> For the complete documentation index, see [llms.txt](https://docs.zerve.ai/self-managed/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.zerve.ai/self-managed/configuration/object-storage.md).

# Object Storage

The `storage` block of the [Execution Environment Manifest](/self-managed/configuration/execution-environment-manifest.md) defines where Zerve stores its state, artifacts, intermediate block data and run logs. Supported storage types are:

* `s3` — AWS S3, and any store exposing the S3 API: MinIO, Ceph/Rook, Nexus Blob Store and the like
* `vast` — VAST, which speaks S3 but pins the region
* `gcs` — Google Cloud Storage
* `abs` — Azure Blob Storage

Snippets below start at the manifest root, so in your values file they go under `executor.execEnvManifest`. Fields marked `(ref)` accept a [reference value](/self-managed/configuration/execution-environment-manifest.md#reference-values) instead of a literal.

## Choosing a store

{% tabs %}
{% tab title="S3-compatible" %}
For MinIO, Ceph/Rook, Nexus Blob Store and other stores exposing the S3 API. `endpointUrl` is required and identifies the store.

```yaml
storage:
  type: s3
  bucketName: my-bucket                    # (ref) required
  endpointUrl: https://minio.example.com   # (ref) required for non-AWS endpoints
  regionName: us-east-1                    # (ref) optional — required by some stores
  caPath: /etc/ssl/certs/ca.crt            # (ref) optional — CA bundle for TLS verification
  skipTlsVerify: false                     # optional — see TLS verification below
  downscopingRoleArn:                      # (ref) optional — recommended, see below
  auth:                                    # optional — omit to use instance/IRSA credentials
    type: aws_static_creds
    accessKeyId:     { ref: env, name: S3_ACCESS_KEY }    # (ref) required
    secretAccessKey: { ref: env, name: S3_SECRET_KEY }    # (ref) required
    sessionToken:    { ref: env, name: S3_SESSION_TOKEN } # (ref) optional
```

{% endtab %}

{% tab title="AWS S3" %}
On AWS, leave `endpointUrl` unset; the region determines the endpoint. If Zerve runs with an EC2 instance profile, EKS IRSA or Pod Identity, omit `auth` to use those credentials.

```yaml
storage:
  type: s3
  bucketName: my-bucket   # (ref) required
  regionName: eu-west-1   # (ref) optional
  downscopingRoleArn: arn:aws:iam::123456789:role/zerve-execution-storage  # (ref) optional
  # auth omitted — instance role / IRSA
```

To use a role instead of long-lived keys:

```yaml
storage:
  type: s3
  bucketName: my-bucket
  auth:
    type: aws_assume_role
    roleArn: arn:aws:iam::123456789:role/my-role  # (ref) required
    externalId: my-external-id                    # (ref) optional
    sourceCredentials:  # optional — the identity that assumes the role.
      type: aws_static_creds                        # Omit to assume from the instance/IRSA role.
      accessKeyId:     { ref: env, name: S3_ACCESS_KEY }
      secretAccessKey: { ref: env, name: S3_SECRET_KEY }
```

{% endtab %}

{% tab title="VAST" %}
VAST implements the S3 protocol but has no regions, so `regionName` only accepts the literal `pseudo`. `endpointUrl` and `auth` are both required; there are no ambient credentials to fall back on.

```yaml
storage:
  type: vast
  bucketName: my-vast-bucket             # (ref) required
  endpointUrl: https://vast.example.com  # (ref) required
  regionName: pseudo                     # optional — `pseudo` is the only accepted value
  caPath: /etc/ssl/certs/ca.crt          # (ref) optional — omit for HTTP endpoints
  downscopingRoleArn:                    # (ref) optional — supported from VAST 5.4, see below
  auth:
    type: aws_static_creds
    accessKeyId:     { ref: env, name: VAST_ACCESS_KEY }   # (ref) required
    secretAccessKey: { ref: env, name: VAST_SECRET_KEY }   # (ref) required
```

VAST is configured like an S3-compatible store; everything else in the S3 sections applies here too.
{% endtab %}

{% tab title="Google Cloud Storage" %}

```yaml
storage:
  type: gcs
  bucketName: zerve-artifacts   # (ref) required
  projectId: my-gcp-project     # (ref) required
  auth:                         # optional — omit to use the ambient service account
    type: gcp_impersonation
    targetPrincipal: zerve-executor@my-gcp-project.iam.gserviceaccount.com  # (ref) required
    targetScopes:               # optional, default as shown
      - https://www.googleapis.com/auth/cloud-platform
```

With `auth` omitted, Zerve uses the credentials available in the environment: Workload Identity on GKE, or a key file referenced by `GOOGLE_APPLICATION_CREDENTIALS`. With `gcp_impersonation`, it issues tokens for `targetPrincipal`, which requires the ambient identity to hold `roles/iam.serviceAccountTokenCreator` on that principal.

`downscopingRoleArn` has no GCS equivalent and is not needed: credentials are downscoped for every run automatically, using a credential access boundary limited to `canvases/<scope>/` within the bucket and to the `roles/storage.objectUser` permission set.
{% endtab %}

{% tab title="Azure Blob Storage" %}

```yaml
storage:
  type: abs
  bucketName: zerve-artifacts           # (ref) required — the blob container name
  storageAccountName: myzervestorage    # (ref) required
  auth:                                 # required
    type: azure_client_secret
    tenantId:     { ref: env, name: AZURE_TENANT_ID }      # (ref) required
    clientId:     { ref: env, name: AZURE_CLIENT_ID }      # (ref) required
    clientSecret: { ref: env, name: AZURE_CLIENT_SECRET }  # (ref) required
```

`bucketName` is the container within the storage account. `auth` is required, so a service principal is always needed.

Per-run scoping is automatic, as with GCS: Zerve requests a user delegation key and issues a directory SAS over `canvases/<scope>`, valid for 12 hours. This requires a hierarchical namespace (ADLS Gen2) on the account, and the service principal needs both **Storage Blob Delegator** and a data-plane role such as **Storage Blob Data Contributor**.
{% endtab %}
{% endtabs %}

## TLS verification

For the S3 and VAST types, an omitted `caPath` does not disable verification:

| Configuration                     | Result                                              |
| --------------------------------- | --------------------------------------------------- |
| `endpointUrl` unset (AWS)         | Verified against the system trust store             |
| `https://` endpoint, no `caPath`  | Verified against the system trust store             |
| `https://` endpoint with `caPath` | Verified against that CA bundle                     |
| `http://` endpoint                | No TLS                                              |
| `skipTlsVerify: true`             | Verification disabled, regardless of other settings |

For a store with a private or self-signed certificate, mount your internal CA and set `caPath` to it. `skipTlsVerify` is intended for bring-up and test installs only, and should not be used in production.

## Downscoping role

Setting `downscopingRoleArn` is strongly recommended on S3 and on VAST 5.4 and later. The role must be trusted by the identity configured in `storage.auth`, and allow list/read/write/delete on the bucket.

Zerve assumes this role with a restricted session policy for every run, so code can only access the data belonging to its own Notebook. Without it, runs receive the credentials from `storage.auth` unchanged, giving user code full access to the bucket.

## Tuning the S3 client

`botoConfig` applies to the S3 and VAST types only, and is intended for stores that require a specific dialect of the S3 protocol. The most common setting is addressing style: stores that do not support virtual-host-style buckets require `path`.

```yaml
storage:
  type: s3
  # ...
  botoConfig:
    signatureVersion: s3v4
    connectTimeout: 10
    readTimeout: 60
    maxPoolConnections: 50
    s3:
      addressingStyle: path   # auto (default) | virtual | path
      payloadSigningEnabled: true
    requestChecksumCalculation: when_required  # when_supported (default) | when_required
```

Keys are camelCase here too, and map onto the corresponding [botocore client configuration](https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html) options, which document the full list. Omit this block, or set only the fields your storage vendor requires.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.zerve.ai/self-managed/configuration/object-storage.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
