- ExternalSecret syncs age key from Vault to pod - CRD defines rotation schedule for each secret - Controller watches CRD, rotates on schedule: * Call provider API (Authentik/Forgejo/MinIO) for new secret * Update k8s Secret * Update .enc.yaml via sops (uses age key from Vault) * Git commit and push - Vault is source of truth for age key (never on disk) - Examples: minio-oidc (90d), portfolio-agent (90d), forgejo-token (90d), minio-root (180d)
93 lines
2.4 KiB
YAML
93 lines
2.4 KiB
YAML
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: secret-rotation-controller
|
|
namespace: secret-rotation
|
|
spec:
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
app: secret-rotation-controller
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: secret-rotation-controller
|
|
spec:
|
|
serviceAccountName: secret-rotation-controller
|
|
containers:
|
|
- name: controller
|
|
image: secret-rotation-controller:latest
|
|
imagePullPolicy: IfNotPresent
|
|
env:
|
|
# SOPS reads age key from this file
|
|
- name: SOPS_AGE_KEY_FILE
|
|
value: /etc/sops/age/private-key.txt
|
|
|
|
# Vault auth (token in projected volume)
|
|
- name: VAULT_ADDR
|
|
value: http://vault.vault.svc.cluster.local:8200
|
|
- name: VAULT_TOKEN_FILE
|
|
value: /var/run/secrets/vault/token
|
|
|
|
# Authentik
|
|
- name: AUTHENTIK_URL
|
|
value: http://authentik-server.iam.svc.cluster.local
|
|
- name: AUTHENTIK_BOOTSTRAP_TOKEN
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: authentik-bootstrap
|
|
key: token
|
|
|
|
# Git
|
|
- name: GIT_REPO
|
|
value: https://forgejo.riotpiao.com/rock/homelab.git
|
|
- name: GIT_AUTHOR_EMAIL
|
|
value: [email protected]
|
|
- name: GIT_AUTHOR_NAME
|
|
value: Secret Rotation Controller
|
|
- name: FORGEJO_TOKEN
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: forgejo-registry-secret
|
|
key: REGISTRY_TOKEN
|
|
|
|
volumeMounts:
|
|
# Age key from ExternalSecret (synced from Vault)
|
|
- name: age-key
|
|
mountPath: /etc/sops/age
|
|
readOnly: true
|
|
|
|
# Vault auth token (projected)
|
|
- name: vault-token
|
|
mountPath: /var/run/secrets/vault
|
|
readOnly: true
|
|
|
|
# Temp working dir
|
|
- name: tmp
|
|
mountPath: /tmp
|
|
|
|
resources:
|
|
requests:
|
|
cpu: 100m
|
|
memory: 256Mi
|
|
limits:
|
|
cpu: 500m
|
|
memory: 512Mi
|
|
|
|
volumes:
|
|
- name: age-key
|
|
secret:
|
|
secretName: sops-age-key
|
|
defaultMode: 0400
|
|
|
|
- name: vault-token
|
|
projected:
|
|
sources:
|
|
- serviceAccountToken:
|
|
path: token
|
|
audience: vault
|
|
expirationSeconds: 3600
|
|
|
|
- name: tmp
|
|
emptyDir: {}
|