Skip to content

Use CSI-S3 and COSI

The operator supports native S3 clients directly through GarageKey Secrets. CSI-S3 and COSI are optional integrations for workloads that need a Kubernetes storage/provisioning abstraction.

CSI-S3

k8s-csi-s3 mounts an S3 bucket through FUSE. It is useful for filesystem-oriented workloads, but it is not a block-storage replacement: expect higher latency, no true random writes, and no fsync semantics.

Create a bucket and key with the data keys expected by the CSI driver:

apiVersion: garage.rajsingh.info/v1beta1
kind: GarageKey
metadata:
  name: csi-s3-key
  namespace: storage
spec:
  clusterRef:
    name: garage
  secretTemplate:
    name: csi-s3-secret
    accessKeyIdKey: accessKeyID
    secretAccessKeyKey: secretAccessKey
    additionalData:
      endpoint: http://garage.garage.svc:3900
      region: garage
  bucketPermissions:
    - bucketRef:
        name: csi-s3
      read: true
      write: true

Install CSI-S3 separately and configure its StorageClass to use the existing Secret. The CSI-S3 namespace needs a privileged Pod Security Admission exception because its node plugin uses FUSE.

One example using the upstream chart is:

kubectl create namespace csi-s3
kubectl label namespace csi-s3 pod-security.kubernetes.io/enforce=privileged
helm repo add csi-s3 https://yandex-cloud.github.io/k8s-csi-s3/charts
helm repo update
helm install csi-s3 csi-s3/csi-s3 \
  --namespace csi-s3 \
  --set storageClass.singleBucket=csi-s3 \
  --set 'storageClass.mountOptions=--memory-limit 1000 --dir-mode 0777 --file-mode 0666' \
  --set secret.create=false

The driver chart and its values can change independently of this operator. Review the chart's current StorageClass/Secret wiring before production use; the important contract here is that the GarageKey Secret has the access-key and secret-key names selected by the driver, plus its S3 endpoint and region.

COSI

COSI is a separate Kubernetes API and controller. The operator is a COSI driver implementation; it does not replace the cluster-wide COSI controller and does not use a per-driver sidecar.

Enable it in Helm:

helm upgrade --install garage-operator \
  oci://ghcr.io/rajsinghtech/charts/garage-operator \
  --namespace garage-operator-system \
  --set cosi.enabled=true

Install the COSI CRDs and cluster-wide controller from the pinned revision below, then create a BucketClass and BucketAccessClass with driverName: garage.rajsingh.info.

The cluster-wide controller is a separate prerequisite. It reconciles BucketClaimBucket and BucketAccessClaimBucketAccess and populates the BucketClaimRef and class parameters that this driver validates. The operator does not run a per-driver sidecar.

COSI_REF=cc544691e2ef7ddc2fba972d796ed3188ea46315
for crd in bucketclaims bucketaccesses bucketclasses bucketaccessclasses buckets; do
  kubectl apply -f "https://raw.githubusercontent.com/kubernetes-sigs/container-object-storage-interface/${COSI_REF}/client/config/crd/objectstorage.k8s.io_${crd}.yaml"
done
kubectl apply -k "github.com/kubernetes-sigs/container-object-storage-interface/controller?ref=${COSI_REF}"
apiVersion: objectstorage.k8s.io/v1alpha2
kind: BucketClass
metadata:
  name: garage-standard
spec:
  driverName: garage.rajsingh.info
  deletionPolicy: Delete
  parameters:
    clusterRef: garage
    clusterNamespace: storage
---
apiVersion: objectstorage.k8s.io/v1alpha2
kind: BucketAccessClass
metadata:
  name: garage-readwrite
spec:
  driverName: garage.rajsingh.info
  authenticationType: Key
  parameters:
    clusterRef: garage
    clusterNamespace: storage

Only S3 and Key authentication are supported. BucketAccess requests using ServiceAccount authentication are rejected by the driver with ServiceAccount auth not supported by Garage; Garage has no IAM authentication mode. BucketClaim creates a Garage bucket and BucketAccess creates a key/credential Secret through operator-owned shadow GarageBucket/GarageKey resources. Delete waits for the bucket to be empty; a non-empty bucket is not silently destroyed.

The generated COSI access Secret contains the canonical keys COSI_PROTOCOL, COSI_S3_BUCKET_ID, COSI_S3_ENDPOINT, COSI_S3_REGION, COSI_S3_ADDRESSING_STYLE, COSI_S3_ACCESS_KEY_ID, and COSI_S3_ACCESS_SECRET_KEY. The historical S3_* aliases are also retained: S3_BUCKET_ID, S3_ENDPOINT, S3_REGION, S3_ACCESS_KEY_ID, and S3_ACCESS_SECRET_KEY. The endpoint uses path-style addressing.

Bucket and access deletion is a two-controller handoff. The Garage protection finalizer removes the remote bucket/key or revokes permissions, then releases the upstream COSI protection finalizer. A retained bucket skips remote bucket deletion; a Delete bucket must be emptied before cleanup can complete.

If cosi.namespace differs from the target GarageCluster namespace, create a GarageReferenceGrant in that target namespace for the COSI shadow GarageBucket and GarageKey kinds.

The shadow resources live in the configured cosi.namespace, while COSI BucketClaim, BucketAccess, and their Secrets remain in the requesting namespace. The operator must watch both namespaces, and a cross-namespace shadow reference is denied unless the destination namespace grants the shadow namespace explicitly or through a matching namespaceSelector.