feat(argocd): wire SOPS ConfigManagementPlugin properly — initContainer installs sops/yq, sidecar decrypts *.enc.yaml into app Secrets
Correct CMP setup (prior attempt used unsupported config): repoServer.initContainers fetches sops v3.9.0 + yq v4.44.3 into a shared volume; repoServer.extraContainers runs argocd-cmp-server with plugin.yaml from the sops-cmp-plugin ConfigMap, age key from sops-age Secret. Plugin emits authentik/loki-s3-creds/grafana-admin/grafana-oidc Secrets from decrypted enc files. sops-secrets Application (wave 0) uses the plugin at repo root. Unblocks authentik/loki/grafana which were Degraded on missing secrets.
This commit is contained in:
@@ -19,7 +19,8 @@ spec:
|
|||||||
source:
|
source:
|
||||||
repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git
|
repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git
|
||||||
targetRevision: main
|
targetRevision: main
|
||||||
path: k8s/security/sops-secrets
|
path: .
|
||||||
directory: {}
|
plugin:
|
||||||
|
name: sops-secrets-v1.0
|
||||||
destination:
|
destination:
|
||||||
server: https://kubernetes.default.svc
|
server: https://kubernetes.default.svc
|
||||||
|
|||||||
@@ -91,6 +91,69 @@ repoServer:
|
|||||||
serviceMonitor:
|
serviceMonitor:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
|
# ── SOPS ConfigManagementPlugin ─────────────────────────────────────────────
|
||||||
|
# initContainer fetches sops+yq into a shared volume; the sidecar runs
|
||||||
|
# argocd-cmp-server with the plugin.yaml from the sops-cmp-plugin ConfigMap and
|
||||||
|
# decrypts *.enc.yaml with the age key from the sops-age Secret.
|
||||||
|
initContainers:
|
||||||
|
- name: install-sops-tools
|
||||||
|
image: alpine:3.20
|
||||||
|
command: [sh, -c]
|
||||||
|
args:
|
||||||
|
- |
|
||||||
|
set -e
|
||||||
|
apk add --no-cache curl
|
||||||
|
curl -sSfL https://github.com/getsops/sops/releases/download/v3.9.0/sops-v3.9.0.linux.amd64 -o /custom-tools/sops
|
||||||
|
curl -sSfL https://github.com/mikefarah/yq/releases/download/v4.44.3/yq_linux_amd64 -o /custom-tools/yq
|
||||||
|
chmod +x /custom-tools/sops /custom-tools/yq
|
||||||
|
volumeMounts:
|
||||||
|
- name: custom-tools
|
||||||
|
mountPath: /custom-tools
|
||||||
|
extraContainers:
|
||||||
|
- name: sops-cmp
|
||||||
|
image: quay.io/argoproj/argocd:v3.4.5
|
||||||
|
command: [/var/run/argocd/argocd-cmp-server]
|
||||||
|
env:
|
||||||
|
- name: PATH
|
||||||
|
value: /custom-tools:/usr/local/bin:/usr/bin:/bin
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 999
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop: ["ALL"]
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
volumeMounts:
|
||||||
|
- mountPath: /var/run/argocd
|
||||||
|
name: var-files
|
||||||
|
- mountPath: /home/argocd/cmp-server/plugins
|
||||||
|
name: plugins
|
||||||
|
- mountPath: /home/argocd/cmp-server/config/plugin.yaml
|
||||||
|
subPath: plugin.yaml
|
||||||
|
name: sops-cmp-plugin
|
||||||
|
- mountPath: /home/argocd/plugins/generate.sh
|
||||||
|
subPath: generate.sh
|
||||||
|
name: sops-cmp-plugin
|
||||||
|
- mountPath: /custom-tools
|
||||||
|
name: custom-tools
|
||||||
|
- mountPath: /sops-age
|
||||||
|
name: sops-age
|
||||||
|
- mountPath: /tmp
|
||||||
|
name: cmp-tmp
|
||||||
|
volumes:
|
||||||
|
- name: custom-tools
|
||||||
|
emptyDir: {}
|
||||||
|
- name: cmp-tmp
|
||||||
|
emptyDir: {}
|
||||||
|
- name: sops-cmp-plugin
|
||||||
|
configMap:
|
||||||
|
name: sops-cmp-plugin
|
||||||
|
defaultMode: 0555
|
||||||
|
- name: sops-age
|
||||||
|
secret:
|
||||||
|
secretName: sops-age
|
||||||
|
|
||||||
applicationSet:
|
applicationSet:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
resources:
|
resources:
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# ConfigMap holding the SOPS CMP plugin spec + generate script. Mounted into the
|
||||||
|
# repo-server sidecar at /home/argocd/cmp-server/config/plugin.yaml (the path the
|
||||||
|
# argocd-cmp-server binary reads) and /home/argocd/plugins/generate.sh.
|
||||||
|
#
|
||||||
|
# The plugin decrypts every k8s/**/*secrets*.enc.yaml Helm-values fragment and
|
||||||
|
# emits correctly-keyed Kubernetes Secrets to stdout — no helm template inside
|
||||||
|
# the plugin. Applied to the argocd namespace (bootstrap resource).
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: sops-cmp-plugin
|
||||||
|
namespace: argocd
|
||||||
|
data:
|
||||||
|
plugin.yaml: |
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: ConfigManagementPlugin
|
||||||
|
metadata:
|
||||||
|
name: sops-secrets
|
||||||
|
spec:
|
||||||
|
version: v1.0
|
||||||
|
generate:
|
||||||
|
command: [sh, -c]
|
||||||
|
args:
|
||||||
|
- /home/argocd/plugins/generate.sh
|
||||||
|
discover:
|
||||||
|
fileName: "./*.sops-marker"
|
||||||
|
generate.sh: |
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
export SOPS_AGE_KEY_FILE=/sops-age/keys.txt
|
||||||
|
# CMP runs with cwd = the app source path; sops-secrets app points at repo
|
||||||
|
# root, so enc files resolve from the current directory.
|
||||||
|
REPO_ROOT="$(pwd)"
|
||||||
|
|
||||||
|
emit_secret() {
|
||||||
|
# $1 ns $2 name then key=jqpath pairs read from decrypted $ENC
|
||||||
|
ns="$1"; name="$2"; shift 2
|
||||||
|
printf 'apiVersion: v1\nkind: Secret\nmetadata:\n name: %s\n namespace: %s\ntype: Opaque\ndata:\n' "$name" "$ns"
|
||||||
|
for kv in "$@"; do
|
||||||
|
k="${kv%%=*}"; path="${kv#*=}"
|
||||||
|
val="$(echo "$DEC" | yq -r "$path")"
|
||||||
|
printf ' %s: %s\n' "$k" "$(printf '%s' "$val" | base64 -w0)"
|
||||||
|
done
|
||||||
|
printf -- '---\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── authentik (iam) ────────────────────────────────────────────────
|
||||||
|
DEC="$(sops -d "$REPO_ROOT/k8s/security/iam/authentik-secrets.enc.yaml")"
|
||||||
|
emit_secret iam authentik \
|
||||||
|
AUTHENTIK_SECRET_KEY=.authentik.secret_key \
|
||||||
|
AUTHENTIK_BOOTSTRAP_PASSWORD=.authentik.bootstrap_password \
|
||||||
|
AUTHENTIK_BOOTSTRAP_TOKEN=.authentik.bootstrap_token \
|
||||||
|
AUTHENTIK_POSTGRESQL__PASSWORD=.authentik.postgresql_password
|
||||||
|
|
||||||
|
# ── loki S3 (logging) ──────────────────────────────────────────────
|
||||||
|
DEC="$(sops -d "$REPO_ROOT/k8s/platform/logging/loki-secrets.enc.yaml")"
|
||||||
|
emit_secret logging loki-s3-creds \
|
||||||
|
access_key_id=.loki.s3.accessKeyId \
|
||||||
|
secret_access_key=.loki.s3.secretAccessKey
|
||||||
|
|
||||||
|
# ── grafana (logging) ──────────────────────────────────────────────
|
||||||
|
DEC="$(sops -d "$REPO_ROOT/k8s/platform/logging/grafana-secrets.enc.yaml")"
|
||||||
|
emit_secret logging grafana-admin \
|
||||||
|
admin-password=.adminPassword
|
||||||
|
emit_secret logging grafana-oidc \
|
||||||
|
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET=.env.GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET
|
||||||
Reference in New Issue
Block a user