Skip to content

Storage Backends

Configure where Retour stores backups.

Types

Type Description
s3 Any S3-compatible endpoint: AWS S3, MinIO, Ceph RGW, Cloudflare R2, Backblaze B2, Wasabi, DigitalOcean Spaces, Hetzner, Scaleway, IBM COS, Oracle, Alibaba OSS, and the rest
azureblob Azure Blob Storage (shared key, SAS URL, or workload identity)
gcs Google Cloud Storage (service-account JSON or Application Default Credentials)
crypt Client-side encrypted wrapper around an s3 backend

type: local is refused at validation. A local path is a path inside the carrier pod, which the worker deletes when the job finishes, so the backup went with it while the CR still reported Completed.

Two settings cut across the types:

  • engine selects the data plane: rclone (default) or kopia (deduplicated, incremental-forever snapshots). Kopia works on s3, azureblob, and gcs.
  • transfer bounds every transfer through the backend: bandwidthLimit in rclone --bwlimit syntax (a timetable such as 08:00,512k 19:00,10M 23:00,off is how a backup window is expressed), plus transfers and checkers.

S3 Backend

apiVersion: retour.thebackup.company/v1
kind: StorageBackend
metadata:
  name: s3-production
  namespace: retour
spec:
  type: s3
  s3:
    bucket: retour-backups
    region: us-east-1
    useSSL: true
    secretRef:
      name: s3-credentials
      keys:
        accessKeyID: access-key-id
        secretAccessKey: secret-access-key

MinIO, Ceph RGW, and other S3-compatible providers

Point endpoint at the provider. Everything else is the same, which is why the S3-compatible services (R2, B2's S3 API, Wasabi, Spaces, Hetzner, Scaleway, IBM COS, Oracle, Alibaba OSS) need no type of their own.

spec:
  type: s3
  s3:
    endpoint: http://minio.retour.svc.cluster.local:9000
    bucket: retour-backups
    region: us-east-1
    useSSL: false
    secretRef:
      name: minio-credentials
      keys:
        accessKeyID: access-key-id
        secretAccessKey: secret-access-key

AWS S3 with IRSA (no secrets)

On EKS, use IAM Roles for Service Accounts:

spec:
  type: s3
  s3:
    bucket: retour-backups
    region: us-east-1
    useSSL: true
    envAuth: true

The carrier pods must use a ServiceAccount annotated with eks.amazonaws.com/role-arn.

Server-side encryption and Object Lock

Both are S3-only, and both compose with crypt and with each other:

spec:
  type: s3
  s3:
    bucket: retour-backups
    region: us-east-1
    serverSideEncryption: "aws:kms"   # or AES256 for SSE-S3
    kmsKeyID: arn:aws:kms:us-east-1:111122223333:key/abcd-1234
    immutability:
      mode: COMPLIANCE                # or GOVERNANCE
      retainDays: 30
    secretRef:
      name: s3-credentials
      keys:
        accessKeyID: access-key-id
        secretAccessKey: secret-access-key

immutability needs a bucket created with Object Lock enabled. Retention is applied to every uploaded object after upload, and a lock that cannot be applied fails the backup rather than reporting an immutability nothing enforces. Backend data is not deleted until status.retainedUntil passes.

Azure Blob Backend

spec:
  type: azureblob
  azureblob:
    account: retourstorage
    container: retour-backups
    secretRef:
      name: azure-credentials
      keys:
        accountKey: account-key       # or sasToken: sas-url

sasToken takes the full SAS URL for the container or account, not the bare token. For Azure Workload Identity or a managed identity, drop secretRef and set envAuth: true. endpoint overrides the blob service endpoint for Azurite or a sovereign cloud, and is rclone-only: kopia's Azure provider has no endpoint override, so the combination is refused rather than silently writing to the real service.

Google Cloud Storage Backend

spec:
  type: gcs
  gcs:
    bucket: retour-backups
    secretRef:
      name: gcs-credentials
      keys:
        serviceAccountKey: service-account-json

The secret value is the service-account JSON document itself, not a path to one. Under GKE Workload Identity, drop secretRef and set envAuth: true so Application Default Credentials are used. As with Azure, a custom endpoint (fake-gcs-server, private access endpoints) is rclone-only.

Encrypted Backend (Crypt)

Wrap an S3 backend with rclone crypt. File contents and file names are encrypted client-side, before upload:

apiVersion: v1
kind: Secret
metadata:
  name: crypt-credentials
  namespace: retour
type: Opaque
stringData:
  password: "your-encryption-password"
  access-key-id: "minio"
  secret-access-key: "minio123"
---
apiVersion: retour.thebackup.company/v1
kind: StorageBackend
metadata:
  name: s3-encrypted
  namespace: retour
spec:
  type: crypt
  crypt:
    backend: s3
    s3:
      endpoint: http://minio.retour.svc.cluster.local:9000
      bucket: retour-backups
      region: us-east-1
      useSSL: false
    secretRef:
      name: crypt-credentials
      keys:
        password: password
        accessKeyID: access-key-id
        secretAccessKey: secret-access-key

A crypt backend is also what the encrypted Secrets stream requires, with a second passphrase under keys.secretsPassword that must differ from this one.

Incremental backups (kopia engine)

spec:
  type: s3
  engine: kopia
  s3:
    bucket: retour-backups
    region: us-east-1
    secretRef:
      name: s3-credentials
      keys:
        accessKeyID: access-key-id
        secretAccessKey: secret-access-key
        kopiaPassword: kopia-password

kopiaPassword is required on s3, azureblob, and gcs, including under envAuth: workload identity covers the cloud credentials, not the repository password. Losing it makes every kopia backup in that repository unrestorable. Kopia cannot be combined with crypt or with immutability, and both combinations are refused with a message saying so.

Bandwidth and transfer tuning

spec:
  type: s3
  transfer:
    bandwidthLimit: "08:00,512k 19:00,10M 23:00,off"
    transfers: 4
    checkers: 8
  s3:
    bucket: retour-backups
    region: us-east-1

A single rate (10M), an upload:download pair (10M:100k), and the timetable above are all valid. Backup.spec.bandwidthLimit overrides the rate for one run. On the kopia engine only a simple single rate maps, to the repository upload throttle.

Connection Test

The operator tests StorageBackend connectivity when the CR is created or changed. Check status:

kubectl get storagebackends -n retour

Phases: Pending → Ready (or Failed with error message)