## Intro

Les Secrets Kubernetes stockent identifiants, jetons, clés d'API et autres configurations sensibles. Traitez-les comme des joyaux de la couronne. Ce guide montre comment durcir les Secrets dans de vrais clusters avec des exemples YAML et des commandes kubectl pratiques. Vous apprendrez à :

- Inventorier et classifier les Secrets selon leur sensibilité et leur propriétaire

- Activer le chiffrement au repos pour les Secrets dans le magasin de données de l' API server (serveur d'API)

- Appliquer le principe du moindre privilège avec RBAC (Role‑Based Access Control) : contrôle d'accès basé sur les rôles, et des comptes de service dédiés par charge de travail

- Consommer les Secrets via des montages de fichiers en lecture seule au lieu de variables d'environnement

- Ajouter des politiques réseau default‑deny au niveau de l'espace de noms avec des autorisations explicites

- Exécuter des vérifications rapides, à faible risque, pour valider le durcissement

## Workflow Overview

Appliquez les étapes espace de noms par espace de noms :

- Inventorier et classifier

- Chiffrer au repos

- Verrouiller RBAC et comptes de service

- Utiliser les Secrets en toute sécurité dans les pods

- Contenir l'exposition réseau

- Ajouter des contrôles et de la rotation

### 1) Inventorier et classifier les Secrets

Listez tous les Secrets et identifiez les propriétaires :

kubectl get secrets -A -o wide 
 Ajoutez des étiquettes cohérentes pour faciliter les requêtes :

kubectl label secret db-credentials owner=payments purpose=database -n team-apps --overwrite 
 Créez un nouveau Secret avec un nommage clair et une portée définie :

kubectl create secret generic db-credentials \
 --from-literal=username=app \
 --from-literal=password='S3cr3t!' \
 -n team-apps 
 Conseil : préférez un Secret par application ou composant plutôt que des Secrets partagés entre plusieurs applications. Cela limite le rayon d'impact et simplifie le RBAC .

### 2) Chiffrer les Secrets au repos

Les Secrets résident dans le magasin de données de l' API server (Application Programming Interface server : serveur d'interface de programmation d'applications). Activez le chiffrement pour qu'ils soient chiffrés sur disque.

Exemple de EncryptionConfiguration (fournisseur aescbc) :

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
 - secrets
 providers:
 - aescbc:
 keys:
 - name: key1
 secret: <clé-32-octets-encodée-en-base64>
 - identity: {} 
 Étapes de haut niveau :

- Placez le fichier sur chaque nœud control‑plane.

- Démarrez l' API server avec --encryption-provider-config=/chemin/vers/config.yaml .

- Redémarrez l' API server et lancez kubectl get secrets --all-namespaces -o json | kubectl replace -f - pour rechiffrer les données existantes.

Dans les clusters gérés, activez le paramètre « Secrets encryption » fourni par la plateforme.

### 3) Verrouiller RBAC et comptes de service

Accordez l'accès en lecture uniquement aux charges de travail qui ont besoin d'un Secret spécifique.

Compte de service qui ne monte pas le jeton par défaut :

apiVersion: v1
kind: ServiceAccount
metadata:
 name: web-sa
 namespace: team-apps
automountServiceAccountToken: false 
 Rôle autorisant get sur un seul Secret :

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
 name: read-db-credentials
 namespace: team-apps
