Provisioning and Managing S3 Buckets
This chapter describes how to provision and manage AWS S3 buckets using Klutch.
Pre-requisite
- Ensure that the App Cluster has network connectivity to the Klutch Control Plane Cluster.
- Verify that the application cluster is set up correctly by ensuring the required Custom Resource Definitions (CRDs) are installed.
You can verify their presence with:
kubectl get crds
Example output:
NAME CREATED AT
apiservicebindings.klutch.anynines.com 2025-10-15T23:14:44Z
objectstoragebindings.anynines.com 2025-10-15T23:15:28Z
objectstorageinstances.anynines.com 2025-10-15T23:14:46Z
These CRDs allow developers to request, bind, and consume AWS S3 object storage through Klutch.
Using Klutch to provision AWS S3 buckets
After verifying that the app cluster is properly configured with the necessary CRDs and can communicate with the control plane cluster, you can start by requesting S3 buckets.
Step 1: Request an S3 Bucket
To create an S3 bucket, use the object storage claim template below, or apply the provided example file.
- Template
- Example
apiVersion: anynines.com/v1
kind: ObjectStorageInstance
metadata:
name: <name>
namespace: <namespace>
spec:
service: aws-s3 # must be aws-s3
plan: <plan-name>
region: <region-name>
compositionRef:
name: <composition-name> # to be supplied by a platform operator
# Optional
parameters:
tags:
TagName: <tag-value>
deletionPolicy: <EmptyBucketAndDelete/DeleteInstanceKeepBucket>
encryption:
type: <kms/aes256> # Defaults to aes256
key: # <-- Required only if type is 'kms'
# Option A: Have Klutch create a Managed Key
managed:
alias: <alias-name> # Optional, e.g. "my-key-alias"
# Option B: Use an Existing Key
existing:
id: <arn:aws:kms:...> # The ARN of your key
Note: If you specify an encryption key,
AWS KMS will be used. Provide exactly one of
managed or existing under the key block. This is not required if type
is aes256 or the encryption block is omitted.
Deploy the resource:
kubectl apply -f <your-file-name>
cat <<'EOF' > s3-instance-example.yaml
apiVersion: anynines.com/v1
kind: ObjectStorageInstance
metadata:
name: s3-bucket-example
namespace: default
spec:
service: aws-s3
plan: standard
region: eu-central-1
compositionRef:
name: aws-s3
EOF
Deploy the resource:
kubectl apply -f s3-instance-example.yaml
What Klutch does:
The Klutch control plane provisions an S3 bucket in the specified region. The AWS bucket name is derived from the object storage claim name, with a unique suffix appended to ensure uniqueness and prevent naming collisions, as required by S3 (for example, example-aws-s3-xyz12).
Check that the ObjectStorageInstance was created successfully:
kubectl get objectstorageinstance
Example output:
NAME SYNCED READY CONNECTION-SECRET AGE
s3-bucket-example True True 10s
If you want to see more details about the resource (e.g. the actual name of the bucket created on AWS) you can use the command below and look for the status field.
kubectl describe objectstorageinstance <name>
Expand for more details about the ObjectStorageInstance's spec fields
| Field | Type | Required | Description | Supported Values |
|---|---|---|---|---|
| service | string | Yes | Specifies the object storage service backend. | aws-s3 |
| plan | string | Yes | Defines the service plan. Values match AWS S3 storage classes. | standard, infrequentaccess, intelligent, archiveinstant, archiveflexible, archivedeep |
| region | string | Yes | Specifies the region where the object storage will be created. | All AWS regions supported by Klutch. See here. |
| parameters | object | No | Optional parameters to customize the instance. | tags, deletionPolicy, encryption |
| parameters.tags | object | No | Key/value map of tags to apply to the provisioned resource. | Keys must be alphanumeric and can include spaces, dashes (-), and underscores (_). Values must be ≤256 characters. |
| parameters.deletionPolicy | string | No | Controls what happens to the bucket and its data when the instance is deleted. | DeleteInstanceKeepBucket (default), EmptyBucketAndDelete |
| parameters.encryption | object | No | Configures server-side encryption. Cannot be changed after creation. | type and key |
| parameters.encryption.type | string | No | The type of encryption to use. Defaults to aes256 if omitted. | aes256, kms |
| parameters.encryption.key | object | Conditionally required | AWS KMS key configuration. Required if type is kms. Must contain either managed or existing. | Must contain one of managed or existing |
| parameters.encryption.key.managed | object | No | Configures a new KMS key to be created by Klutch. | Contains alias |
| parameters.encryption.key.managed.alias | string | No | Alias for the managed KMS key. Immutable. Must not start with aws/. | 1–250 alphanumeric characters, /, _, - |
| parameters.encryption.key.existing | object | No | Configures the bucket to use a pre-existing KMS key. | Contains id (Key ARN) |
| parameters.encryption.key.existing.id | string | No | ARN of the existing AWS KMS key. Immutable. | Must match arn:aws:kms:[region]:[account]:key/... |
For details on behaviors and limitations of AWS S3 buckets, see the official AWS S3 documentation.
Step 2: Bind the Bucket to Get Access Credentials
Once the ObjectStorageInstance is ready, create an ObjectStorageBinding to get access and use the bucket.
- Template
- Example
apiVersion: anynines.com/v1
kind: ObjectStorageBinding
metadata:
name: <name>
namespace: <namespace>
spec:
instanceRef: <objectStorageInstance-name>
compositionRef:
name: <composition-name> # to be supplied by a platform operator
writeConnectionSecretToRef:
name: <secret-name>
# Optional
permissions: <permissions> # Optional, defaults to readWrite
scopedAccess:
- prefix: <prefix>
permissions: <permissions>
Deploy the resource:
kubectl apply -f <your-file-name>
cat << 'EOF' > s3-binding-example.yaml
apiVersion: anynines.com/v1
kind: ObjectStorageBinding
metadata:
name: storage-binding-example
namespace: default
spec:
instanceRef: s3-bucket-example
writeConnectionSecretToRef:
name: example-storage-binding-credentials
compositionRef:
name: aws-objectstoragebinding
EOF
Deploy the resource: (after replacing the bucket name):
kubectl apply -f s3-binding-example.yaml
What Klutch does:
Klutch creates an IAM user with a tightly scoped policy following the principle
of least privilege. The access credentials are stored in the Kubernetes secret
specified in writeConnectionSecretToRef. When KMS encryption is used, Klutch
also assigns only the required KMS permissions based on the specified access
level.
Check that the binding to the bucket was created successfully:
kubectl get objectstoragebinding
Example output:
NAME SYNCED READY CONNECTION-SECRET AGE
example-storage-binding True True example-storage-binding-credentials 11s
Once the binding is ready, you can deploy an application that uses the provisioned S3 bucket.
Expand for more details about the ObjectStorageBinding's spec fields
| Field | Type | Required | Description | Supported Values |
|---|---|---|---|---|
| instanceRef | string | Yes | The name of the target object storage instance to bind to. | n.a. |
| permissions | string | No | The default permission level for the entire bucket. Applies to both S3 actions and KMS actions if the bucket is encrypted. | listOnly, readOnly, writeOnly, readWrite (Default), admin |
| scopedAccess | array | No | Fine-grained permissions for specific S3 prefixes (folders) within the bucket. | Same values as permissions field. Maximum 10 entries. |
| writeConnectionSecretToRef | object | Yes | Defines the Kubernetes secret where the access credentials for the instance will be stored. | The object must include a name field. |
More information on permissions values:
listOnly: Allows listing object names but not reading their content.readOnly: Allows listing objects and reading their content.writeOnly: Allows creating and deleting objects.readWrite: Allows listing, reading, creating, and deleting objects.admin: Grants full permissions on all objects (s3:*Object).
Note: If the bucket is encrypted with KMS, the specified permissions are also applied to the corresponding KMS operations.
Cleanup
To remove the ObjectStorageInstance and ObjectStorageBinding resources, use
the standard kubectl delete <resource-type> <resource-name> command.
If you deployed the example manifests, run the following commands to delete the
corresponding objects.
To delete the binding for the S3 bucket:
kubectl delete objectstoragebinding storage-binding-example
To delete the s3 bucket:
kubectl delete objectstorageinstance s3-bucket-example