Storage backend#
Backend settings allow you to configure one or more storage backends, such as S3, MinIO, and Azure Blob, that the Storage Service deployment can reach.
In the Helm chart, storage backend settings are located under the config.storage element.
Azure Blob backend#
The Azure Blob backend allows you to configure multiple Azure Blob storage endpoints. The table below provides an overview of top-level settings.
config.storage.azureBlob.readRedirectSize- Required:
no
- Type:
size
- Default:
256KiB
Minimum object size to use redirect (presigned URL) for reads.
config.storage.azureBlob.writeBodyMaxSize- Required:
no
- Type:
size
- Default:
2MiB
Maximum size for write requests through service body.
config.storage.azureBlob.writeRedirectMaxSize- Required:
no
- Type:
size
- Default:
64MiB
Maximum size for write redirects (presigned URLs).
config.storage.azureBlob.timeouts.connect- Required:
no
- Type:
duration
- Default:
60s
Connection establishment timeout.
config.storage.azureBlob.timeouts.read- Required:
no
- Type:
duration
- Default:
60s
Read operation timeout.
config.storage.azureBlob.timeouts.operation- Required:
no
- Type:
duration
- Default:
60s
Overall operation timeout.
config.storage.azureBlob.timeouts.operationAttempt- Required:
no
- Type:
duration
- Default:
60s
Single operation attempt timeout.
config.storage.azureBlob.timeouts.keepalive- Required:
no
- Type:
duration
- Default:
60s
Connection keep-alive timeout.
config.storage.azureBlob.expiration.presignedExpiration- Required:
no
- Type:
duration
- Default:
24h
How long presigned URLs remain valid.
config.storage.azureBlob.allowUnconfiguredEndpoints- Required:
no
- Type:
boolean
- Default:
false
Allow requests to arbitrary, undeclared storage accounts within the
*.blob.core.windows.netdomain.config.storage.azureBlob.nativeMetadataEnabled- Required:
no
- Type:
boolean
- Default:
false
Serve blob metadata. Azure returns it inline with a listing, so this backend has no fan-out setting.
config.storage.azureBlob.poolMaxIdlePerHost- Required:
no
- Type:
integer
Max idle HTTP connections per host in the reqwest pool; unset uses the reqwest default,
0disables idle pooling.config.storage.azureBlob.endpoints- Required:
no
- Type:
object
Endpoint-specific settings, see below.
Endpoint settings#
If you want to expose one or more Azure Blob storage accounts, you will need to declare them under the config.storage.azureBlob.endpoints object, using the storage account address as the key. The address must include a scheme and the storage account’s full domain name, for example https://<account>.blob.core.windows.net.
Endpoints support the following configuration parameters:
config.storage.azureBlob.endpoints.<name>.credentials- Required:
yes
- Type:
object
Provide authentication credentials for this backend, see below.
config.storage.azureBlob.endpoints.<name>.storageAccount- Required:
no
- Type:
string
Override the storage account name in the API calls.
config.storage.azureBlob.endpoints.<name>.metadataBackend- Required:
no
- Type:
string
Bind the storage account to a metadata backend. See Azure Blob metadata backend.
config.storage.azureBlob.endpoints.<name>.frontDoor- Required:
no
- Type:
object
Route reads through Azure Front Door, see below.
config.storage.azureBlob.endpoints.<name>.versioningEnabled- Required:
no
- Type:
boolean
- Default:
true
Explicitly enable or disable versioning support for this storage account. When omitted, versioning support is enabled.
config.storage.azureBlob.endpoints.<name>.readOnly- Required:
no
- Type:
boolean
- Default:
false
Declare this storage account read-only, so that clients present its contents without offering to modify them.
config.storage.azureBlob.endpoints.<name>.listInTopLevelAddresses- Required:
no
- Type:
boolean
- Default:
true
List this backend in
ListTopLevelAddresses.config.storage.azureBlob.endpoints.<name>.listInRoutes- Required:
no
- Type:
boolean
- Default:
true
List this backend in
ListRoutes(and, being a superset, inListTopLevelAddresses).config.storage.azureBlob.endpoints.<name>.permissionsEnabled- Required:
no
- Type:
boolean
- Default:
true
Whether to enforce permission checks for this endpoint,.
config:
storage:
azureBlob:
endpoints:
"https://mystorageacc.blob.core.windows.net":
# Place your endpoint settings here.
Metadata backend#
Use the config.storage.azureBlob.endpoints.<name>.metadataBackend configuration key to specify a binding between a storage account and a metadata backend:
config:
storage:
azureBlob:
endpoints:
"https://mystorageacc.blob.core.windows.net":
metadataBackend: my-metadata-backend-id
# Account-specific settings...
metadata:
my-metadata-backend-id:
# Metadata backend settings...
Authentication#
Backend authentication configuration is provided per storage account. For each storage account, you must either configure anonymous access explicitly or provide settings for one of the supported authentication flows.
Anonymous authentication#
Set the below parameter to true if you want to access the storage account without credentials.
config.storage.azureBlob.endpoints.<name>.credentials.anonymous- Required:
yes
- Type:
boolean
Whether to use anonymous authentication for this storage account.
Anonymous authentication grants no rights to modify the storage account, so the storage account is
always read-only, whatever config.storage.azureBlob.endpoints.<name>.readOnly is set to.
A backend configuration with anonymous authentication could look as follows:
config:
storage:
azureBlob:
endpoints:
"https://mystorageacc.blob.core.windows.net":
credentials:
anonymous: true
Storage key authentication#
You can use a storage key to authenticate against your storage account, although this is not recommended in production deployments as it provides unrestricted access to the storage account.
config.storage.azureBlob.endpoints.<name>.credentials.storageKey.storageKey- Required:
yes
- Type:
string
A key for the storage account.
A backend configuration with storage key authentication could look as follows:
config:
storage:
azureBlob:
endpoints:
# Inject the storage key from the environment variable called
# STORAGE_SERVICE_AZURE_STORAGE_KEY.
"https://mystorageacc.blob.core.windows.net":
credentials:
storageKey:
storageKey: "${STORAGE_SERVICE_AZURE_STORAGE_KEY}"
Service principal authentication#
As a more secure alternative, you can use client credentials of a service principal in Azure Entra ID.
config.storage.azureBlob.endpoints.<name>.credentials.clientSecret.tenantId- Required:
yes
- Type:
string
Azure Entra ID Tenant ID for service principal authentication.
config.storage.azureBlob.endpoints.<name>.credentials.clientSecret.clientId- Required:
yes
- Type:
string
Azure Entra ID Client ID for service principal authentication.
config.storage.azureBlob.endpoints.<name>.credentials.clientSecret.clientSecret- Required:
yes
- Type:
string
Azure Entra ID client secret for service principal authentication.
config.storage.azureBlob.endpoints.<name>.credentials.clientSecret.authorityHost- Required:
no
- Type:
string
Override the Azure Entra ID authority host.
A minimal configuration with service principal credentials could look as follows:
config:
storage:
azureBlob:
endpoints:
"https://mystorageacc.blob.core.windows.net":
credentials:
clientSecret:
tenantId: "94e63603-d604-480a-a221-557a203d1d1e"
clientId: "b866fb03-aca5-4278-bd84-b0fd4af748cd"
clientSecret: "${STORAGE_SERVICE_AZURE_ENTRA_ID_CLIENT_SECRET}"
Federated Credentials (Workload Identity) authentication#
Federated Credentials authentication allows the application to exchange an access token issued by an external OIDC provider for an Azure Entra ID access token.
config.storage.azureBlob.endpoints.<name>.credentials.federated.tenantId- Required:
yes
- Type:
string
Azure Entra ID Tenant ID for federated authentication.
config.storage.azureBlob.endpoints.<name>.credentials.federated.clientId- Required:
yes
- Type:
string
Azure Entra ID Client ID for federated authentication.
config.storage.azureBlob.endpoints.<name>.credentials.federated.federatedTokenFile- Required:
yes
- Type:
string
Path to the file containing the federated identity token.
config.storage.azureBlob.endpoints.<name>.credentials.federated.authorityHost- Required:
no
- Type:
string
The authority endpoint to request tokens from.
A configuration for the Workload Identity authentication could look as follows:
serviceAccount:
create: true
annotations:
azure.workload.identity/client-id: "<client-id-for-the-app-registration-in-azure-entra-id>"
azure.workload.identity/tenant-id: "<tenant-id-in-azure-entra-id>"
podLabels:
azure.workload.identity/use: "true"
config:
storage:
azureBlob:
endpoints:
"https://mystorageacc.blob.core.windows.net":
credentials:
federated:
# Don't inject any of these environment variables - the Workload
# Identity addon injects them automatically.
clientId: "${AZURE_CLIENT_ID}"
tenantId: "${AZURE_TENANT_ID}"
federatedTokenFile: "${AZURE_FEDERATED_TOKEN_FILE}"
authorityHost: "${AZURE_AUTHORITY_HOST}"
Delegated token credentials#
If none of the above credential flows meet your needs, you can delegate token acquisition to a separate process - for example, one running in a sidecar container. That process writes the credentials to a file with the following structure:
{
"expires_on": "Token expiration timestamp in RFC 3339 format",
"access_token": "eyJhbG.SflKxwRJSMeKK.dsF354gwwweW"
}
The token must be a bearer token scoped to Azure Storage (scope https://storage.azure.com/.default), refreshed no later than 60 seconds before expiry.
The token file provider supports the following configuration parameters:
config.storage.azureBlob.endpoints.<name>.credentials.accessTokenFile.path- Required:
yes
- Type:
string
Path to the file containing the access token.
A configuration for token file authentication could look as follows:
config:
storage:
azureBlob:
endpoints:
"https://mystorageacc.blob.core.windows.net":
credentials:
accessTokenFile:
path: "/etc/secrets/azure-access-token"
Azure Front Door CDN#
If you have an Azure Front Door CDN distribution for your storage account, you can reference it in the endpoint settings. When configured, the Storage Service redirects blob read requests to the distribution rather than sending them to the storage account.
config.storage.azureBlob.endpoints.<name>.frontDoor.url- Required:
yes
- Type:
string
Azure Front Door endpoint URL.
A configuration referencing an Azure Front Door CDN distribution could look as follows:
config:
storage:
azureBlob:
endpoints:
"https://mystorageacc.blob.core.windows.net":
frontDoor:
url: https://myfrontdoordistro-jSiZFrNbYlyye4n4Me90ipT8.a03.azurefd.net
Permissions#
You will need to configure the following policy for your service principal to read and write in the storage account:
{
"Name": "Storage Service Blob Access",
"Description": "Minimal permissions required for Storage Service to operate on Azure Blob Storage",
"Actions": [
"Microsoft.Storage/storageAccounts/blobServices/containers/read",
"Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey/action"
],
"NotActions": [],
"DataActions": [
"Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read",
"Microsoft.Storage/storageAccounts/blobServices/containers/blobs/write",
"Microsoft.Storage/storageAccounts/blobServices/containers/blobs/delete",
"Microsoft.Storage/storageAccounts/blobServices/containers/blobs/add/action",
"Microsoft.Storage/storageAccounts/blobServices/containers/blobs/move/action",
"Microsoft.Storage/storageAccounts/blobServices/containers/blobs/tags/read",
"Microsoft.Storage/storageAccounts/blobServices/containers/blobs/tags/write"
],
"NotDataActions": [],
"AssignableScopes": [
"/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<storage-account>"
]
}
Alternatively, you can use the built-in role of Storage Blob Data Contributor for the storage account. Note that this grants the service principal full control over storage containers.
S3 backend#
The S3 backend allows you to configure multiple S3-compatible storage endpoints, including AWS S3, MinIO, and others. The table below provides an overview of top-level settings.
config.storage.s3.readRedirectSize- Required:
no
- Type:
size
- Default:
256KiB
Minimum object size to use redirect (presigned URL) for reads.
config.storage.s3.writeBodyMaxSize- Required:
no
- Type:
size
- Default:
2MiB
Maximum size for write requests through service body.
config.storage.s3.writeRedirectMaxSize- Required:
no
- Type:
size
- Default:
64MiB
Maximum size for write redirects (presigned URLs).
config.storage.s3.timeouts.connect- Required:
no
- Type:
duration
- Default:
60s
Connection establishment timeout.
config.storage.s3.timeouts.read- Required:
no
- Type:
duration
- Default:
60s
Read operation timeout.
config.storage.s3.timeouts.operation- Required:
no
- Type:
duration
- Default:
60s
Overall operation timeout.
config.storage.s3.timeouts.operationAttempt- Required:
no
- Type:
duration
- Default:
60s
Single operation attempt timeout.
config.storage.s3.timeouts.keepalive- Required:
no
- Type:
duration
- Default:
60s
Connection keep-alive timeout.
config.storage.s3.expiration.presignedExpiration- Required:
no
- Type:
duration
- Default:
24h
How long presigned URLs remain valid.
config.storage.s3.allowUnconfiguredEndpoints- Required:
no
- Type:
boolean
- Default:
false
Allow requests to arbitrary, undeclared buckets within AWS S3 domains.
config.storage.s3.nativeMetadataEnabled- Required:
no
- Type:
boolean
- Default:
false
Serve object
x-amz-meta-*metadata.config.storage.s3.nativeMetadataListFanoutEnabled- Required:
no
- Type:
boolean
- Default:
false
Fetch native metadata for each object listed by
ListStat. S3 does not return it with a listing, so this costs one request per entry.Enable it together with
nativeMetadataEnabledunless both caches are disabled: the caches are filled fromListStat, and the service refuses to start on the inconsistent combination.config.storage.s3.endpoints- Required:
no
- Type:
object
Endpoint-specific settings, see below.
Endpoint settings#
If you want to expose one or more S3 buckets, you will need to declare them under the config.storage.s3.endpoints object, using the bucket address as the key. Bucket addresses must include a scheme and hostname, and may include a path. They are formatted as follows:
When the bucket name is encoded in the hostname of the bucket, for example:
https://<bucketname>.s3.<region-name>.amazonaws.com.When the bucket name is encoded in the first path segment, for example:
https://s3.<region-name>.amazonaws.com/<bucket-name>.
Endpoints support the following configuration parameters:
config.storage.s3.endpoints.<name>.credentials- Required:
yes
- Type:
object
Provide authentication credentials for this backend.
config.storage.s3.endpoints.<name>.bucket- Required:
no
- Type:
string
Override the bucket name for this bucket in API calls.
config.storage.s3.endpoints.<name>.region- Required:
no
- Type:
string
Override the region name for this bucket in API calls.
config.storage.s3.endpoints.<name>.endpointUrl- Required:
no
- Type:
string
Override the S3 API endpoint URL.
config.storage.s3.endpoints.<name>.addressingStyle- Required:
no
- Type:
string
- Default:
inferred from the endpoint name
S3 addressing style. When omitted, the style is inferred from the endpoint name: an endpoint name with a non-empty path uses path addressing; otherwise, virtual addressing is used. Supported values are:
virtual- Encode the bucket name in the hostname, for examplehttps://<bucket>.s3.<region>.amazonaws.com/<key>.path- Encode the bucket name in the URL path, for examplehttps://<host>/<bucket>/<key>.
config.storage.s3.endpoints.<name>.metadataBackend- Required:
no
- Type:
string
Bind the bucket to a metadata backend. See S3 metadata backend.
config.storage.s3.endpoints.<name>.versioningEnabled- Required:
no
- Type:
boolean
- Default:
true
Explicitly enable or disable versioning support for this bucket. When omitted, versioning support is enabled.
config.storage.s3.endpoints.<name>.readOnly- Required:
no
- Type:
boolean
- Default:
false
Declare this bucket read-only, so that clients present its contents without offering to modify them.
config.storage.s3.endpoints.<name>.permissionsEnabled- Required:
no
- Type:
boolean
- Default:
true
Whether to enforce permission checks for this endpoint,.
config.storage.s3.endpoints.<name>.listInTopLevelAddresses- Required:
no
- Type:
boolean
- Default:
true
List this backend in
ListTopLevelAddresses.config.storage.s3.endpoints.<name>.listInRoutes- Required:
no
- Type:
boolean
- Default:
true
List this backend in
ListRoutes(and, being a superset, inListTopLevelAddresses).
A configuration could look as follows:
config:
storage:
s3:
endpoints:
"https://mybucket.s3.us-west-2.amazonaws.com":
credentials:
accessKey:
accessKeyId: "${STORAGE_SERVICE_AWS_ACCESS_KEY_ID}"
secretAccessKey: "${STORAGE_SERVICE_AWS_SECRET_ACCESS_KEY}"
# Other bucket-specific settings...
"http://localhost.localdomain/privatebucket":
region: "us-east-1"
endpointUrl: "http://localhost.localdomain"
addressingStyle: "path"
credentials:
accessKey:
accessKeyId: "${STORAGE_SERVICE_MINIO_ACCESS_KEY_ID}"
secretAccessKey: "${STORAGE_SERVICE_MINIO_SECRET_ACCESS_KEY}"
"https://public-bucket.s3.us-east-1.amazonaws.com":
credentials:
anonymous: true
Metadata backend#
Use the config.storage.s3.endpoints.<name>.metadataBackend configuration key to specify a binding between a bucket and a metadata backend:
config:
storage:
s3:
endpoints:
"https://mybucket.s3.us-east-1.amazonaws.com":
metadataBackend: my-metadata-backend-id
# Account-specific settings...
metadata:
my-metadata-backend-id:
# Metadata backend settings...
Authentication#
Backend authentication settings are provided per bucket. For each bucket, you must either configure anonymous access explicitly or provide settings for one of the supported authentication flows.
Anonymous authentication#
Set the below parameter to true if you want to access the bucket without credentials.
config.storage.s3.endpoints.<name>.credentials.anonymous- Required:
yes
- Type:
boolean
Whether to use anonymous authentication for this bucket.
Anonymous authentication grants no rights to modify the bucket, so the bucket is always read-only,
whatever config.storage.s3.endpoints.<name>.readOnly is set to.
A backend configuration with anonymous authentication could look as follows:
config:
storage:
s3:
endpoints:
"https://publicbucket.s3.us-east-1.amazonaws.com":
credentials:
anonymous: true
Access Key credentials#
The following settings allow you to inject custom Access Key credentials to authenticate requests.
config.storage.s3.endpoints.<name>.credentials.accessKey.accessKeyId- Required:
yes
- Type:
string
AWS access key id.
config.storage.s3.endpoints.<name>.credentials.accessKey.secretAccessKey- Required:
yes
- Type:
string
AWS secret access key.
config.storage.s3.endpoints.<name>.credentials.accessKey.sessionToken- Required:
no
- Type:
string
AWS session token.
Note that like any other configuration parameters, these also support environment variable interpolation - you can always reference an environment variable instead of hardcoding the value:
config:
storage:
s3:
endpoints:
"https://privatebucket.s3.us-east-1.amazonaws.com":
credentials:
accessKey:
accessKeyId: "AKIAIOSFODNN7EXAMPLE"
secretAccessKey: "${STORAGE_SERVICE_AWS_SECRET_ACCESS_KEY}"
Assume Role credentials#
If your bucket belongs to a different AWS account, you will not normally be able to access it with your service credentials. When you provide the following settings, the Storage Service will use your service credentials to assume a role in the target AWS account.
config.storage.s3.endpoints.<name>.credentials.assumeRole.roleArn- Required:
yes
- Type:
string
AWS Role ARN.
config.storage.s3.endpoints.<name>.credentials.assumeRole.externalId- Required:
no
- Type:
string
External ID for the AssumeRole credentials.
config.storage.s3.endpoints.<name>.credentials.assumeRole.sessionName- Required:
no
- Type:
string
Session name for the AssumeRole credentials.
config.storage.s3.endpoints.<name>.credentials.assumeRole.sessionLength- Required:
no
- Type:
duration
Session length for the AssumeRole credentials.
A configuration could look as follows:
config:
storage:
s3:
endpoints:
# Will assume role arn:aws:iam::111122223333:role/myrole using the
# provided access key credentials
"https://bucket-a.s3.us-east-1.amazonaws.com":
credentials:
accessKey:
accessKeyId: "AKIAIOSFODNN7EXAMPLE"
secretAccessKey: "${STORAGE_SERVICE_AWS_SECRET_ACCESS_KEY}"
assumeRole:
roleArn: "arn:aws:iam::111122223333:role/myrole"
Web Identity Token (AWS IRSA) authentication#
The Web Identity Token flow allows the application to exchange an access token issued by an external OIDC provider for an AWS access key.
config.storage.s3.endpoints.<name>.credentials.webIdentityToken.webIdentityTokenFile- Required:
yes
- Type:
string
Access token file location.
config.storage.s3.endpoints.<name>.credentials.webIdentityToken.roleArn- Required:
yes
- Type:
string
AWS IAM role ARN for the application.
config.storage.s3.endpoints.<name>.credentials.webIdentityToken.roleSessionName- Required:
no
- Type:
string
Session name for the token.
A configuration for the AWS IRSA authentication could look as follows:
serviceAccount:
create: true
name: storage-service
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::<aws-account-id>:role/<aws-iam-role-name>
config:
storage:
s3:
endpoints:
"https://myprivatebucket.s3.eu-north-1.amazonaws.com":
credentials:
webIdentityToken:
# Don't inject any of the environment variables below - they
# are injected by the IRSA addon automatically.
webIdentityTokenFile: "${AWS_WEB_IDENTITY_TOKEN_FILE}"
roleArn: "${AWS_ROLE_ARN}"
Delegated access key credentials#
If none of the above credential flows meet your needs, you can delegate access key acquisition to a separate process - for example, one running in a sidecar container. That process writes the credentials to a file with the following structure:
{
"expires_on": "Credentials expiration timestamp in RFC 3339 format",
"access_key_id": "AKIAIOSFODNN7EXAMPLE",
"secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"session_token": "Optional, AQoDYXdzEJr..."
}
Credentials must be refreshed no later than 60 seconds before expiry.
The credentials file provider supports the following configuration parameters:
config.storage.s3.endpoints.<name>.credentials.credentialsFile.path- Required:
yes
- Type:
string
Path to the file containing the access key credentials.
A configuration for credentials file authentication could look as follows:
config:
storage:
s3:
endpoints:
"https://mybucket.s3.us-west-1.amazonaws.com":
credentials:
credentialsFile:
path: "/mnt/shared/aws-credentials"
CloudFront CDN#
If you have a configured CloudFront CDN distribution for your bucket, you can reference it in the settings. If configured, the Storage Service will redirect object read requests to the CDN rather than sending them to the bucket. If your distribution is not publicly accessible, you can provide the signing key as well.
config.storage.s3.endpoints.<name>.cloudfront.distributionUrl- Required:
yes
- Type:
string
CloudFront distribution URL.
config.storage.s3.endpoints.<name>.cloudfront.keyPairId- Required:
no
- Type:
string
CloudFront key pair ID used for signing requests.
config.storage.s3.endpoints.<name>.cloudfront.privateKeyPem- Required:
no
- Type:
string
Private key encoded in PEM format.
A configuration with CloudFront CDN for a bucket that uses a private key for signing requests to the CDN could look as follows:
config:
storage:
s3:
endpoints:
"https://bucket-a.s3.us-east-1.amazonaws.com":
credentials:
webIdentityToken:
webIdentityTokenFile: "${AWS_WEB_IDENTITY_TOKEN_FILE}"
roleArn: "${AWS_ROLE_ARN}"
cloudfront:
distributionUrl: "https://kV3gMLHdNLvEKqo8z9ezzxLC.cloudfront.net"
keyPairId: "wXv4ZvSPL8ITIZ9s4wgvLBrb"
privateKeyPem: "${STORAGE_SERVICE_CLOUD_FRONT_PRIVATE_KEY_PEM}"
Permissions#
You will need to configure the following policy for the service role to read and write in the bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "BucketLevelPermissions",
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:ListBucketVersions"
],
"Resource": "arn:aws:s3:::<bucket-name>"
},
{
"Sid": "ObjectLevelPermissions",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:PutObject",
"s3:DeleteObject",
"s3:DeleteObjectVersion",
"s3:AbortMultipartUpload",
"s3:ListMultipartUploadParts"
],
"Resource": "arn:aws:s3:::<bucket-name>/*"
}
]
}