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:
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¶
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_userpassword:<your-strong-password>
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>
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>
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)¶
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)¶
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 exist →
barman-clouddoes not create it; create it first. - Missing checksum env vars → cryptic
x-amz-content-sha256upload 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
InfisicalSecretto sync before the cluster starts.
Where to go deeper¶
Next: The PostgreSQL Cluster — the centerpiece.