## Introduction

Les Secrets Kubernetes contiennent des identifiants, clés API, jetons, matériel TLS et autres valeurs critiques. Les sauvegarder et les restaurer en toute sécurité est un prérequis indispensable pour la reprise d'activité, mais cela reste souvent implicite jusqu'à ce qu'une panne force l'action. Ce guide pratique montre comment :

- Inventorier et délimiter un projet pilote sûr pour la sauvegarde des Secrets

- Exporter les Secrets avec des manifests minimaux et réutilisables

- Chiffrer et stocker les sauvegardes

- Restaurer les Secrets proprement vers un namespace ou un nouveau cluster

- Vérifier la correction avec des contrôles concrets et observables

- Identifier les modes de défaillance et récupérer de façon prévisible

- Exécuter avec une liste de contrôle opérationnelle répétable

Les exemples supposent un shell de type Unix et l'accès kubectl . Tous les exemples sont construits et utilisent des noms et valeurs hypothétiques pour la clarté.

## Inventaire des versions et de l'environnement

Avant toute manipulation, consignez votre environnement. Cela aide à choisir les bonnes commandes, éviter les surprises et garder une trace reproductible.

Prérequis :

- Kubernetes : v1.19+ recommandé (supporte les Secrets immuables). Toute version maintenue fonctionne.

- kubectl : correspondez à la version mineure de votre cluster quand c'est possible.

- Accès : vous avez besoin au minimum de get/list/watch/create/patch/delete sur les Secrets dans les namespaces cibles. Pour une sauvegarde cluster-wide, il faut lister les Secrets à l'échelle du cluster.

- Outils optionnels pour simplifier l'export et la conversion : jq , yq , openssl , sops / age (pour le chiffrement au repos des sauvegardes).

- Un périmètre pilote étroit : un namespace et 1 à 3 Secrets critiques. Restez mesurable et inspectable localement.

Commandes d'inventaire rapides (lecture seule) :

kubectl version --short
kubectl config get-contexts
kubectl auth can-i list secrets -A
kubectl get ns 
 Consignez le ou les namespaces cibles et les Secrets pour le pilote. Par exemple : namespace demo , secrets ai-api , app-tls .

## Chemin de configuration sécurisé

Cette section décrit un chemin délimité et répétable que vous pouvez adopter dès aujourd'hui. Elle se concentre sur l'export basé sur kubectl avec métadonnées minimales, chiffrement au repos optionnel, et restaurations simples. Vous pourrez l'étendre plus tard avec votre gestion de clés ou automatisation préférée.

### Décider quoi sauvegarder et quoi exclure

Tous les Secrets n'ont pas leur place dans votre jeu de sauvegarde. Commencez par les éléments à haute valeur et faible taux de changement.

<div class="my-stack-md overflow-x-auto">
<table class="w-full min-w-[42rem] border-collapse text-left">
<thead><tr><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Type ou usage du Secret</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Inclure dans la sauvegarde ?</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Notes</th></tr></thead>
<tbody><tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Opaque (clés API, identifiants DB)</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Oui</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Identifiants critiques d&#39;application.</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">kubernetes.io/tls</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Oui</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Certificats et clés ; vérifier l&#39;expiration à la restauration.</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">kubernetes.io/dockerconfigjson</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Oui</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Requis pour les tirages d&#39;images depuis registres privés.</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Jetons de compte de service (hérités)</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Généralement non</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Éphémères dans les clusters modernes (1.24+). Recréer via comptes de service si nécessaire.</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Jetons générés ou courts</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Généralement non</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Préférer les procédures de régénération à la sauvegarde.</td></tr></tbody>
</table>
</div>

### Identifier les Secrets cibles (pilote)

Exemples de commandes construits pour un pilote dans le namespace demo :

# Lister les Secrets et leurs types
kubectl get secrets -n demo -o custom-columns=NAME:.metadata.name,TYPE:.type

# Filtrer les Secrets probablement gérés par l'utilisateur (exclure les jetons de compte de service hérités)
kubectl get secrets -n demo -o json | jq -r '.items[] | select(.type!="kubernetes.io/service-account-token\)) | [.metadata.name,.type] | @tsv' 
 Choisissez 1 à 3 Secrets pour le pilote, par exemple :

- ai-api (Opaque) avec une clé API

- app-tls (kubernetes.io/tls) pour le HTTPS entrant

### Exporter un Secret unique avec métadonnées minimales

kubectl renvoie des données encodées en base64 plus de nombreux champs de métadonnées que vous ne voulez pas dans une sauvegarde réutilisable. Supprimez les champs volatils pour que le manifest puisse être appliqué proprement ailleurs.

Exemple construit : exporter le Secret ai-api depuis demo en YAML minimal :

- Exporter en JSON et retirer les métadonnées volatiles :

