Skip to content

Azure Blob Storage

Azure Blob Storage is Microsoft’s object storage service. It can serve as the blob store, holding message contents, files and other blobs in a container of an Azure Storage Account. Stalwart talks to it through the native Blob Storage API. All the nodes of a cluster can share the same container.

The backend is selected with the Azure variant of the BlobStore object (found in the WebUI under Settings › Storage › Blob Store). storageAccount names the Storage Account and container the container, which must already exist. keyPrefix prepends a fixed prefix to every blob name, so that several servers can share one container.

Stalwart derives the address of the service from the storage account and the environment, which names the Azure cloud: public for the global Azure cloud, china for Azure China, or us-government for Azure Government. The environment also selects the Microsoft Entra ID authority that the token-based authentication methods use. When the derived address is not the right one, url replaces it, for example for a private endpoint or for the Azurite emulator.

timeout limits the duration of each request. A failed request is retried up to maxRetries times, and 0 disables retries. When the retries are exhausted, the operation that needed the blob fails.

Azure offers several ways for an application to prove its identity, and the right one depends on where Stalwart runs. The auth field selects the method. Secrets can be given as a value, read from an environment variable or read from a file.

@typeFieldsUsed when
SharedKeyaccountKeyThe Storage Account’s access key is available to the server.
SasTokensasTokenAccess is granted by a shared access signature. The token must allow reading, writing and deleting blobs in the container; the leading ? is optional.
ClientSecrettenantId, clientId, clientSecretThe server authenticates as a Microsoft Entra ID service principal (an application registration) with a client secret.
ManagedIdentityclientId (optional)The server runs on an Azure resource with a managed identity, such as a virtual machine. Without clientId, the system-assigned identity is used; with it, the user-assigned identity of that client ID.
WorkloadIdentitytenantId, clientId, tokenFile (all optional)The server runs in Kubernetes with Microsoft Entra Workload ID. Empty fields are read from the AZURE_TENANT_ID, AZURE_CLIENT_ID and AZURE_FEDERATED_TOKEN_FILE environment variables that the workload identity webhook injects into the pod.

The token-based methods (ClientSecret, ManagedIdentity and WorkloadIdentity) authenticate an identity, and that identity must hold a role that permits reading, writing and deleting blobs in the container, such as Storage Blob Data Contributor.

The following blob store authenticates with the Storage Account’s access key, read from an environment variable:

{
"@type": "Azure",
"storageAccount": "examplemail",
"container": "stalwart",
"auth": {
"@type": "SharedKey",
"accountKey": {"@type": "EnvironmentVariable", "variableName": "AZURE_STORAGE_KEY"}
}
}

The following blob store runs in an Azure Kubernetes Service cluster with workload identity, and takes the tenant, the client and the token file from the pod environment:

{
"@type": "Azure",
"storageAccount": "examplemail",
"container": "stalwart",
"auth": {"@type": "WorkloadIdentity"}
}

The following blob store uses the user-assigned managed identity of a virtual machine:

{
"@type": "Azure",
"storageAccount": "examplemail",
"container": "stalwart",
"auth": {
"@type": "ManagedIdentity",
"clientId": "00000000-0000-0000-0000-000000000000"
}
}