Skip to content

S3 Bucket Backup

The S3Backup CRD backs up entire S3-compatible buckets to a Restic repository. Unlike VolumeBackup (which backs up PVCs), S3Backup mounts a source S3 bucket via FUSE and runs Restic against the mounted filesystem.

Use Cases

  • Back up S3/Ceph/MinIO buckets to a different storage backend
  • Create versioned, encrypted backups of object storage data
  • Cross-region or cross-provider replication via Restic

How It Works

  1. The operator creates a CronJob on the configured schedule
  2. The CronJob pod mounts the source S3 bucket using rclone FUSE
  3. Restic backs up the mounted filesystem to the target repository
  4. Retention policies are applied after each backup

Credentials

S3Backup requires two Secrets:

Source bucket credentials (for mounting the S3 bucket):

apiVersion: v1
kind: Secret
metadata:
  name: s3-source-credentials
  namespace: default
type: Opaque
stringData:
  AWS_ACCESS_KEY_ID: "source-access-key-id"
  AWS_SECRET_ACCESS_KEY: "source-secret-access-key"

Repository credentials (for the Restic target):

apiVersion: v1
kind: Secret
metadata:
  name: s3-repo-credentials
  namespace: default
type: Opaque
stringData:
  AWS_ACCESS_KEY_ID: "repo-access-key-id"
  AWS_SECRET_ACCESS_KEY: "repo-secret-access-key"
  RESTIC_PASSWORD: "your-restic-repository-password"

Full Example

apiVersion: backups.k8s.bnerd.com/v1
kind: S3Backup
metadata:
  name: my-bucket-backup
  namespace: default
spec:
  source:
    endpoint: "https://storage.muc1.de.bnerd.com"
    bucket: "my-source-bucket"
    prefix: "data/"               # Only back up objects under this prefix
    usePathStyle: true            # Required for most non-AWS S3 (Ceph, MinIO)
    # noCheckBucket: false        # Set true if IAM denies s3:ListBucket
    secretRef:
      name: s3-source-credentials

  schedule: "0 3 * * *"

  repository:
    type: s3
    url: "s3:s3.eu-central-1.amazonaws.com/my-backup-repo/bucket-backups"
    secretRef:
      name: s3-repo-credentials

  host: "production-bucket-backup"

  exclude:
    - "*.tmp"
    - "*.log"

  retention:
    keepLast: 15
    keepDaily: 7
    keepWeekly: 4
    keepMonthly: 6

  cache:
    enabled: true
    size: "10Gi"

  resources:
    requests:
      memory: "512Mi"
      cpu: "300m"
    limits:
      memory: "2Gi"
      cpu: "1000m"

Source Configuration

Field Required Default Description
source.endpoint Yes -- S3 endpoint URL
source.bucket Yes -- Source bucket name
source.prefix No (all objects) Only back up objects under this prefix
source.region No -- AWS region for the source bucket
source.usePathStyle No true Use path-style S3 URLs (required for Ceph RGW, MinIO)
source.noCheckBucket No false Skip bucket existence check on mount
source.secretRef.name Yes -- Secret with source S3 credentials

Path-Style vs. Virtual-Hosted

  • Path-style (usePathStyle: true): https://endpoint/bucket/key -- required for most non-AWS S3 providers (Ceph, MinIO, b'nerd Object Storage)
  • Virtual-hosted (usePathStyle: false): https://bucket.endpoint/key -- used by AWS S3

noCheckBucket

Set noCheckBucket: true when your IAM policy denies s3:ListBucket at the bucket level. The operator will skip the bucket existence check on mount. The backup will still fail if the bucket does not exist.

Integrity Checks and Restore Testing

S3Backup supports the same check and restoreTest options as VolumeBackup:

spec:
  check:
    enabled: true
    schedule: "0 4 * * 0"    # Weekly
    readDataSubset: "5%"

  restoreTest:
    enabled: true
    schedule: "0 5 * * 0"    # Weekly
    fileCount: 25
    verifyChecksums: true

Suspend and Resume

Temporarily stop backups without deleting the resource:

kubectl patch s3backup my-bucket-backup -p '{"spec":{"suspended":true}}' --type=merge

Resume:

kubectl patch s3backup my-bucket-backup -p '{"spec":{"suspended":false}}' --type=merge