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]>
52 lines
2.7 KiB
Plaintext
52 lines
2.7 KiB
Plaintext
# =============================================================================
|
|
# TEMPLATE — NOT APPLIED, NOT ENCRYPTED (.yaml.example is ignored by kustomize and never
|
|
# auto-encrypted by SOPS). Reference scaffold + OPERATOR HAND-OFF.
|
|
#
|
|
# WHAT THIS IS: the scoped (non-root) MinIO S3 access key for the off-cluster backup target that
|
|
# roles/minio_backup_target stands up on the Proxmox host (playbooks/backup-minio.yml). It is the
|
|
# credential Velero (R-STATE-03) and CloudNativePG / Barman (R-IDP-05) use to write backups. The
|
|
# SAME key/secret live (ansible-vault) in infra/ansible/inventory/group_vars/proxmox_hosts/vault.yml
|
|
# as minio_backup_target_access_key/_secret_key — the two MUST stay in sync.
|
|
#
|
|
# ENDPOINT (not secret): http://192.168.1.9:9000 (path-style; region us-east-1 is a placeholder,
|
|
# MinIO ignores it but S3 clients require one). Buckets: velero, cnpg.
|
|
#
|
|
# HAND-OFF STEPS (operator):
|
|
# (a) Copy to: platform/backup/minio-credentials.sops.yaml
|
|
# (b) Fill the access key + secret (== the vaulted scoped key on the Proxmox host).
|
|
# (c) Encrypt: sops -e -i platform/backup/minio-credentials.sops.yaml
|
|
# (d) Wire per consumer (WS-STORAGE / WS-SEC):
|
|
# - Velero → credentials.existingSecret pointing at a Secret with the `cloud` INI key,
|
|
# backupStorageLocation.config.s3Url=S3_ENDPOINT, s3ForcePathStyle="true",
|
|
# bucket=velero (namespace: velero).
|
|
# - CNPG → Barman objectStore endpointURL=S3_ENDPOINT, destinationPath=s3://cnpg,
|
|
# s3Credentials.accessKeyId/secretAccessKey from ACCESS_KEY_ID/ACCESS_SECRET_KEY
|
|
# (namespace: cnpg-system).
|
|
# A Secret is namespace-scoped — replicate/rename this one into each consumer namespace as
|
|
# that wiring requires.
|
|
# =============================================================================
|
|
apiVersion: v1
|
|
kind: Secret
|
|
metadata:
|
|
name: minio-backup-credentials
|
|
namespace: backup
|
|
type: Opaque
|
|
stringData:
|
|
# ── endpoint + buckets (not secret; single source of truth) ──
|
|
S3_ENDPOINT: "http://192.168.1.9:9000"
|
|
S3_REGION: "us-east-1"
|
|
S3_FORCE_PATH_STYLE: "true"
|
|
VELERO_BUCKET: "velero"
|
|
CNPG_BUCKET: "cnpg"
|
|
# ── scoped access key (velero + cnpg buckets only) ──
|
|
AWS_ACCESS_KEY_ID: "REPLACE-ME"
|
|
AWS_SECRET_ACCESS_KEY: "REPLACE-ME"
|
|
# CNPG Barman object store consumes these discrete key names.
|
|
ACCESS_KEY_ID: "REPLACE-ME"
|
|
ACCESS_SECRET_KEY: "REPLACE-ME"
|
|
# Velero's aws plugin reads an INI credentials file from the `cloud` key of its existingSecret.
|
|
cloud: |
|
|
[default]
|
|
aws_access_key_id=REPLACE-ME
|
|
aws_secret_access_key=REPLACE-ME
|