rules:
- apiGroups: ["
 resources: ["secrets
d resourceNames: ["db-credentials
d verbs: ["get 
 RoleBinding :

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
 name: bind-read-db-credentials
 namespace: team-apps
subjects:
- kind: ServiceAccount
 name: web-sa
 namespace: team-apps
roleRef:
 kind: Role
 name: read-db-credentials
 apiGroup: rbac.authorization.k8s.io 
 Testez :

kubectl auth can-i get secret db-credentials \
 --as=system:serviceaccount:team-apps:web-sa \
 -n team-apps 

### 4) Utiliser les Secrets en toute sécurité dans les pods

 Montez les Secrets comme des fichiers en lecture seule ; évitez les variables d'environnement qui peuvent fuiter dans les logs et /proc .

Extrait de spécification de pod (Deployment) :

apiVersion: apps/v1
kind: Deployment
metadata:
 name: web
 namespace: team-apps
spec:
 replicas: 1
 selector:
 matchLabels:
 app: web
 template:
 metadata:
 labels:
 app: web
 spec:
 serviceAccountName: web-sa
 automountServiceAccountToken: false
 containers:
 - name: app
 image: your-registry/web:1.0.0
 volumeMounts:
 - name: db-secret
 mountPath: /var/run/secrets/app
 readOnly: true
 env:
 - name: DB_USER_FILE
 value: /var/run/secrets/app/username
 - name: DB_PASS_FILE
 value: /var/run/secrets/app/password
 volumes:
 - name: db-secret
 secret:
 secretName: db-credentials 
 L'application lit les fichiers au démarrage ( cat $DB_USER_FILE ). Si les variables d'environnement sont inévitables, limitez-les aux conteneurs strictement nécessaires et n'utilise jamais envFrom avec un Secret entier.

Rendez les Secrets immuables pour empêcher les modifications accidentelles :

apiVersion: v1
kind: Secret
metadata:
 name: db-credentials
 namespace: team-apps
type: Opaque
immutable: true
data:
 username: YXBw
 password: UzNjcjN0IQ== 
 La rotation se fait en créant db-credentials-v2 , en mettant à jour le Deployment pour le référencer, en déployant le roulement, puis en supprimant l'ancien Secret après validation.

### 5) Contenir l'exposition réseau

Les politiques réseau ne protègent pas directement les Secrets, mais elles limitent les déplacements latéraux.

Refus par défaut de tout trafic entrant et sortant :

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
 name: default-deny-all
 namespace: team-apps
spec:
 podSelector: {}
 policyTypes: [Ingress, Egress] 
 Autorisez le trafic DNS sortant (adaptez les sélecteurs à votre cluster) :

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
 name: allow-dns-egress
 namespace: team-apps
spec:
 podSelector: {}
 policyTypes: [Egress]
 egress:
 - to:
 - namespaceSelector:
 matchLabels:
 kubernetes.io/metadata.name: kube-system
 podSelector:
 matchLabels:
 k8s-app: kube-dns
 ports:
 - protocol: UDP
 port: 53
 - protocol: TCP
 port: 53 
 Ajoutez des politiques d'autorisation explicites pour chaque dépendance requise.

### 6) Ajouter des vérifications et audits rapides

Exécutez ces contrôles légers régulièrement.

Qui peut lire quels Secrets

kubectl auth can-i --list \
 --as=system:serviceaccount:team-apps:web-sa \
 -n team-apps | grep secrets || true 
 Pods qui référencent des Secrets via des variables d'environnement (nécessite jq ) :

kubectl get pods -A -o json | jq -r '
 .items[]
 | select((.spec.containers // [])
 | map(.env // [] | map(has("valueFrom
) and .valueFrom.secretKeyRef != null) | any) | any)
 | [.metadata.namespace, .metadata.name] | @tsv' 
 Secrets non immuables :

kubectl get secrets -A -o json | jq -r '
 .items[] | select(.immutable != true) | [.metadata.namespace, .metadata.name] | @tsv' 
 Rôles/ClusterRoles à portée large pouvant lire de nombreux Secrets :

kubectl get role,clusterrole -A -o yaml | grep -n "resources: \[secrets\]" || true 
 Confirmer le chiffrement au repos – inspectez le drapeau --encryption-provider-config de l' API server sur les nœuds control‑plane ou le réglage du service géré.

## Local Pilot Plan

Commencez petit, mesurez, puis étendez.

Périmètre

- Espace de noms : team-apps

- Charge de travail : un seul Deployment web qui a besoin de db-credentials

Critères de succès

- Seul web-sa peut get le Secret db-credentials dans team-apps

- Aucun pod dans team-apps ne consomme de Secrets via des variables d'environnement

- L'espace de noms possède une politique réseau default‑deny avec des autorisations explicites

Étapes

- Créer l'espace de noms et le compte de service

kubectl create namespace team-apps
 kubectl apply -f - <<'EOF'
 apiVersion: v1
 kind: ServiceAccount
 metadata:
 name: web-sa
 namespace: team-apps
 automountServiceAccountToken: false
 EOF 

- Créer le Secret

 kubectl create secret generic db-credentials \
 --from-literal=username=app \
 --from-literal=password='S3cr3t!' \
 -n team-apps 

- Appliquer le RBAC au moindre privilège

 kubectl apply -f - <<'EOF'
 apiVersion: rbac.authorization.k8s.io/v1
 kind: Role
 metadata:
 name: read-db-credentials
 namespace: team-apps
 rules:
 - apiGroups: ["
 resources: ["secrets
d resourceNames: ["db-credentials
d verbs: ["get
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: RoleBinding
 metadata:
 name: bind-read-db-credentials
 namespace: team-apps
 subjects:
 - kind: ServiceAccount
 name: web-sa
 namespace: team-apps
 roleRef:
 kind: Role
 name: read-db-credentials
 apiGroup: rbac.authorization.k8s.io
 EOF
 kubectl auth can-i get secret db-credentials \
 --as=system:serviceaccount:team-apps:web-sa \
 -n team-apps 

- Déployer l'application avec montage de Secrets en fichiers

 kubectl apply -f - <<'EOF'
 apiVersion: apps/v1
 kind: Deployment
 metadata:
 name: web
 namespace: team-apps
 spec:
 replicas: 1
 selector:
 matchLabels:
 app: web
 template:
 metadata:
 labels:
 app: web
 spec:
 serviceAccountName: web-sa
 automountServiceAccountToken: false
 containers:
 - name: app
 image: your-registry/web:1.0.0
 volumeMounts:
 - name: db-secret
 mountPath: /var/run/secrets/app
 readOnly: true
 env:
 - name: DB_USER_FILE
 value: /var/run/secrets/app/username
 - name: DB_PASS_FILE
 value: /var/run/secrets/app/password
 volumes:
 - name: db-secret
 secret:
 secretName: db-credentials
 EOF 

- Appliquer default‑deny et autoriser DNS

 kubectl apply -f - <<'EOF'
 apiVersion: networking.k8s.io/v1
 kind: NetworkPolicy
 metadata:
 name: default-deny-all
 namespace: team-apps
 spec:
 podSelector: {}
 policyTypes: [Ingress, Egress]
 ---
 apiVersion: networking.k8s.io/v1
 kind: NetworkPolicy
 metadata:
 name: allow-dns-egress
 namespace: team-apps
 spec:
 podSelector: {}
 policyTypes: [Egress]
 egress:
 - to:
 - namespaceSelector:
 matchLabels:
 kubernetes.io/metadata.name: kube-system
 podSelector:
 matchLabels:
 k8s-app: kube-dns
 ports:
 - protocol: UDP
 port: 53
 - protocol: TCP
 port: 53
 EOF 

- Valider

 # Seul web-sa peut lire db-credentials
 kubectl auth can-i get secret db-credentials \
 --as=system:serviceaccount:team-apps:web-sa \
 -n team-apps

 # Le SA par défaut ne doit pas pouvoir
 kubectl auth can-i get secret db-credentials \
 --as=system:serviceaccount:team-apps:default \
 -n team-apps

 # Aucun pod ne consomme de Secrets via des variables d'env
 kubectl get pods -n team-apps -o json | jq -r '
 .items[]
 | select((.spec.containers // [])
 | map(.env // [] | map(has("valueFrom
d) and .valueFrom.secretKeyRef != null) | any) | any)
 | .metadata.name' | wc -l

 # Les politiques réseau existent
 kubectl get networkpolicy -n team-apps 

- Documenter la rotation de db-credentials

- Créer db-credentials-v2

- Mettre à jour le Deployment pour référencer db-credentials-v2

- Déployer le roulement et vérifier

- Supprimer db-credentials après validation

 Plan de retour arrière

- Conservez l'ancien Secret jusqu'à la fin de la validation.

- En cas d'échec du déploiement, rétablissez la référence au Secret précédent dans le Deployment et relancez les tests.

## Conclusion

Vous disposez maintenant d'un chemin pratique pour durcir les Secrets Kubernetes : inventorier, chiffrer au repos, appliquer le moindre privilège, garder les Secrets hors des variables d'environnement, restreindre l'exposition réseau et vérifier avec des contrôles reproductibles. Lancez un pilote dans un espace de noms, mesurez les résultats, puis étendez progressivement.

Suivez quelques indicateurs clés au fur et à mesure de l'expansion :

- Nombre de Secrets par espace de noms et présence d'étiquettes propriétaire

- Rôles pouvant lire des Secrets arbitraires vs Rôles limités à des noms précis

- Pods consommant des Secrets via variables d'environnement vs montages de fichiers

- Espaces de noms couverts par des politiques réseau default‑deny

Une approche par étapes garde les changements sûrs et observables tout en améliorant votre posture de sécurité pas à pas.