Introduction
Les ressources Ingress de Kubernetes acheminent le trafic HTTP et HTTPS externe vers les services à l'intérieur de votre cluster. La classe Ingress (IngressClass) détermine quel contrôleur d'entrée traite un objet Ingress donné. Si elle n'est pas correctement sécurisée, la configuration de la classe Ingress peut devenir une voie d'attaque : un attaquant pourrait détourner le trafic ou contourner les contrôles d'accès. Le renforcement de la sécurité de la classe Ingress comble ces lacunes.
Cet article présente des étapes pratiques pour sécuriser les classes Ingress. Nous aborderons la compréhension des ressources IngressClass, l'application des contrôles d'accès, la gestion des secrets TLS, la restriction des autorisations avec le RBAC (Role-Based Access Control, contrôle d'accès basé sur les rôles), le contrôle de l'exposition réseau et la vérification de votre configuration. À la fin, vous disposerez d'une liste de contrôle réutilisable et de commandes concrètes à appliquer dans votre propre cluster.
Inventaire de version et d'environnement
Avant de procéder à des modifications, établissez ce avec quoi vous travaillez. Cet inventaire évite les surprises et vous aide à délimiter les changements en toute sécurité.
Prérequis
- Un cluster Kubernetes en cours d'exécution (version 1.19 ou ultérieure pour l'API stable IngressClass).
- kubectl configuré avec des autorisations pour afficher et modifier les objets Ingress, IngressClass, Secrets et RBAC.
- Un contrôleur d'entrée installé (par exemple, ingress-nginx, Traefik, HAProxy ou un contrôleur spécifique au cloud comme AWS ALB Ingress Controller).
- Un espace de noms de test pour une validation isolée (par exemple, ingress-test).
Vérifiez votre version de Kubernetes :
kubectl version --short
Exemple de sortie :
Client Version: v1.24.0
Server Version: v1.24.0
Exemple de topologie
Pour ce guide, nous supposons un cluster avec :
- Deux espaces de noms : prod et dev.
- Un contrôleur d'entrée déployé dans l'espace de noms ingress-nginx, avec une IngressClass par défaut nommée nginx.
- Un Ingress de test dans l'espace de noms dev utilisant la classe nginx.
Listez les IngressClasses existantes :
kubectl get ingressclass
Exemple de sortie :
NAME CONTROLLER PARAMETERS AGE
nginx k8s.io/ingress-nginx <none> 30d
Identifier la classe Ingress par défaut
La classe Ingress par défaut est utilisée lorsqu'un Ingress ne spécifie pas ingressClassName. Vérifiez l'annotation :
kubectl get ingressclass nginx -o yaml
Recherchez ingressclass.kubernetes.io/is-default-class: "true" dans les annotations.
Si aucune valeur par défaut n'est définie, un Ingress sans classe peut ne pas être traité. Décidez si vous avez besoin d'une classe par défaut ; si oui, désignez-en une explicitement.
Chemin de configuration sécurisé
Cette section fournit un processus de renforcement étape par étape. Commencez par un Ingress non critique et validez chaque changement avant de l'appliquer à grande échelle.
Étape 1 : Définir explicitement ingressClassName sur les ressources Ingress
S'appuyer sur la classe par défaut peut entraîner un mauvais routage si un attaquant crée un Ingress sans classe et capture le trafic. Exigez des noms de classe explicites.
Exemple de manifeste Ingress avec classe explicite :
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
namespace: dev
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80
Appliquez et vérifiez :
kubectl apply -f my-app-ingress.yaml
kubectl get ingress my-app-ingress -n dev -o yaml
Vérifiez que spec.ingressClassName est nginx.
Action : Appliquez cela via une politique d'admission ou simplement par convention. Pour une application plus stricte, utilisez un webhook d'admission comme OPA/Gatekeeper pour rejeter les Ingress sans ingressClassName.
Étape 2 : Restreindre qui peut créer ou modifier les ressources Ingress et IngressClass
Les ressources Ingress et IngressClass sont des ressources à l'échelle du cluster ou de l'espace de noms. Limitez l'accès en écriture aux utilisateurs ou comptes de service de confiance.
Créez un Role qui autorise uniquement l'accès en lecture aux Ingress dans un espace de noms :
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev
name: ingress-reader
rules:
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "watch"]
Liez-le à un groupe de développeurs :
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: dev-ingress-reader
namespace: dev
subjects:
- kind: Group
name: developers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: ingress-reader
apiGroup: rbac.authorization.k8s.io
Pour les ressources IngressClass à l'échelle du cluster, utilisez ClusterRole et ClusterRoleBinding uniquement pour les administrateurs.
Vérifiez les autorisations :
kubectl auth can-i create ingresses -n dev --as system:serviceaccount:dev:developer
Résultat attendu : non pour un compte restreint.
Étape 3 : Protéger les secrets TLS
Le TLS Ingress utilise des Secrets Kubernetes. La compromission de ces secrets permet l'usurpation d'identité de votre service.
- Stockez les certificats TLS en tant que Secrets de type kubernetes.io/tls.
- Limitez l'accès à ces Secrets à l'aide du RBAC.
- Envisagez une solution de gestion des secrets comme External Secrets Operator ou Sealed Secrets.
Exemple de Secret TLS :
apiVersion: v1
kind: Secret
metadata:
name: app-tls
namespace: dev
type: kubernetes.io/tls
data:
tls.crt: <base64 encoded cert>
tls.key: <base64 encoded key>
Restreignez l'accès avec un Role :
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev
name: tls-secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
resourceNames: ["app-tls"]
Seul le compte de service du contrôleur d'entrée doit avoir un accès en lecture aux secrets TLS. Pour ingress-nginx, le compte de service est généralement ingress-nginx dans l'espace de noms ingress-nginx.
Étape 4 : Isoler le contrôleur d'entrée et les espaces de noms
Exécutez votre contrôleur d'entrée dans un espace de noms dédié et restreignez la communication entre pods avec des Network Policies (politiques réseau).
Exemple de Network Policy pour autoriser uniquement le contrôleur d'entrée à accéder aux pods backend :
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-ingress
namespace: dev
spec:
podSelector:
matchLabels:
app: my-app
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
ports:
- port: 8080
Appliquez et testez la connectivité depuis un pod hors de l'espace de noms autorisé pour vérifier le refus.
Étape 5 : Renforcer la configuration du contrôleur d'entrée
Les contrôleurs d'entrée ont leurs propres paramètres de sécurité. Pour ingress-nginx, utilisez une ConfigMap pour définir les options :
apiVersion: v1
kind: ConfigMap
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
data:
enable-real-ip: "true"
use-forwarded-headers: "true"
ssl-protocols: "TLSv1.2 TLSv1.3"
ssl-ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256"
hsts: "true"
hsts-max-age: "31536000"
hsts-include-subdomains: "true"
Appliquez et rechargez le contrôleur :
kubectl apply -f configmap.yaml
kubectl rollout restart deployment ingress-nginx-controller -n ingress-nginx
Vérification et diagnostics
Après avoir mis en œuvre les étapes de renforcement, vérifiez que chaque contrôle fonctionne comme prévu.
1. Vérifier l'affectation de la classe Ingress
kubectl get ingress my-app-ingress -n dev -o jsonpath='{.spec.ingressClassName}'
Sortie attendue : nginx
2. Vérifier l'application du RBAC
Essayez de créer un Ingress en tant qu'utilisateur non autorisé :
kubectl auth can-i create ingresses -n dev --as system:serviceaccount:dev:developer
Résultat attendu : non
Si vous obtenez oui, examinez les RoleBindings.
3. Confirmer l'accès au secret TLS
Vérifiez les journaux du contrôleur d'entrée pour les erreurs de lecture de secret. Pour ingress-nginx :
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller | grep "app-tls"
Aucune erreur n'indique un accès réussi. En cas d'erreurs, vérifiez le RBAC pour le compte de service du contrôleur.
4. Tester la politique réseau
Depuis un pod dans un autre espace de noms, tentez d'atteindre le service backend :
kubectl run test-pod --rm -it --image=alpine --namespace=other-ns -- sh
wget -qO- http://my-app-service.dev.svc.cluster.local:8080
Résultat attendu : délai de connexion ou refus.
5. Valider la configuration TLS
Utilisez openssl pour vérifier les protocoles et suites de chiffrement TLS :
echo | openssl s_client -connect app.example.com:443 -tls1_2 2>/dev/null | grep "Protocol"
Résultat attendu : TLSv1.2 ou TLSv1.3 (si TLS 1.3 négocié).
Pièges courants et comment les éviter
Même les administrateurs Kubernetes expérimentés commettent des erreurs lors du renforcement des classes Ingress. Voici les pièges les plus courants et des moyens pratiques de les prévenir ou de s'en remettre.
Piège 1 : Oublier de définir ingressClassName sur les nouveaux Ingress
Pourquoi cela arrive : Les équipes s'appuient souvent sur une IngressClass par défaut et omettent le champ dans les nouveaux manifestes. Si la classe par défaut change ou est supprimée, le trafic s'arrête ou est mal acheminé.
Comment éviter : Appliquez explicitement ingressClassName via les pipelines CI/CD ou les politiques d'admission. Utilisez une contrainte OPA/Gatekeeper comme celle-ci :
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequireIngressClass
metadata:
name: require-ingress-class
spec:
match:
kinds:
- apiGroups: ["networking.k8s.io"]
kinds: ["Ingress"]
parameters:
message: "Ingress must have spec.ingressClassName set"
Récupération : Si un Ingress manque la classe, corrigez-le immédiatement :
kubectl patch ingress my-app-ingress -n dev --type='merge' -p '{"spec":{"ingressClassName":"nginx"}}'
Piège 2 : RBAC trop large pour les ressources Ingress
Pourquoi cela arrive : Les développeurs se voient souvent accorder cluster-admin ou des autorisations larges par commodité. Cela permet à n'importe quel utilisateur de créer ou modifier des Ingress, potentiellement en détournant le trafic.
Comment éviter : Implémentez un RBAC à moindre privilège. Utilisez des Roles d'espace de noms pour les autorisations Ingress et réservez les ClusterRoles pour la gestion des IngressClass. Auditez régulièrement avec des outils comme kubectl-who-can ou rakkess.
Récupération : Si vous découvrez des autorisations excessives, révoquez-les immédiatement :
kubectl delete clusterrolebinding overly-broad-binding
kubectl create rolebinding restricted-binding --role=ingress-reader --group=developers -n dev
Piège 3 : Secrets TLS accessibles à trop de principaux
Pourquoi cela arrive : Les autorisations d'espace de noms par défaut ou les liaisons de commodité peuvent permettre à tous les utilisateurs authentifiés de lire les secrets. Un pod ou un utilisateur compromis peut alors voler les certificats TLS.
Comment éviter : Limitez l'accès aux secrets au seul compte de service du contrôleur d'entrée. Utilisez un espace de noms dédié pour les secrets TLS et appliquez un RBAC limité aux noms de secrets spécifiques, comme indiqué à l'étape 3.
Récupération : Si un secret a été exposé, faites pivoter le certificat immédiatement et mettez à jour le secret :
kubectl create secret tls app-tls --cert=new-cert.pem --key=new-key.pem -n dev --dry-run=client -o yaml | kubectl apply -f -
Redémarrez ensuite le contrôleur d'entrée pour prendre en compte le nouveau secret.
Piège 4 : Politiques réseau mal configurées qui bloquent le trafic légitime
Pourquoi cela arrive : Les politiques réseau sont souvent écrites de manière trop restrictive, bloquant involontairement les contrôles de santé ou la communication inter-espaces de noms nécessaire au contrôleur d'entrée.
Comment éviter : Testez les politiques réseau dans un environnement de préproduction d'abord. Utilisez des outils comme kubectl netpol ou cyclonus pour valider la logique de la politique avant le déploiement.
Récupération : Supprimez temporairement la politique pour rétablir le trafic, puis corrigez les sélecteurs :
kubectl delete networkpolicy allow-from-ingress -n dev
# Modifiez le YAML de la politique pour corriger podSelector ou namespaceSelector
kubectl apply -f corrected-policy.yaml
Piège 5 : Exécuter un contrôleur d'entrée obsolète avec des vulnérabilités connues
Pourquoi cela arrive : Les équipes oublient souvent de mettre à jour le contrôleur d'entrée parce qu'il fonctionne en arrière-plan et « fonctionne simplement ».
Comment éviter : Abonnez-vous aux avis de sécurité de votre contrôleur et définissez une cadence de mise à niveau trimestrielle. Utilisez l'analyse d'images automatisée (par exemple, Trivy, Clair) dans votre pipeline CI/CD.
Récupération : Si une vulnérabilité est découverte, mettez à niveau rapidement :
kubectl set image deployment/ingress-nginx-controller -n ingress-nginx controller=k8s.gcr.io/ingress-nginx/controller:v1.8.1
Vérifiez ensuite le déploiement et testez la fonctionnalité d'entrée.
Modes de défaillance et récupération
Même avec une planification minutieuse, des problèmes peuvent survenir. Comprenez les modes de défaillance potentiels et comment s'en remettre.
Défaillance : L'Ingress cesse de fonctionner après l'ajout d'ingressClassName
Risque : Si le nom de la classe Ingress est incorrect ou si le contrôleur ne prend pas en charge la classe, le trafic s'arrête.
Récupération :
- Vérifiez les événements Ingress :
kubectl describe ingress my-app-ingress -n dev
Recherchez des événements comme Ingress class not found.
- Revenez en arrière en supprimant le champ ingressClassName ou en le corrigeant :
kubectl patch ingress my-app-ingress -n dev --type='json' -p='[{"op": "remove", "path": "/spec/ingressClassName"}]'
- Vérifiez que le trafic reprend.
Défaillance : Certificat TLS introuvable
Risque : Un secret mal nommé ou un mauvais espace de noms provoque un échec HTTPS.
Récupération :
- Vérifiez la spécification TLS de l'Ingress :
kubectl get ingress my-app-ingress -n dev -o yaml | grep -A5 tls
- Vérifiez que le secret existe et son type :
kubectl get secret app-tls -n dev
- S'il manque, recréez le secret ou ajustez l'Ingress pour référencer le bon secret.
Défaillance : La politique réseau bloque le trafic légitime
Risque : Une politique réseau trop restrictive peut bloquer le trafic prévu.
Récupération :
- Supprimez temporairement la politique réseau :
kubectl delete networkpolicy allow-from-ingress -n dev
- Testez la connectivité.
- Recréez avec des sélecteurs et des règles corrigés.
Défaillance : RBAC trop restrictif bloque le contrôleur
Risque : Le compte de service du contrôleur d'entrée n'a pas les autorisations pour lire les Ingresses, Secrets ou Services.
Récupération :
Vérifiez les journaux du pod du contrôleur pour les erreurs d'autorisation :
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller | grep "forbidden"
En cas d'erreurs, examinez et mettez à jour les liaisons ClusterRole/Role pour le compte de service du contrôleur.
Stratégie de retour en arrière
Conservez toujours des sauvegardes des manifestes originaux avant les modifications. Utilisez le contrôle de version (Git) pour tous les objets Kubernetes. Pour revenir en arrière, appliquez la version précédente du manifeste.
Liste de contrôle opérationnelle
Utilisez cette liste de contrôle pour la maintenance continue de la sécurité. Attribuez un propriétaire unique pour chaque élément et une fréquence de révision.
| Élément | Propriétaire | Fréquence | Commande/Outil |
|---|---|---|---|
| Lister toutes les IngressClasses et s'assurer que seules celles attendues existent | Ingénieur plateforme | Mensuel | kubectl get ingressclass |
| Réviser le RBAC pour les ressources Ingress et IngressClass | Responsable sécurité | Mensuel | kubectl get roles, clusterroles --all-namespaces -o yaml | grep -B5 -A10 "ingress" |
| Auditer les secrets TLS et leurs accès | Responsable sécurité | Mensuel | kubectl get secrets --all-namespaces --field-selector type=kubernetes.io/tls |
| Vérifier les Ingress sans ingressClassName | Ingénieur plateforme | Hebdomadaire | kubectl get ingress --all-namespaces -o json | jq '.items[] | select(.spec.ingressClassName == null) | .metadata.name' |
| Valider que les politiques réseau autorisent toujours le trafic requis | Administrateur réseau | Après modifications | kubectl get networkpolicy --all-namespaces |
| Examiner les journaux du contrôleur d'entrée pour les événements de sécurité | Analyste sécurité | Hebdomadaire | kubectl logs -n ingress-nginx deployment/ingress-nginx-controller --tail=100 |
| Tester HTTPS avec openssl ou testssl.sh | Analyste sécurité | Mensuel | openssl s_client -connect your-domain.com:443 |
| Mettre à jour le contrôleur d'entrée vers la dernière version stable | Ingénieur plateforme | Trimestriel | Consultez la doc du contrôleur |
Conclusion
La sécurisation des classes Ingress de Kubernetes est essentielle pour protéger vos applications contre l'interception de trafic et les accès non autorisés. En suivant ce guide, vous avez :
- Inventorié les IngressClasses et la topologie de votre cluster.
- Défini explicitement les noms de classe Ingress sur les ressources Ingress.
- Restreint les autorisations RBAC pour les Ingress et les secrets.
- Protégé les secrets TLS.
- Isolé le contrôleur d'entrée avec des politiques réseau.
- Renforcé la configuration du contrôleur d'entrée.
- Vérifié chaque contrôle avec des vérifications observables.
- Préparé des étapes de récupération pour les défaillances courantes.
Prochaines étapes : appliquez ces mesures de renforcement dans un espace de noms de test, validez avec les commandes de vérification, puis déployez progressivement en production. Conservez la liste de contrôle opérationnelle comme tâche de révision récurrente. La surveillance continue et les audits périodiques maintiendront votre configuration Ingress sécurisée à mesure que votre cluster évolue.
Rappelez-vous : la sécurité n'est pas une tâche ponctuelle mais une pratique continue.