Files
home-network-k3s-impl/infra/ansible/roles/minio_backup_target
jakman85andClaude Opus 4.8 ac32f01f7b feat(backup): MinIO S3 backup target on Proxmox host for Velero + CNPG
Stand up a single-node/single-drive MinIO S3 endpoint on the Proxmox host as the
off-cluster backup target for Velero (R-STATE-03) and CloudNativePG (R-IDP-05).

Ansible (author + executed):
- roles/minio_backup_target + playbooks/backup-minio.yml — idempotent, additive only:
  ZFS dataset Storage/k3s-backups (zstd, quota=100G, /mnt/Storage/k3s-backups, no
  sharenfs); minio system user; pinned+checksummed MinIO/mc binaries (fetched on the
  controller since the host has no WAN, copied to host); hardened systemd unit bound to
  the host's cluster-reachable LAN IP (auto-discovered) on :9000; velero + cnpg buckets;
  a non-root access key scoped by IAM policy to only those two buckets.
- inventory: new [proxmox_hosts] group ([email protected].2.102); overrides the cluster-wide
  ansible_user. Does not disturb existing k3s node entries.
- group_vars/proxmox_hosts/vault.yml (ansible-vault): root + scoped MinIO creds.

GitOps hand-off:
- platform/backup/minio-credentials.sops.yaml (+ .example) — SOPS/age-encrypted endpoint +
  scoped key/secret for the Velero/CNPG wiring (WS-STORAGE/WS-SEC). Not yet wired into a
  kustomization (left for the consuming agents).

Verified live: dataset props correct; minio active+enabled bound to 192.168.1.9:9000;
S3 endpoint http://192.168.1.9:9000/minio/health/ready returns 200 from an in-cluster pod;
buckets velero+cnpg present; scoped key created+policy attached; re-run is idempotent.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-28 22:15:05 -05:00
..

roles/minio_backup_target

Stands up a single-node, single-drive MinIO S3 endpoint on the Proxmox host to serve as the off-cluster backup target for the k3s platform's Velero (volume/resource DR, R-STATE-03) and CloudNativePG (Keycloak DB Barman object store, R-IDP-05). A backup target — not primary storage — so a single drive is intentional.

What it does (all additive + idempotent)

  1. ZFS dataset Storage/k3s-backups — compression=zstd, quota=100G, mountpoint=/mnt/Storage/k3s-backups, no sharenfs. Uses community.general.zfs so re-runs are no-ops and existing datasets are never touched.
  2. minio system user/group + a data dir (…/k3s-backups/data) it owns.
  3. MinIO + mc binaries (pinned, checksummed). The Proxmox host has no outbound internet, so the binaries are downloaded on the Ansible controller and copied to the host.
  4. systemd unit minio.service (Type=notify, hardened), bound to the host's cluster-reachable 192.168.1.x address on port 9000 (console 9001) — auto-discovered from facts, assert-guarded.
  5. Buckets velero + cnpg, a scoped non-root access key limited by an IAM policy to just those two buckets, plus the retained root creds for host-side admin.

Credentials

Supplied via the vaulted inventory/group_vars/proxmox_hosts/vault.yml (ansible-vault). Nothing is defaulted — a missing vault fails the play loudly:

var purpose
minio_backup_target_root_user / _root_password MinIO root (host admin only)
minio_backup_target_access_key / _secret_key scoped key handed to Velero + CNPG

The same scoped key is staged for the GitOps side, SOPS-encrypted, at platform/backup/minio-credentials.sops.yaml.

Run

cd infra/ansible
ansible-galaxy collection install -r collections/requirements.yml   # community.general (zfs)
ansible-playbook playbooks/backup-minio.yml

Endpoint

http://<host-192.168.1.x>:9000 — the S3 URL the cluster uses (path-style). Health: GET /minio/health/ready ⇒ 200. Verified reachable from an in-cluster pod at bring-up.