kubectl get secret ai-api -n demo -o json \
 | jq 'del(.metadata.uid, .metadata.resourceVersion, .metadata.creationTimestamp, .metadata.managedFields, .metadata.annotations["kubectl.kubernetes.io/last-applied-configuration"], .metadata.generation)' \
 > ai-api.json 

- Optionnellement convertir le JSON en YAML pour la lisibilité :

 yq -P e ai-api.json > ai-api.yaml 
 Le fichier ai-api.yaml résultant doit ressembler à cet exemple construit (valeurs hypothétiques) :

apiVersion: v1
kind: Secret
metadata:
 name: ai-api
 namespace: demo
type: Opaque
data:
 OPENAI_API_KEY: c2stdGVzdC1BQUFCQ0QxMjM0NTY= 
 Attention : les valeurs data sont encodées en base64, pas chiffrées. Traitez ces fichiers comme sensibles et restreignez l'accès.

### Exporter les Secrets TLS

Pour TLS, le type doit être kubernetes.io/tls avec deux clés : tls.crt et tls.key .

kubectl get secret app-tls -n demo -o json \
 | jq 'del(.metadata.uid, .metadata.resourceVersion, .metadata.creationTimestamp, .metadata.managedFields, .metadata.annotations["kubectl.kubernetes.io/last-applied-configuration"], .metadata.generation)' \
 > app-tls.json
yq -P e app-tls.json > app-tls.yaml 

### Export en masse pour un namespace

 Pour une structure simple par fichier Secret (diffing et restauration plus faciles) :

NS=demo
TS=$(date +%Y%m%d-%H%M%S)
mkdir -p backups/$NS-$TS
for s in $(kubectl get secrets -n $NS -o jsonpath='{.items[*].metadata.name}'); do
 kubectl get secret "$s" -n $NS -o json \
 | jq 'select(.type != "kubernetes.io/service-account-token\)) | del(.metadata.uid, .metadata.resourceVersion, .metadata.creationTimestamp, .metadata.managedFields, .metadata.annotations["kubectl.kubernetes.io/last-applied-configuration"], .metadata.generation)' \
 > backups/$NS-$TS/$s.json
 yq -P e backups/$NS-$TS/$s.json > backups/$NS-$TS/$s.yaml
 rm backups/$NS-$TS/$s.json
done 
 Ajustez les filtres selon votre environnement. Conservez JSON et YAML si vous préférez ; le YAML est montré pour la lisibilité.

### Optionnel : Chiffrer les sauvegardes au repos

Si vous stockez les sauvegardes hors d'un coffre dédié, utilisez le chiffrement au niveau fichier. Comme option, chiffrez avec sops et age (exemple construit) :

# Générer une paire de clés age (une fois)
age-keygen -o ~/.age/key.txt

# Chiffrer un fichier YAML pour votre destinataire public
sops --encrypt --age YOUR_AGE_PUBLIC_KEY backups/demo-20260101-000000/ai-api.yaml \
 > backups/demo-20260101-000000/ai-api.enc.yaml

# Déchiffrer lors de la restauration
sops --decrypt backups/demo-20260101-000000/ai-api.enc.yaml > /tmp/ai-api.yaml 
 Restreignez les permissions du système de fichiers pour les clés et sauvegardes (par exemple, chmod 600 sur les fichiers et répertoires sensibles).

### Restaurer un Secret unique (même cluster ou nouveau cluster)

- Assurez-vous que le namespace cible existe :

kubectl get ns demo || kubectl create ns demo 

- Appliquez le manifest du Secret :

 kubectl apply -f ai-api.yaml 

- Si un Secret était marqué immutable: true et que des valeurs changées sont requises, supprimez puis recréez :

 # Vérifier si immuable
kubectl get secret ai-api -n demo -o jsonpath='{.immutable}' 2>/dev/null || true

# Si immutable est true, faire delete-then-apply :
kubectl delete secret ai-api -n demo
kubectl apply -f ai-api.yaml 

- Pour TLS, appliquez de façon similaire :

 kubectl apply -f app-tls.yaml 

- Redémarrez les charges de travail qui consomment des variables d'environnement depuis les Secrets (les pods ne rechargent pas automatiquement les variables d'env). Pour les déploiements :

 kubectl rollout restart deploy/myapp -n demo 
 Les montages en volume reflètent les mises à jour des Secrets peu après modification ; les variables d'env nécessitent un redémarrage du pod.

### Restaurer plusieurs Secrets

Si vous avez exporté des fichiers YAML par Secret dans un répertoire :

kubectl apply -f backups/demo-20260101-000000/ 
 Si les fichiers incluent des Secrets immuables et que les valeurs ont réellement changé, pré-supprimez au besoin (ou retirez immutable: true du fichier, supprimez, puis appliquez).

