5. Secrets & ObjectStore (R2)¶
Goal: create the database namespace, the credential Secrets, and the
ObjectStore resource that tells the Barman Cloud Plugin where (and how) to
store backups in Cloudflare R2. This is where the R2-specific workarounds
live.
flowchart LR
secret["Secret: r2-credentials<br/>(Access Key / Secret)"] --> os
os["ObjectStore: pg-r2-store<br/>endpoint, region, checksum env"] --> r2[("R2 bucket")]
cl["Cluster (next chapter)"] -->|barmanObjectName: pg-r2-store| os
Step 5.1 — Namespace¶
Keep the database in its own namespace, separate from applications.
Step 5.2 — Application credentials Secret¶
The Cluster will bootstrap an application database and user. Create its credentials (generate a strong password locally):
kubectl create secret generic pg-app-credentials \
--from-literal=username=app_user \
--from-literal=password="$(openssl rand -base64 24)" \
-n production
Kubernetes Secrets are not encrypted by default
They are only base64-encoded at rest unless your cluster enables encryption at rest. For the production phase, consider the External Secrets Operator to keep secrets in a real vault. For learning, the above is fine.
Step 5.3 — R2 credentials Secret¶
In the Cloudflare dashboard, create an R2 API token scoped to your backup
bucket. It yields an Access Key ID and Secret Access Key (S3-style).
Also note your Account ID (used in the endpoint URL). Create the bucket
first (recent barman-cloud does not auto-create buckets).
kubectl create secret generic r2-credentials \
--from-literal=ACCESS_KEY_ID="<your-r2-access-key-id>" \
--from-literal=ACCESS_SECRET_KEY="<your-r2-secret-access-key>" \
-n production
Step 5.4 — The ObjectStore¶
This resource (provided by the Barman Cloud Plugin) defines the backup destination, compression, retention, and — critically for R2 — the workaround environment variables.
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: pg-r2-store
namespace: production
spec:
retentionPolicy: "30d" # (1)!
instanceSidecarConfiguration:
env: # (2)!
- name: AWS_DEFAULT_REGION
value: "auto" # (3)!
- name: AWS_REQUEST_CHECKSUM_CALCULATION
value: "when_required" # (4)!
- name: AWS_RESPONSE_CHECKSUM_VALIDATION
value: "when_required"
configuration:
destinationPath: "s3://<your-bucket>/pg-cluster/" # (5)!
endpointURL: "https://<account-id>.r2.cloudflarestorage.com" # (6)!
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
- Retention now lives on the ObjectStore (not the ScheduledBackup, as in the old in-tree model). Keep 30 days of backups+WAL.
instanceSidecarConfiguration.envinjects environment variables into the plugin sidecar that runsbarman-cloud— this is how we apply R2 fixes.- R2's region is
auto. SettingAWS_DEFAULT_REGIONvia env is the reliable way; thes3Credentials.regionfield has been observed to have no effect. - The checksum workaround. Recent AWS SDK data-integrity behavior triggers
x-amz-content-sha256errors on some S3-compatible stores. Forcing checksums towhen_requiredavoids it. s3://<bucket>/<prefix>/— the prefix groups this cluster's backups.- The R2 S3 endpoint uses your Account ID.
Step 5.5 — A first connectivity smoke test (optional but wise)¶
You will not see backups until the Cluster exists and runs one, but you can at least confirm the credentials and endpoint are plausible by listing the bucket with the AWS CLI from your laptop (R2 speaks S3):
AWS_ACCESS_KEY_ID=<id> AWS_SECRET_ACCESS_KEY=<secret> \
aws s3 ls --endpoint-url https://<account-id>.r2.cloudflarestorage.com \
s3://<your-bucket>/
What could go wrong (R2-specific)¶
- Bucket does not exist →
barman-cloudno longer creates it; create it first. - Missing checksum env vars → cryptic
x-amz-content-sha256upload errors. - Wrong endpoint/account ID → connection refused or auth errors.
- Restore fails even though backups upload → this is the known R2 issue. Do not consider backups trustworthy until you complete the restore validation.
Where to go deeper¶
Next: The PostgreSQL Cluster — the centerpiece.