feat(phase0): setup SOPS for encrypted secret management

Phase 0 groundwork for helmfile→ArgoCD migration using SOPS (Secrets Operations):

1. Install SOPS + AGE encryption
   - AGE key generated and stored locally at ~/.sops/key.txt
   - Public key embedded in .sops.yaml for file encryption rules

2. Create K8s Secret for AGE private key
   - kubectl: create secret generic sops-age -n argocd --from-file=keys.txt=~/.sops/key.txt
   - ArgoCD will use this key to decrypt secrets at sync time

3. Encrypt initial secrets
   - k8s/base/secrets.enc.yaml: AES256_GCM encrypted secrets for all services
   - Placeholder values (will be replaced with real values per environment)
   - Secrets never visible in git (encrypted at rest)

4. Configure SOPS
   - .sops.yaml: creation rules for k8s/*/secrets.enc.yaml files
   - All future secret files auto-encrypt on edit (sops -e)

Setup: Store AGE key as K8s Secret in argocd namespace:
  export KUBECONFIG=cluster-config/kubeconfig
  kubectl create secret generic sops-age -n argocd --from-file=keys.txt=~/.sops/key.txt

Next: Configure ArgoCD Helm plugin to decrypt secrets on sync (Phase 0 continuation).

Co-Authored-By: Claude Haiku 4.5 <[email protected]>
This commit is contained in:
Story Crater Bot
2026-08-18 15:08:01 -07:00
co-authored by Claude Haiku 4.5
parent f2b6ad1c60
commit ee385e59a1
3 changed files with 44 additions and 0 deletions
+1
View File
@@ -45,3 +45,4 @@ terraform/*.tfstate
terraform/*.tfstate.*
terraform.tfvars.local
skills-lock.json
secrets-plaintext.yaml
+3
View File
@@ -0,0 +1,3 @@
creation_rules:
- path_regex: k8s/.*secrets.*\.ya?ml
age: age1smu533f803gmd0jq60s2zaj9zlznajy0ca6rtewd4r37mr2hs3uqsrldfh
+40
View File
@@ -0,0 +1,40 @@
#ENC[AES256_GCM,data:k1a5oCIROHB42A03dwKG3cCui4iOr2YQ1S2BydD8/KZFwAaGZ+0=,iv:bOu/4lsBjwWeNueNT5IoKqxnxUsD08wqrnMj3PbO6ZA=,tag:KxqqstEoZek5iIl77vU9BA==,type:comment]
#ENC[AES256_GCM,data:kcyifte8jC2RIxTAEhd739OPeDE/cN9HgLsvoXkYvrCI1RTct91aFMVhvAsdV3WmFQhIsaKm41m4XuMYX4s/A/eSrobtkHJcsGFDBYtycw==,iv:rojwVUquM7W40bZzDRT1ZR3nh/Q78CsWPGgA7dA5+Tc=,tag:3dL7o5GoioD4YGG4uwl/9w==,type:comment]
authentik:
secret_key: ENC[AES256_GCM,data:OC4O2uQU9ZSIlpzXbaRkQy7f6bVeFKEXzEv0EeqfN00=,iv:OlLZz/7hF2DrajC6HH5wCd99/tZmyeCs2Bhy6Tsa5YU=,tag:e6o5KIChJp9P9arpzIVq0A==,type:str]
bootstrap_password: ENC[AES256_GCM,data:d8ssYA2Qrza5R01b9jTE8siqy1Xhkom9xaHaCHbZ,iv:owp4nlv5fElzNIQ07yZSpWtsdSWKnLfdubOisDKdnJI=,tag:Z6rOQqa1iThjQEyAGvUqog==,type:str]
bootstrap_token: ENC[AES256_GCM,data:SZIjtiybSqk5TZCK7tknEsGeE165K7eDS40T,iv:/rF97yp3MxZn1nlw3xuN7oW/3+F5/xOkUlV5rrxVozY=,tag:Q3vkjaZatKemV7PjV77Duw==,type:str]
postgresql_password: ENC[AES256_GCM,data:myRIPmkEXnBNoK0IvD+BhkZo9FFNo/D3rvX06x/+5ozR,iv:MzmgyfKhug4KssBDaKzddhQCK2kfCIY1jey8sDt1oMU=,tag:AyQw/lJNvJcO5MACpaivog==,type:str]
minio:
root_user: ENC[AES256_GCM,data:+EQ2wuGD1kkzwA==,iv:wuj5wnW9Snv23KrrGM6gJALFXCj8JDgkFC757j8sQ4E=,tag:+GxxIgtIe1tVLKooyK2zGg==,type:str]
root_password: ENC[AES256_GCM,data:Nk2F+G1GC9t9HVZm+UltRRXTCptb6P3oegw=,iv:9HtWDrb2i5CuWAIKy1tTqam1nLkpylTTx+jg8we+tOQ=,tag:kJ/6zXw1dr8qZeVu18qMMA==,type:str]
oidc_client_secret: ENC[AES256_GCM,data:nekH14JGIL6Cp5WRlr5DLgIRZZHpy8zW6972lIs=,iv:7b4GeRUi0dD8HJ5NVcfYoW26V+xlTH03pFxfwS8Fdk0=,tag:+A+sIOBJCmGgGBLKyVYR8Q==,type:str]
forgejo:
admin_password: ENC[AES256_GCM,data:yV31S6LtztoRShZ7Sy/p5HMHsXKD82emFp4D5g==,iv:yznI8H6a8gOAl334aSFtwBBjv8K5B5hxKA7u7ZIwX48=,tag:MLef9OHXbXcxtIutr4t+Tw==,type:str]
oidc_client_secret: ENC[AES256_GCM,data:md3A65MtGRtth6rotRgUiLiP1L4wuA7F5MD7rdxHdw==,iv:DFRa32Dy1Jp5l0BNoPSbNbYRwo2KY38UIgWdpCRjm9k=,tag:qwMAJ0JMhhvmTlw6SFebPg==,type:str]
grafana:
admin_password: ENC[AES256_GCM,data:r3V6owuFGH1FciXbPXBX0stEkrXQ4J+QpA9nUA==,iv:d+IpwYe2Jtxb3RI0qkMClTKLVmDHfyu1ismG9ZG+l3w=,tag:s5HBtXq6zBMOqlV5egNeeQ==,type:str]
oidc_client_secret: ENC[AES256_GCM,data:ne/YcY1wsLYFFrELfaA5kgGNeSb+Fb3/s9NAqAtRXA==,iv:3m3BLCNarhIPHIrCJX7YpER+JiTxnI91lmjpQh837AU=,tag:OVVRxGfLloCfIA0PbBjYog==,type:str]
argocd:
oidc_client_secret: ENC[AES256_GCM,data:kS3WCF0NGWWYeQjo8M5p8vu6FKTozLdR437dnn+D,iv:kLRlwiur1YWLgGc2UFwPp/5+GUmNX8finanLPAAqhD4=,tag:N/cV8xGrh/99d2MGpEk/Mg==,type:str]
temporal:
oidc_client_id: ENC[AES256_GCM,data:1uz28SF6Vitn3VB4J9wOb0ggFr27TrJpgGELow==,iv:7xTD3Z3843UYCGxnvoZ2tDWOs4CjbF5P5fxIg9SyOm4=,tag:NSm+3jim+HNRkn5slAunJw==,type:str]
oidc_client_secret: ENC[AES256_GCM,data:gNWGxyniP3FI58YdLh55LqDbUxwUHH+1hvnioxRB9ys=,iv:WpfOAw6C3wIeNEYT+kOjRKfKEdP6tMZziFAzdTov4Uo=,tag:Tnfl5/ggsmWdDndKNibuJw==,type:str]
ollama:
oidc_client_id: ENC[AES256_GCM,data:8lXuGFkPwnOI9uNA9cbNh92q+vIZSZR8hNU=,iv:rMZtnwyYS1bvovKQDO/FO3xZItgXiopOnY8ab4ApBso=,tag:Rx6tniX2i+leCzr5c52yxA==,type:str]
oidc_client_secret: ENC[AES256_GCM,data:ssYURrGZ+7jbKUfoNLxyrOXR1Ee9QXfUpBlAHjYi,iv:bhlVSQFF+Xza9WzBQUlmhWs33zi6nmUprZ5txP9kWtw=,tag:FNPfUdXNh5b10oz5IYRWSg==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBxbEhGbHJEbktxSmVIRjF6
Z2JFb3pjMWg2elBhVEV3UmVGTit0V29TTW1JCkptVkUvTnkxaGJnaTI1RHh4d0R0
TXY1QVBVOUFvc0dvUjBhZHhIT0k0dncKLS0tIG0yZEVLK01wMGx0bHNRckpUT3c1
TzZORWdzK3ZvOFJhRC9KWW1Gbmc2SzAK0GXC78gW8MrPEpZEgYPTxmXs8MOeNz8E
LqHuHHTDBl7m4IOwkuKhqvzR1+DJ8FeMEyzdF5OE61wkAes/758ZlQ==
-----END AGE ENCRYPTED FILE-----
recipient: age1smu533f803gmd0jq60s2zaj9zlznajy0ca6rtewd4r37mr2hs3uqsrldfh
lastmodified: "2026-07-15T21:59:44Z"
mac: ENC[AES256_GCM,data:VeRGqVo6KVNkFTkeuOeeYdpOz6Pjf/ndqF4RjDsS73kW+gh7Q1O7dbuGWxJquhG/jTamZQa8XkMk0NA0KtAuyqxbM7sWXbKV4bk3hDYGOk/AZ6XEo4sjivvqLiYctaZQ0DHQ7v6Q1tB5BBvN2wVs7ueh4T/HsEVT3aFGH2iTlTg=,iv:UP1LRRVzZD+aYr/mlZjHcyIXSDW/4p3b6UdB20A6uIY=,tag:QO7Jdz4L56AqheAYcvJcjw==,type:str]
unencrypted_suffix: _unencrypted
version: 3.13.2