## Vérification et diagnostics

Il vous faut des contrôles clairs et observables prouvant que les artefacts de sauvegarde et les objets restaurés sont corrects.

### Vérifier les fichiers de sauvegarde localement

# Inspecter métadonnées et type
yq e '.kind, .metadata.name, .metadata.namespace, .type' ai-api.yaml

# Vérifier l'existence des clés attendues (exemple construit attend OPENAI_API_KEY)
yq e '.data | keys' ai-api.yaml

# Optionnellement décoder et comparer les valeurs hors ligne (stocker les sorties en sécurité)
yq -r '.data.OPENAI_API_KEY' ai-api.yaml | base64 -d | sha256sum 
 Consignez les hachages pour comparaison après restauration.

### Vérifier le Secret restauré dans le cluster

# Confirmer présence et type du Secret
kubectl get secret ai-api -n demo -o jsonpath='{.type}{"\n"}'

# Comparer jeu de clés et hachages à la sauvegarde
kubectl get secret ai-api -n demo -o json \
 | jq -r '.data | to_entries[] | "\(.key) \(.value)"}' \
 | while read k v; do echo -n "$k " ; echo -n "$v" | base64 -d | sha256sum; done

# Pour TLS, décoder et vérifier CN et expiration (exemple construit)
kubectl get secret app-tls -n demo -o jsonpath='{.data.tls\.crt}' \
 | base64 -d > /tmp/tls.crt
openssl x509 -in /tmp/tls.crt -noout -subject -dates -fingerprint -sha256 
 Résultats attendus :

- Les types correspondent (Opaque vs kubernetes.io/tls)

- Les jeux de clés correspondent

- Les hachages correspondent aux valeurs précédentes (si inchangées)

- Le certificat TLS a le sujet attendu et des dates valides

### Vérifier que les charges de travail consomment les Secrets

# Pods montant les Secrets en volumes : vérifier que les fichiers existent et ont le contenu et permissions attendus
kubectl exec -n demo deploy/myapp -- sh -c 'ls -l /etc/secrets && head -c 16 /etc/secrets/some-key | wc -c'

# Pods utilisant des variables d'env depuis les Secrets : confirmer la présence de la valeur (éviter d'afficher les secrets). Utiliser des contrôles indirects ou endpoints de santé de l'application.

# Le statut du rollout est sain après les redémarrages
kubectl rollout status deploy/myapp -n demo --timeout=120s 

### Diagnostics pour problèmes courants

 # Problème de permission
kubectl auth can-i create secrets -n demo

# Incohérence de namespace
kubectl get secret ai-api -A | grep ai-api

# Mauvais contexte
kubectl config current-context

# Événements référençant les Secrets
kubectl get events -n demo --sort-by=.lastTimestamp | grep -i secret || true 

## Modes de défaillance et récupération

 Anticipez les façons dont les sauvegardes et restaurations de Secrets peuvent échouer, pour récupérer sans précipitation.

<div class="my-stack-md overflow-x-auto">
<table class="w-full min-w-[42rem] border-collapse text-left">
<thead><tr><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Mode de défaillance</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Symptôme</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Récupération</th></tr></thead>
<tbody><tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Namespace manquant</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl apply</code> échoue : namespace introuvable</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Créer le namespace, réappliquer.</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Secret immuable modifié</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">L&#39;application échoue ; le champ immuable empêche la mise à jour</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Supprimer le Secret, puis appliquer le nouveau manifest.</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Incohérence de type à la restauration</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">L&#39;application peut réussir, mais les charges de travail attendent un type spécifique</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">S&#39;assurer que <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">.type</code> correspond à l&#39;original ; supprimer-et-recréer si nécessaire.</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Données corrompues ou non-base64</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl apply</code> ou montage pod échoue</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Recréer le fichier depuis une sauvegarde saine connue ; vérifier base64 et clés.</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Export incomplet (métadonnées seulement)</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Le Secret existe mais manque de clés</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Réexporter en assurant la présence des clés <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">.data</code> ; vérifier avant restauration.</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Mauvais cluster/contexte</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Secrets restaurés sur cluster non intentionnel</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Vérifier le contexte <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl</code> avant apply ; étiqueter les sauvegardes avec l&#39;ID du cluster.</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Charges de travail ne rechargeant pas les variables d&#39;env</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">L&#39;application voit encore les anciennes valeurs</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Rollout restart des déploiements/statefulsets utilisant le Secret.</td></tr></tbody>
</table>
</div>
Risques supplémentaires et atténuations :

- Fuite de stockage : Les sauvegardes contiennent des données sensibles. Utilisez le chiffrement au repos et des permissions de fichier strictes.

- Sauvegardes trop larges : Commencez par un namespace pilote pour réduire le rayon d'impact, puis étendez progressivement.

