ObjectStorageConfig¶
ObjectStorageConfig is a namespaced contract kind that describes one bucket, for backups or for document storage, and how consumers authenticate to it. You create it, or another tool creates it for you.
The operator never creates a bucket. This kind carries the location of a bucket that exists, and the authentication choice. The producer of the bucket and the resources that write to it do not need to know each other. The operator checks the Secret that the contract names and reports the result on Ready.
| Role | Who |
|---|---|
| Producers | You, by hand, or another tool that provisions the bucket and creates the contract for you |
| Consumers | CamundaCluster (through backupStorageRef and documentStorageRef), ElasticsearchCluster (through snapshotStorageRef), DatabaseServer (through archive.objectStorageRef), LogicalBackupElasticsearch and LogicalBackupRDBMS (through the backupStorageRef of the cluster they back up) |
A consumer names the contract and reads it in its own namespace. A CamundaCluster in my-cluster-ns with backupStorageRef: my-backup-bucket reads the contract my-backup-bucket of my-cluster-ns. A contract of the same name in another namespace is a different bucket. Two consumers in one namespace can share one contract. A consumer in another namespace needs a contract of its own, even when both point at one bucket.
spec.type selects the storage API of the bucket. Exactly the block with the same name carries its fields: s3, gcs, or azureBlob. Each block has its own auth block, because the three storage types authenticate in different ways.
The smallest contract names an AWS bucket, accessed through IRSA (IAM Roles for Service Accounts on EKS):
apiVersion: core.camunda.io/v1
kind: ObjectStorageConfig
metadata:
name: my-backup-bucket
namespace: my-cluster-ns
spec:
type: S3
s3:
bucketName: my-cluster-backup-bucket
region: eu-west-1
auth:
type: workloadIdentity
workloadIdentity:
roleArn: "arn:aws:iam::123456789012:role/my-cluster-workload-role"
graph LR
EXT["Bucket provisioner (external)"] --> OSC[ObjectStorageConfig]
OSC -.->|auth.credentials.secretRef| SEC[Secret]
CC[CamundaCluster] -.->|backupStorageRef, documentStorageRef| OSC
EC[ElasticsearchCluster] -.->|snapshotStorageRef| OSC
DBS[DatabaseServer] -.->|archive.objectStorageRef| OSC
LBE[LogicalBackupElasticsearch] -.->|through the cluster backupStorageRef| OSC
LBR[LogicalBackupRDBMS] -.->|through the cluster backupStorageRef| OSC
Authentication¶
auth.type selects one of two mechanisms. workloadIdentity is the default. No credentials pass through Kubernetes. The cloud binds a principal to the ServiceAccount of the consuming pods, and each pod gets a token from its runtime. The optional workloadIdentity block names that principal. When you set it, the consumer writes the matching annotation on the ServiceAccount of its pods:
| Storage type | Field | Annotation on the ServiceAccount |
|---|---|---|
S3 |
roleArn |
eks.amazonaws.com/role-arn |
GCS |
serviceAccountEmail |
iam.gke.io/gcp-service-account |
AzureBlob |
clientId |
azure.workload.identity/client-id |
The operator writes the annotation only on a ServiceAccount that it creates. With serviceAccount.create: false, add the annotation to your ServiceAccount yourself.
On AzureBlob with workloadIdentity, the consumer also puts the label azure.workload.identity/use: "true" on its pods. The Azure webhook injects nothing into a pod without that label.
An empty or absent workloadIdentity block means that the consumer adds no annotation. The cloud then trusts the ServiceAccount of the pods as it is. Use it for mechanisms that need no annotation, for example EKS Pod Identity and GKE Workload Identity Federation. There the binding lives on the cloud side and names the ServiceAccount. The principal to bind is system:serviceaccount:<namespace>:<serviceAccount name> of the consuming resource. By default, that ServiceAccount is <name>-camunda for a CamundaCluster and <name>-es for an ElasticsearchCluster. For a DatabaseServer, it is <name>-postgres, and a rollback does not change it. See DatabaseServer.
credentials names a Secret of the namespace of the contract that holds a static key. Use it for S3-compatible storage such as MinIO or Ceph, and for a cloud bucket that you access with keys. The shape of the Secret differs per storage type. S3 takes an access key pair, GCS a service-account JSON key, and AzureBlob an account key.
Validation checks¶
With auth.type: credentials, the operator makes sure that the Secret exists in the namespace of the contract and holds the configured keys. The operator checks again when you edit the contract or the Secret. With type: workloadIdentity, there is nothing to check, and Ready is True. The operator does not reach the bucket to test it.
Deletion¶
Deleting the contract removes nothing from the bucket. A consumer that references it reports the missing reference on its own Ready condition.
Status¶
kubectl get objectstorageconfig shows Ready, its reason, the storage type, and the age.
| Type | Reason | Meaning | What to do |
|---|---|---|---|
Ready |
Healthy |
The contract is valid. A Secret in auth.credentials, if any, exists and holds the configured keys. |
Nothing. |
Ready |
MissingSecret |
The Secret of auth.credentials is missing, or it lacks a configured key. |
Create the Secret, or add the key. The message names the Secret and the key. |
A missing key reads:
status:
conditions:
- type: Ready
status: "False"
reason: MissingSecret
message: Secret my-cluster-ns/minio-credentials is missing key "secretAccessKey"
status.observedGeneration is the last generation of the contract that the operator validated.
Spec reference¶
Every field, with its type, whether it is required, and its default:
apiVersion: core.camunda.io/v1
kind: ObjectStorageConfig
metadata:
name: my-backup-bucket
namespace: my-cluster-ns
spec:
# string enum: S3 | GCS | AzureBlob. Required. Storage API of the bucket. Exactly the block of the same name must be set.
type: S3
# object. Required when type is S3, forbidden otherwise. An S3 or S3-compatible bucket.
s3:
# string. Required. Bucket name as the storage client SDK uses it.
bucketName: my-cluster-backup-bucket
# string. Optional. Key prefix under which consumers write objects, without leading or trailing slashes. Omit it to write to the bucket root.
basePath: backups
# string. Required unless endpoint is set. Region of the bucket. With an endpoint and no region, consumers send the placeholder region us-east-1.
region: eu-west-1
# string. Optional. URL of an S3-compatible store. Empty means AWS S3, addressed through region.
endpoint: "http://minio.minio.svc:9000"
# boolean. Optional, default: false. Forces path-style bucket addressing, which S3-compatible stores often need.
forcePathStyle: true
# object. Optional, default: {type: workloadIdentity}. How consumers authenticate.
auth:
# string enum: workloadIdentity | credentials. Optional, default: workloadIdentity.
type: workloadIdentity
# object. Optional, only valid with type workloadIdentity. Absent means that no annotation is added.
workloadIdentity:
# string. Optional. IAM role that the bucket trusts. It becomes the eks.amazonaws.com/role-arn annotation on the ServiceAccount of the consumer.
roleArn: "arn:aws:iam::123456789012:role/my-cluster-workload-role"
# object. Required with type credentials, forbidden otherwise. A static access key pair.
credentials:
secretRef:
# string. Required. Name of the Secret that holds the key pair.
name: minio-credentials
# string. Required. Key in the Secret that holds the access key ID.
accessKeyIdKey: accessKeyId
# string. Required. Key in the Secret that holds the secret access key.
secretAccessKeyKey: secretAccessKey
# object. Required when type is GCS, forbidden otherwise. A Google Cloud Storage bucket.
gcs:
# string. Required. Bucket name as the storage client SDK uses it.
bucketName: my-cluster-documents
# string. Optional. Key prefix under which consumers write objects, without leading or trailing slashes. Omit it to write to the bucket root.
basePath: documents
# object. Optional, default: {type: workloadIdentity}. How consumers authenticate.
auth:
# string enum: workloadIdentity | credentials. Optional, default: workloadIdentity.
type: workloadIdentity
# object. Optional, only valid with type workloadIdentity. Absent means that no annotation is added.
workloadIdentity:
# string. Optional. Google service account that the bucket trusts. It becomes the iam.gke.io/gcp-service-account annotation.
serviceAccountEmail: "my-cluster-workload@my-project.iam.gserviceaccount.com"
# object. Required with type credentials, forbidden otherwise. A static service-account JSON key.
credentials:
secretRef:
# string. Required. Name of the Secret that holds the JSON key.
name: gcs-key
# string. Required. Key in the Secret that holds the JSON key.
key: key.json
# object. Required when type is AzureBlob, forbidden otherwise. An Azure Blob Storage container.
azureBlob:
# string. Required. Storage account that holds the container.
accountName: camundabackups
# string. Required. Blob container that consumers write to.
container: backups
# string. Optional. Blob prefix under which consumers write objects, without leading or trailing slashes. Omit it to write to the container root.
basePath: clusters
# string. Optional. URL of the blob service. Empty means the public Azure endpoint of the account. Set it for Azurite and sovereign clouds.
endpoint: "https://camundabackups.blob.core.windows.net"
# object. Optional, default: {type: workloadIdentity}. How consumers authenticate.
auth:
# string enum: workloadIdentity | credentials. Optional, default: workloadIdentity.
type: workloadIdentity
# object. Optional, only valid with type workloadIdentity. Absent means that no annotation is added.
workloadIdentity:
# string. Optional. Managed identity that the container trusts. It becomes the azure.workload.identity/client-id annotation.
clientId: "11111111-2222-3333-4444-555555555555"
# object. Required with type credentials, forbidden otherwise. A static storage account key.
credentials:
secretRef:
# string. Required. Name of the Secret that holds the account key.
name: azure-key
# string. Required. Key in the Secret that holds the account key.
key: accountKey
Validation rules¶
- Exactly the block that matches
spec.typemust be set:S3withs3,GCSwithgcs, andAzureBlobwithazureBlob. - In every
authblock,credentialsis required whenauth.typeiscredentials, and forbidden otherwise. - In every
authblock,workloadIdentityis only valid whenauth.typeisworkloadIdentity. s3.regionis required unlesss3.endpointis set. With an endpoint and no region, every consumer sends the placeholder regionus-east-1. An S3-compatible store ignores it. If your store does not ignore it, setregion.s3.endpointandazureBlob.endpointmust be validhttporhttpsURLs.- A
basePath, when set, must match^[^/]+(/[^/]+)*$: a plain prefix without leading or trailing slashes. An empty string is rejected. Omit the field to use the bucket root. bucketName,accountName,container, and every Secret reference field must not be empty.- The API server accepts a contract whose
auth.credentialsSecret does not exist yet, so you can create the Secret after the contract. The contract reports the missing Secret onReady. - No field is immutable.
S3 with EKS Pod Identity¶
A bucket bound through EKS Pod Identity, which needs no annotation. Bind the principal system:serviceaccount:my-cluster-ns:my-cluster-camunda on the cloud side:
apiVersion: core.camunda.io/v1
kind: ObjectStorageConfig
metadata:
name: my-backup-bucket
namespace: my-cluster-ns
spec:
type: S3
s3:
bucketName: my-cluster-backup-bucket
region: eu-west-1
auth:
type: workloadIdentity
S3-compatible storage with static credentials¶
S3-compatible storage with static keys, the shape that MinIO and Ceph need:
apiVersion: core.camunda.io/v1
kind: ObjectStorageConfig
metadata:
name: my-backup-bucket
namespace: my-cluster-ns
spec:
type: S3
s3:
bucketName: camunda-backups
basePath: clusters
endpoint: "http://minio.minio.svc:9000"
forcePathStyle: true
auth:
type: credentials
credentials:
secretRef:
name: minio-credentials
accessKeyIdKey: accessKeyId
secretAccessKeyKey: secretAccessKey
GCS for document storage¶
A document storage bucket on Google Cloud, scoped to a key prefix:
apiVersion: core.camunda.io/v1
kind: ObjectStorageConfig
metadata:
name: my-document-bucket
namespace: my-cluster-ns
spec:
type: GCS
gcs:
bucketName: my-cluster-documents
basePath: documents
auth:
type: workloadIdentity
workloadIdentity:
serviceAccountEmail: "my-cluster-workload@my-project.iam.gserviceaccount.com"
Related¶
- CamundaCluster: consumes this contract through
backupStorageReffor backups anddocumentStorageReffor document storage. - ElasticsearchCluster: consumes this contract through
snapshotStorageReffor its snapshot repository. - LogicalBackupElasticsearch and LogicalBackupRDBMS: write to the bucket that the
backupStorageRefof the cluster names. - Backup guide: how to set up a backup bucket and take a backup.
- Getting started: the order in which you create the resources.