bootstrap/sops (age-keygen refusing in-repo, .sops.yaml, install-age-key.sh glue installing the sops-age Secret) + bootstrap/flux (bootstrap.sh: flux install -> apply -k clusters/dev; decryption/url patches). PM wiring: place .sops.yaml at repo root (SOPS walks to root); inline the 3 flux patches into clusters/dev (avoids kustomize ../ load-restriction). clusters/dev builds with decryption enabled; full CI gate PASS. No key material; nothing executed. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
28 lines
1.5 KiB
Bash
Executable File
28 lines
1.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# bootstrap/sops/install-age-key.sh — install the age PRIVATE key into the cluster as the
|
|
# `sops-age` Secret in flux-system, so Flux can decrypt SOPS-encrypted manifests (ADR-0007,
|
|
# R-SEC-01). This is the scripted form of the runbook in age-key-secret.md, and the entrypoint
|
|
# the Ansible flux_bootstrap role calls (flux_bootstrap_sops_cmd) BEFORE bootstrap.sh.
|
|
#
|
|
# The private key NEVER lives in git. It is read from AGE_KEY_FILE (default: the standard sops
|
|
# age path) and passed to kubectl from a file (not argv). Run at bootstrap by the OPERATOR — not
|
|
# by any agent, and not during author-only Phase 1.
|
|
set -euo pipefail
|
|
AGE_KEY_FILE="${AGE_KEY_FILE:-${HOME}/.config/sops/age/keys.txt}"
|
|
NAMESPACE="${FLUX_NAMESPACE:-flux-system}"
|
|
SECRET_NAME="${SOPS_SECRET_NAME:-sops-age}"
|
|
|
|
[ -f "$AGE_KEY_FILE" ] || { echo "ERROR: age key not found at ${AGE_KEY_FILE} — run age-keygen.sh first." >&2; exit 1; }
|
|
grep -q 'AGE-SECRET-KEY-' "$AGE_KEY_FILE" || { echo "ERROR: ${AGE_KEY_FILE} contains no AGE-SECRET-KEY." >&2; exit 1; }
|
|
|
|
kubectl get namespace "$NAMESPACE" >/dev/null 2>&1 || kubectl create namespace "$NAMESPACE"
|
|
|
|
# Flux reads keys ending in `.agekey` from the sops-age Secret. Idempotent create-or-update;
|
|
# the key is streamed from the file, never placed on the command line / in shell history.
|
|
kubectl create secret generic "$SECRET_NAME" \
|
|
--namespace "$NAMESPACE" \
|
|
--from-file=age.agekey="$AGE_KEY_FILE" \
|
|
--dry-run=client -o yaml | kubectl apply -f -
|
|
|
|
echo "Installed Secret ${NAMESPACE}/${SECRET_NAME} for Flux SOPS decryption."
|