Skip to content

RustFS Credential Runbook

RustFS uses two credential classes:

  • Root/app credentials are only for the TrueNAS RustFS app bootstrap and console administration.
  • Workload credentials are RustFS-console-created access keys used by Kubernetes clients through External Secrets Operator.

Do not point Kubernetes workloads at the TrueNAS app/root credential.

1Password Item

The shared item is rustfs in vault homelab-prod.

Required fields:

Field Purpose
root-access-key TrueNAS RustFS app/root access key. Do not use for Kubernetes clients.
root-secret-key TrueNAS RustFS app/root secret key. Do not use for Kubernetes clients.
rustfs-workload-access-key RustFS console-created workload access key for Kubernetes S3 clients.
rustfs-workload-secret-key RustFS console-created workload secret key for Kubernetes S3 clients.
kopia_password Kopia repository encryption password.
endpoint RustFS S3 endpoint, currently http://192.168.10.133:30292.
S3_ENDPOINT RustFS S3 endpoint, currently http://192.168.10.133:30292.

Deprecated fields:

Field Replacement
k8s-admin-access-key rustfs-workload-access-key
k8s-admin-secret-key rustfs-workload-secret-key
pvc-plumber-access-key rustfs-workload-access-key (renamed 2026-05-21 with pvc-plumber decommission)
pvc-plumber-secret-key rustfs-workload-secret-key (renamed 2026-05-21 with pvc-plumber decommission)

Delete the deprecated fields only after all ExternalSecrets are synced to the replacement field names.

Workload key IAM policy

The single workload key (named homelab-workload in the RustFS console) is configured with a broad allow policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:*"],
      "Resource": ["arn:aws:s3:::*"]
    }
  ]
}

Decision (homelab single-tenant, 2026-05-21): scope is intentionally broad. Per-bucket IAM scoping would duplicate Kubernetes RBAC's namespace separation without adding meaningful protection in a single-operator homelab — a compromised cluster would mean a compromised key either way. Broad policy also means new buckets work immediately without a forgotten-IAM failure mode when adding a new logging/metrics/backup destination. Workload key remains distinct from root-access-key so cluster cannot invoke RustFS admin operations (bucket create/delete, user mgmt — those use root via console).

When to tighten: - If multiple operators/people gain cluster access and homelab becomes shared. - If a specific app starts misbehaving with the bucket — scope ITS key, not the shared one. - If running an audit/compliance exercise that requires least-privilege docs.

Captured in mink: rustfs-workload-key-policy-full-s3-on-all-buckets-homelab-single-tenant-decision.md

Update 1Password

Use these commands when rotating the RustFS workload key. Replace the placeholder values manually.

op item edit rustfs \
  --vault homelab-prod \
  'rustfs-workload-access-key[text]=PASTE_RUSTFS_WORKLOAD_ACCESS_KEY_HERE' \
  'rustfs-workload-secret-key[concealed]=PASTE_RUSTFS_WORKLOAD_SECRET_KEY_HERE'

Optional root/app fields, if the 1Password item does not already have them:

op item edit rustfs \
  --vault homelab-prod \
  'root-access-key[text]=PASTE_RUSTFS_ROOT_ACCESS_KEY_HERE' \
  'root-secret-key[concealed]=PASTE_RUSTFS_ROOT_SECRET_KEY_HERE'

Verify field presence without revealing concealed values:

op item get rustfs \
  --vault homelab-prod \
  --fields rustfs-workload-access-key,rustfs-workload-secret-key,kopia_password,endpoint,S3_ENDPOINT

ESO Consumers

These GitOps-managed ExternalSecrets read rustfs-workload-access-key and rustfs-workload-secret-key:

ExternalSecret Kubernetes Secret
cloudnative-pg/cnpg-s3-credentials cnpg-s3-credentials
kopia-ui/kopia-ui-secrets kopia-ui-secret (only consumes kopia_password, not the workload key)
loki-stack/loki-s3-credentials loki-s3-credentials
monitoring/tempo-s3-credentials tempo-s3-credentials
posthog/posthog-secrets posthog-secrets
rustfs-lifecycle/rustfs-admin-credentials rustfs-admin-credentials
Each chart-rendered <ns>/volsync-<pvc> per backed-up PVC volsync-<pvc>

The volsync-system/pvc-plumber-kopia ExternalSecret was removed 2026-05-21 along with the pvc-plumber operator decommission. Per-PVC ExternalSecrets are now rendered by the volsync-backup Helm chart at infrastructure/storage/volsync-backup/ rather than the operator.

Force ESO refresh after changing 1Password:

TS="$(date +%s)"
kubectl annotate externalsecret -n cloudnative-pg cnpg-s3-credentials force-sync="$TS" --overwrite
kubectl annotate externalsecret -n kopia-ui kopia-ui-secrets force-sync="$TS" --overwrite
kubectl annotate externalsecret -n loki-stack loki-s3-credentials force-sync="$TS" --overwrite
kubectl annotate externalsecret -n monitoring tempo-s3-credentials force-sync="$TS" --overwrite
kubectl annotate externalsecret -n posthog posthog-secrets force-sync="$TS" --overwrite
kubectl annotate externalsecret -n rustfs-lifecycle rustfs-admin-credentials force-sync="$TS" --overwrite

# Also force every chart-rendered per-PVC ES:
kubectl get externalsecret -A -l app.kubernetes.io/managed-by=volsync-backup-chart \
  -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{end}' | \
  while read ns name; do
    [ -z "$ns" ] && continue
    kubectl annotate externalsecret -n "$ns" "$name" force-sync="$TS" --overwrite
  done

Restart consumers that load S3 credentials from environment variables:

# CNPG re-reads cnpg-s3-credentials automatically via the operator's
# Secret-watcher — no restart needed for postgres clusters.
kubectl rollout restart deploy/kopia-ui -n kopia-ui
kubectl rollout restart statefulset/loki-backend statefulset/loki-write -n loki-stack
kubectl rollout restart deploy/loki-read -n loki-stack
kubectl rollout restart statefulset/tempo -n monitoring
kubectl rollout restart deploy/db deploy/feature-flags deploy/plugins deploy/web deploy/worker \
                       deploy/ingestion-general deploy/ingestion-sessionreplay \
                       deploy/recording-api deploy/replay-capture \
                       deploy/temporal-django-worker deploy/property-defs-rs \
                       -n posthog

VolSync mover Jobs read the per-PVC Secret at Job creation time, so the NEXT scheduled (or manually triggered) backup run picks up the new credentials automatically — no restart of VolSync itself needed. RustFS lifecycle Job is spawned by its CronJob — next scheduled run uses the refreshed Secret.