Skip to content

5. Secrets & ObjectStore (R2 / B2)

Goal: create the database namespace, the credential Secrets, and the ObjectStore resources that tell the Barman Cloud Plugin where (and how) to store backups. Both Cloudflare R2 and Backblaze B2 are supported; switch between them with a single Terraform variable.

flowchart LR
    r2cred["Secret: r2-credentials"] --> r2os["ObjectStore: pg-r2-store"]
    b2cred["Secret: b2-credentials"] --> b2os["ObjectStore: pg-b2-store"]
    r2os & b2os --> cl["Cluster\nbarmanObjectName: ${barman_object_store}"]

Both ObjectStores are always deployed. The active one is selected by the barman_object_store Terraform variable in kube.tf.

Switching providers

In kube.tf:

extra_kustomize_parameters = {
  barman_object_store = "pg-b2-store"   # or "pg-r2-store"
}

After changing the value, run terraform apply. No manual kubectl needed — Terraform re-renders and re-applies the cluster manifest automatically.

Note: switching providers mid-cluster only affects where new WAL and backups go. The old provider's backups remain readable for PITR as long as the ObjectStore and credentials exist.


Step 5.1 — Namespace

kubectl create namespace production

Step 5.1.5 — Infisical Operator Prerequisites

Install the Infisical Operator, then create a Machine Identity in Infisical and store its credentials so the Operator can authenticate:

kubectl create secret generic infisical-auth \
  --from-literal=clientId="<your-machine-identity-client-id>" \
  --from-literal=clientSecret="<your-machine-identity-client-secret>" \
  -n production

Step 5.2 — Application credentials Secret (Infisical)

Add to your Infisical dashboard (prod environment):

  • username: app_user
  • password: <your-strong-password>
infisical-pg-app.yaml
apiVersion: secrets.infisical.com/v1alpha1
kind: InfisicalSecret
metadata:
  name: pg-app-credentials-sync
  namespace: production
spec:
  hostAPI: https://app.infisical.com/api
  resyncInterval: 10
  authentication:
    universalAuth:
      secretsScope:
        projectSlug: "<your-infisical-project-slug>"
        envSlug: "prod"
        secretsPath: "/"
      credentialsRef:
        secretName: infisical-auth
        secretNamespace: production
  managedSecretReference:
    secretName: pg-app-credentials
    secretNamespace: production

Step 5.3 — Provider credentials (Infisical)

Add credentials for each provider you want available to your Infisical dashboard.

Cloudflare R2

In the Cloudflare dashboard, create an R2 API token scoped to your backup bucket.

Add to Infisical: - ACCESS_KEY_ID: <your-r2-access-key-id> - ACCESS_SECRET_KEY: <your-r2-secret-access-key>

infisical-r2-credentials.yaml
apiVersion: secrets.infisical.com/v1alpha1
kind: InfisicalSecret
metadata:
  name: r2-credentials-sync
  namespace: production
spec:
  hostAPI: https://app.infisical.com/api
  resyncInterval: 10
  authentication:
    universalAuth:
      secretsScope:
        projectSlug: "<your-infisical-project-slug>"
        envSlug: "prod"
        secretsPath: "/"
      credentialsRef:
        secretName: infisical-auth
        secretNamespace: production
  managedSecretReference:
    secretName: r2-credentials
    secretNamespace: production

Backblaze B2

In the Backblaze dashboard, create an Application Key scoped to your backup bucket. Note the bucket region (e.g. us-east-005).

Add to Infisical: - ACCESS_KEY_ID: <your-b2-keyId> - ACCESS_SECRET_KEY: <your-b2-applicationKey>

infisical-b2-credentials.yaml
apiVersion: secrets.infisical.com/v1alpha1
kind: InfisicalSecret
metadata:
  name: b2-credentials-sync
  namespace: production
spec:
  hostAPI: https://app.infisical.com/api
  resyncInterval: 10
  authentication:
    universalAuth:
      secretsScope:
        projectSlug: "<your-infisical-project-slug>"
        envSlug: "prod"
        secretsPath: "/"
      credentialsRef:
        secretName: infisical-auth
        secretNamespace: production
  managedSecretReference:
    secretName: b2-credentials
    secretNamespace: production

Step 5.4 — ObjectStore resources

Both ObjectStores are deployed at all times. Only the active one (set by barman_object_store) actually handles WAL archiving and backups.

R2 ObjectStore (pg-r2-store)

objectstore-r2.yaml
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
  name: pg-r2-store
  namespace: production
spec:
  retentionPolicy: "30d"
  instanceSidecarConfiguration:
    env:
      - name: AWS_DEFAULT_REGION
        value: "auto"                     # R2 requires "auto"
      - name: AWS_REQUEST_CHECKSUM_CALCULATION
        value: "when_required"            # avoids x-amz-content-sha256 errors
      - name: AWS_RESPONSE_CHECKSUM_VALIDATION
        value: "when_required"
  configuration:
    destinationPath: "s3://<your-bucket>/pg-cluster/"
    endpointURL: "https://<account-id>.r2.cloudflarestorage.com"
    s3Credentials:
      accessKeyId:
        name: r2-credentials
        key: ACCESS_KEY_ID
      secretAccessKey:
        name: r2-credentials
        key: ACCESS_SECRET_KEY
    wal:
      compression: gzip
      maxParallel: 2
    data:
      compression: gzip

B2 ObjectStore (pg-b2-store)

objectstore-b2.yaml
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
  name: pg-b2-store
  namespace: production
spec:
  retentionPolicy: "30d"
  instanceSidecarConfiguration:
    env:
      - name: AWS_DEFAULT_REGION
        value: "us-east-005"              # B2 requires the actual region
      - name: AWS_REQUEST_CHECKSUM_CALCULATION
        value: "when_required"
      - name: AWS_RESPONSE_CHECKSUM_VALIDATION
        value: "when_required"
  configuration:
    destinationPath: "s3://barman-cloud/pg-cluster/"
    endpointURL: "https://s3.us-east-005.backblazeb2.com"
    s3Credentials:
      accessKeyId:
        name: b2-credentials
        key: ACCESS_KEY_ID
      secretAccessKey:
        name: b2-credentials
        key: ACCESS_SECRET_KEY
    wal:
      compression: gzip
      maxParallel: 2
    data:
      compression: gzip

Key difference between providers:

R2 B2
AWS_DEFAULT_REGION auto actual region (e.g. us-east-005)
Endpoint format https://<account-id>.r2.cloudflarestorage.com https://s3.<region>.backblazeb2.com
Credential secret r2-credentials b2-credentials
ObjectStore name pg-r2-store pg-b2-store

What could go wrong

  • Bucket does not existbarman-cloud does not create it; create it first.
  • Missing checksum env vars → cryptic x-amz-content-sha256 upload errors on R2.
  • Wrong region on B2 → connection refused or auth errors; region must match the bucket's actual region.
  • Infisical secret not synced yet → cluster recovery pod fails immediately with auth errors; wait for InfisicalSecret to sync before the cluster starts.

Where to go deeper

Next: The PostgreSQL Cluster — the centerpiece.