SOPS + age : secrets dans Git sans Vault
À la fin de ce tutoriel, vous saurez installer age et Mozilla SOPS, générer une clé
age1…, configurer.sops.yaml, chiffrer des fichiers YAML/JSON/ENV (clés lisibles, valeurs chiffrées), les committer dans Git, déchiffrer/éditer en local, et brancher un déchiffrement contrôlé dans GitHub Actions — sans déployer HashiCorp Vault.Niveau : Intermédiaire · Temps estimé : 45–60 min · Versions testées : SOPS 3.9+, age (FiloSottile), Git, GitHub Actions · Dernière vérification : 2026-09-11 · Region :
ca-central-1Slug :
wow-sops-age-git· Série : WOW (12/50) · Mot-clé SEO : sops age git · Publish : READY (feu vert Maître)← Précédent : HashiCorp Vault pour secrets DevOps · → Suivant : External Secrets Operator · Aussi : Kubernetes Secrets · Pipeline DevSecOps · GitHub Actions OIDC AWS
Prérequis
- Bases Git (commit,
.gitignore, PR) et notions YAML/JSON - Éditeur terminal (
vim,nanoou VS Code) - Compte GitHub (optionnel) pour la partie CI
- Notions secrets K8s — Kubernetes Secrets
- Survol de Vault secrets DevOps (WOW 11) pour le contraste dynamique vs secrets-as-code
- Aucun cluster Kubernetes ni Vault requis pour ce lab
Coût estimé : 0 € — lab local + runners GitHub Actions. Pas de ressources AWS obligatoires ; ca-central-1 est la convention DEH (tags / exemple d’app).
export AWS_PROFILE=lab
export AWS_DEFAULT_REGION=ca-central-1
Ce que nous allons construire
Lab SOPS + age (WOW 12/50) — ca-central-1
├── keys/age/ # clé privée HORS Git (.gitignore)
├── .sops.yaml # path_regex + destinataires age publics
├── secrets/
│ ├── app.yaml # YAML chiffré (clés lisibles)
│ ├── config.json
│ └── demo.env
├── .github/workflows/sops-decrypt.yml
├── workflow : decrypt → edit → re-encrypt
└── multi-destinataires + rotation + FAQ + quiz
(Schéma — alt : « Secret clair → SOPS+age → fichier chiffré dans Git → CI déchiffre avec identité age privée en secret runner ».)
Étape 1 — Pourquoi SOPS + age (sans Vault)
Mozilla SOPS chiffre les valeurs d’un fichier structuré tout en laissant les clés lisibles — idéal pour les revues de PR. age (FiloSottile) offre un chiffrement moderne (clés age1…), sans la lourdeur PGP.
| Approche | Modèle | Force | Limite |
|---|---|---|---|
| SOPS + age | Secrets-as-code dans Git | Auditable, PR-friendly, offline | Secrets statiques ; rotation manuelle |
| Vault (WOW 11) | Secrets dynamiques / lease | TTL, audit central | Ops, HA, réseau |
| External Secrets (WOW 13) | Sync → Secret K8s | Bridge cloud/Vault → cluster | Dépend d’un backend |
| Sealed Secrets | Controller K8s | Chiffre pour un cluster | Moins portable hors K8s |
Chez DevOps Elastic Hayway : SOPS pour configs sensibles versionnées, Vault pour le dynamisme, ESO pour injecter dans Kubernetes. Voir Argo CD GitOps et Sealed Secrets en complément.
Étape 2 — Installer age et SOPS
AGE_VERSION=1.2.1
curl -sL "https://github.com/FiloSottile/age/releases/download/v${AGE_VERSION}/age-v${AGE_VERSION}-linux-amd64.tar.gz"
| tar -xz
sudo mv age/age age/age-keygen /usr/local/bin/
age --version && age-keygen --version
SOPS_VERSION=3.9.4
curl -sL "https://github.com/getsops/sops/releases/download/v${SOPS_VERSION}/sops-v${SOPS_VERSION}.linux.amd64"
-o sops && chmod +x sops && sudo mv sops /usr/local/bin/
sops --version
macOS : brew install age sops. Lab :
mkdir -p ~/lab-sops-age/{keys/age,secrets,.github/workflows}
cd ~/lab-sops-age
printf 'keys/n*.keynkeys/age/key.txtn' >> .gitignore
Règle d’or : la clé privée age ne quitte jamais le disque local (ou un secret CI). Seule la clé publique (age1…) va dans .sops.yaml.
Étape 3 — Générer une clé age et .sops.yaml
age-keygen -o keys/age/key.txt
# Public key: age1xxxxxxxx...
grep 'public key:' keys/age/key.txt
export SOPS_AGE_KEY_FILE="$HOME/lab-sops-age/keys/age/key.txt"
Remplacez CHANGE_ME_AGE_PUBLIC par votre age1… réel :
# .sops.yaml — destinataires publics uniquement
creation_rules:
- path_regex: secrets/.*.(yaml|yml|json|env)$
age: >-
CHANGE_ME_AGE_PUBLIC
- path_regex: secrets/prod/.*.(yaml|yml)$
age: >-
CHANGE_ME_AGE_PUBLIC,age1OTHER_TEAM_RECIPIENT_DEMO
path_regex cible les fichiers chiffrés automatiquement. Plusieurs destinataires age = chaque détenteur de la clé privée correspondante peut déchiffrer (équipe + CI).
git check-ignore -v keys/age/key.txt
# Ne committez JAMAIS keys/age/key.txt
Étape 4 — Chiffrer un fichier secrets et committer dans Git
cat > secrets/app.yaml <<'EOF'
app:
name: wow-demo
region: ca-central-1
database:
host: db.lab.example.internal
username: app_user
password: CHANGE_ME_super_secret_password
api:
token: CHANGE_ME_api_token_demo
aws:
default_region: ca-central-1
bucket: wow-lab-demo-ca-central-1
EOF
sops --encrypt --in-place secrets/app.yaml
head -n 30 secrets/app.yaml
Les clés (password, token, region) restent lisibles ; les valeurs sensibles deviennent ENC[AES256_GCM,data:…]. C’est le point fort SOPS pour les reviews Git.
git add .sops.yaml secrets/app.yaml .gitignore
git commit -m "feat(secrets): SOPS+age demo ca-central-1"
echo '{"db_password":"CHANGE_ME","region":"ca-central-1"}' > secrets/config.json
sops --encrypt --in-place secrets/config.json
printf 'API_TOKEN=CHANGE_MEnAWS_REGION=ca-central-1n' > secrets/demo.env
sops --encrypt --in-place secrets/demo.env
Étape 5 — Déchiffrer, éditer, re-chiffrer (workflow quotidien)
export SOPS_AGE_KEY_FILE="$HOME/lab-sops-age/keys/age/key.txt"
sops --decrypt secrets/app.yaml | head
sops secrets/app.yaml # éditeur : decrypt → edit → re-encrypt au save
sops --decrypt secrets/app.yaml > /tmp/app.clear.yaml
rm -f /tmp/app.clear.yaml
sops exec-env injecte un ENV chiffré comme variables pour une commande :
sops exec-env secrets/demo.env -- env | grep -E 'API_TOKEN|AWS_REGION'
sops exec-env secrets/demo.env -- ./scripts/migrate-demo.sh
Plugin helm-secrets (mention) : helm secrets upgrade … -f secrets/values.enc.yaml déchiffre à la volée — utile avec Argo CD si vous restez en secrets-as-code.
Checklist DEH : (1) SOPS_AGE_KEY_FILE local, (2) sops fichier.yaml pour éditer, (3) diff Git = blobs ENC[], (4) PR reviewable (structure visible).
Étape 6 — CI (GitHub Actions) : déchiffrement contrôlé
Stockez la clé privée dans le secret Actions SOPS_AGE_KEY (contenu de key.txt). Ne loggez jamais la clé.
# .github/workflows/sops-decrypt.yml
name: sops-decrypt-lab
on:
pull_request:
workflow_dispatch:
jobs:
decrypt-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install SOPS + age
run: |
curl -sL "https://github.com/getsops/sops/releases/download/v3.9.4/sops-v3.9.4.linux.amd64"
-o /usr/local/bin/sops && chmod +x /usr/local/bin/sops
curl -sL "https://github.com/FiloSottile/age/releases/download/v1.2.1/age-v1.2.1-linux-amd64.tar.gz"
| tar -xz -C /tmp && sudo mv /tmp/age/age /usr/local/bin/
- name: Decrypt demo (no echo of values)
env:
SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
run: |
printf '%sn' "$SOPS_AGE_KEY" > /tmp/age-key.txt
chmod 600 /tmp/age-key.txt
export SOPS_AGE_KEY_FILE=/tmp/age-key.txt
sops --decrypt secrets/app.yaml > /tmp/app.yaml
grep -q 'ca-central-1' /tmp/app.yaml
grep -q 'wow-demo' /tmp/app.yaml
shred -u /tmp/age-key.txt /tmp/app.yaml
Pour AWS en ca-central-1, combinez avec GitHub Actions OIDC AWS : OIDC pour le cloud, SOPS pour Git. Dans un pipeline DevSecOps, le job de decrypt est least-privilege (environnement protégé).
Étape 7 — Multi-destinataires, rotation, bonnes pratiques
Multi-destinataires : plusieurs age1… séparés par des virgules dans .sops.yaml, puis sops updatekeys secrets/app.yaml.
Rotation : (1) age-keygen -o keys/age/key-new.txt, (2) ajoutez la nouvelle publique (gardez l’ancienne temporairement), (3) sops updatekeys -y secrets/*.yaml, (4) distribuez la nouvelle privée (CI + password manager), (5) retirez l’ancienne et updatekeys à nouveau.
Bonnes pratiques DEH : jamais de clé privée dans Git/Slack/README ; préfixe secrets/ + path_regex strict ; placeholders CHANGE_ME en lab ; contraste SOPS=Git / Vault=dynamique / ESO=sync K8s ; tags exemples en ca-central-1.
Troubleshooting
| Symptôme | Cause / correction |
|---|---|
no age identity found |
SOPS_AGE_KEY_FILE absent ou mauvais chemin |
failed to get the data key |
Mauvaise clé privée / destinataire absent de .sops.yaml |
| Fichier clair commité | Pre-commit + rotation immédiate |
| Diff Git illisible | Normal sur ENC[] ; éditez via sops fichier |
| CI OK, local KO | Clé CI ≠ destinataire ; sops updatekeys |
path_regex ignore le fichier |
Regex trop stricte ; sops -e fichier explicite |
| Helm ne déchiffre pas | Plugin helm-secrets + clé age correcte |
FAQ
SOPS remplace-t-il Vault ?
Non. SOPS versionne des secrets statiques dans Git. Vault (WOW 11) gère dynamisme, leases et audit. Ils se complètent.
Pourquoi age plutôt que PGP ?
Plus simple (age1…), moins d’erreurs, moderne (X25519). SOPS supporte aussi AWS KMS / GCP KMS.
Peut-on chiffrer tout le fichier ?
Oui (--input-type binary), mais vous perdez la review des clés. Préférez le mode structuré YAML/JSON.
Où stocker la clé privée en équipe ?
Password manager + secret CI (SOPS_AGE_KEY). Jamais dans le repo. Alternative : KMS comme destinataire SOPS.
Lien avec External Secrets Operator ?
SOPS alimente Git ; ESO (WOW 13) synchronise Vault/ASM vers Secrets K8s — plus idiomatique en prod cluster.
Et Sealed Secrets ?
Chiffre pour un cluster précis. SOPS+age reste multi-env / multi-cloud sans controller obligatoire.
Quiz (5 questions)
1. Avec SOPS sur un YAML, que reste-t-il lisible après chiffrement ?
– A. Rien (fichier binaire opaque)
– B. Les clés (chemins) ; les valeurs sensibles sont ENC[…]
– C. Uniquement le mot de passe en clair
2. Que committez-vous dans Git ?
– A. La clé privée age (key.txt)
– B. La clé publique age1… dans .sops.yaml + fichiers chiffrés
– C. Les secrets en clair « juste pour le lab prod »
3. Par rapport à Vault (WOW 11), SOPS+age est surtout :
– A. Un serveur de secrets dynamiques avec TTL
– B. Des secrets-as-code chiffrés dans Git
– C. Un ingress TLS automatique
4. La région lab DEH utilisée dans les exemples est :
– A. us-east-1 uniquement
– B. ca-central-1
– C. eu-west-3 obligatoire
5. En CI GitHub Actions, la pratique sûre est :
– A. Echo de SOPS_AGE_KEY dans les logs pour debug
– B. Stocker la clé privée en secret Actions, déchiffrer, shred les temporaires
– C. Committer keys/age/key.txt sur la branche ci
Réponses : 1‑B · 2‑B · 3‑B · 4‑B · 5‑B
Pour aller plus loin
- Mozilla SOPS · age
- HashiCorp Vault pour secrets DevOps (WOW 11)
- External Secrets Operator (WOW 13)
- Kubernetes Secrets · Pipeline DevSecOps
- GitHub Actions OIDC AWS · Argo CD GitOps
- Documentation helm-secrets / plugin SOPS
Maillage série WOW
| ← Précédent | HashiCorp Vault pour secrets DevOps |
| → Suivant | External Secrets Operator |
| Aussi | Kubernetes Secrets · DevSecOps · GitHub Actions OIDC AWS · Argo CD · Sealed Secrets |
Meta publication (SEO)
- Title SEO : SOPS + age : secrets dans Git sans Vault (guide FR)
- Meta description : Mozilla SOPS + FiloSottile age : chiffrez YAML/JSON/ENV dans Git, .sops.yaml, workflow quotidien, CI GitHub Actions, rotation multi-destinataires, FAQ. Région ca-central-1 — DevOps Elastic Hayway WOW 12/50.
- Focus keyword : sops age git
- Secondary : sops age, secrets git chiffrement, mozilla sops, age encryption devops
- Schemas : Article + HowTo + FAQ
- Image :
assets/web/devopelastichayway/cover-wow-sops-age-git-1200x630.webp(à générer) - Catégorie : WOW / Secrets · Niveau : Intermédiaire
- Parent WP : /tutoriels/ (parent 5463)
- URL cible : https://devopelastichayway.com/tutoriels/wow-sops-age-git/
- Post live : N/A (nouveau) · slug
wow-sops-age-git· Publish : READY (feu vert Maître + auto-push WP-CLI)
Pour aller plus loin — hubs live
Retour parcours Catalogue Tutoriels — hub de la série et leçons sœurs.