- Dérive d'expiration TLS : À la restauration, confirmez la fenêtre de validité du certificat pour éviter des pannes immédiates.

### Scénarios de reprise d'activité

- Restaurer sur un nouveau cluster après perte

- Recréer les namespaces.

- Appliquer les manifests de Secrets (commencer par les dépendances critiques : Secrets de tirage d'images, identifiants d'app, certificats TLS).

- Restaurer les ConfigMaps et charges de travail.

- Déclencher les rollouts et vérifier la santé de bout en bout.

- Revenir à une version antérieure connue saine d'un Secret

- Identifier le fichier de sauvegarde horodaté.

- Si immuable : supprimer le Secret courant.

- Appliquer le manifest plus ancien.

- Redémarrer les charges de travail concernées (consommateurs de variables d'env) et vérifier.

Identifier les Secrets manquants en comparant l'inventaire des manifests au cluster vivant :

- Perte partielle d'un namespace

comm -23 <(ls backups/demo-20260101-000000 | sed 's/.yaml$//' | sort) <(kubectl get secrets -n demo -o jsonpath='{.items[*].metadata.name}' | tr ' ' '\n' | sort) 

- Appliquer uniquement les Secrets manquants.

## Liste de contrôle opérationnelle

 Utilisez ceci comme runbook répétable pour le pilote et la production.

Quotidien ou par changement (selon contexte) :

- Confirmer le contexte kubectl et le(s) namespace(s) cible(s).

- Exporter les Secrets modifiés avec métadonnées minimales.

- Chiffrer et stocker les sauvegardes avec permissions restreintes.

Hebdomadaire :

- Effectuer une restauration test dans un namespace non-production.

- Vérifier les hachages et, pour TLS, la validité des certificats.

- Confirmer que les charges de travail rechargent comme attendu (sémantiques volume vs variable d'env).

Mensuel ou trimestriel :

- Auditer le RBAC pour qui peut lire et sauvegarder les Secrets.

- Rotater les clés de chiffrement pour la sauvegarde au repos si la politique l'exige.

- Réviser l'inventaire et ajouter/retirer des Secrets du périmètre de sauvegarde.

Avant restauration en production :

- Valider que le namespace cible existe et est correct.

- Confirmer que le manifest correspond au .type et aux clés intentionnels.

- Pour les Secrets immuables, planifier la fenêtre delete-then-apply et le redémarrage des charges de travail.

Après restauration :

- Vérifier présence, type et hachages de données du Secret.

- Redémarrer les consommateurs de variables d'env et confirmer le succès du rollout.

- Contrôler les endpoints de santé et logs de l'application pour erreurs d'identifiants ou TLS.

- Documenter ce qui a été restauré, quand, et par qui.

## Exemples pratiques

### Exemple construit 1 : Sauvegarder et restaurer un Secret de clé API

- Créer et sauvegarder :

- Nom du Secret : ai-api , namespace : demo , type : Opaque

- Exporter le YAML minimal comme montré plus tôt vers ai-api.yaml

- Chiffrer vers ai-api.enc.yaml (optionnel)

- Restaurer :

- Déchiffrer si nécessaire : sops --decrypt ai-api.enc.yaml > /tmp/ai-api.yaml

- kubectl apply -f /tmp/ai-api.yaml

- Vérifier que le hachage correspond à la sauvegarde

- Redémarrer le déploiement l'utilisant : kubectl rollout restart deploy/myapp -n demo

### Exemple construit 2 : Sauvegarder et restaurer un Secret TLS

- Sauvegarder app-tls :

- Exporter le YAML minimal vers app-tls.yaml

- Optionnellement stocker le tls.crt décodé séparément pour vérifications openssl rapides (stocker en sécurité)

- Restaurer :

- kubectl apply -f app-tls.yaml

- Vérifier avec openssl x509 -noout -subject -dates -fingerprint -sha256

- Confirmer que l'ingress ou le service reprend des handshakes TLS sains

## Conclusion

Une procédure fiable de sauvegarde et restauration des Secrets Kubernetes est compacte, testable et observable. Commencez par un pilote étroit dans un namespace, exportez des manifests minimaux, chiffrez-les au repos, et entraînez-vous aux restaurations avec des étapes de vérification explicites. À mesure que vous dépassez le pilote, codifiez la liste de contrôle, étiquetez et versionnez vos sauvegardes, et répétez les scénarios de sinistre. Quand la restauration devient une opération claire et distincte avec vérification prévisible, vous réduisez le retravail et raccourcissez les temps de récupération. Votre prochaine étape : choisissez un namespace, sélectionnez deux Secrets, et lancez dès aujourd'hui un exercice complet sauvegarde-vérification-restauration de bout en bout.