E-NO
Kubernetes 13 min de lecture

Renforcement de la sécurité Kubernetes Ingress avec des exemples pratiques : guide d'implémentation

calendar_today Publié : 2026-07-31
update Dernière mise à jour : 2026-07-31
analytics Efficacité SEO : 97%
Illustration du guide technique pour « Renforcement de la sécurité Kubernetes Ingress avec des exemples pratiques : guide d'implémentation ».

Introduction

Ingress expose vos applications au monde extérieur. Une petite erreur de configuration peut divulguer des en-têtes, accepter des chiffrements faibles, contourner une authentification, ou surexposer des chemins réseau. Ce guide explique comment durcir la sécurité de Kubernetes Ingress avec des étapes pratiques, vérifiables, et des procédures de retour arrière claires. Vous allez :

  • Réaliser un inventaire des versions et des points d'exposition pour des changements compatibles et testables.
  • Appliquer un chemin de configuration sûr et limité pour TLS, mTLS, listes d'IP autorisées, limitation de débit, secrets, RBAC, NetworkPolicy et contrôles du load balancer.
  • Vérifier les protections avec des commandes concrètes et des résultats attendus.
  • Reconnaître les modes de panne et rétablir rapidement.
  • Maintenir une checklist opérationnelle exécutable régulièrement.

Les exemples sont signalés comme « exemple construit ». Adaptez noms, espaces de noms et limites à votre environnement.

Inventaire des versions et de l'environnement

Avant toute modification, consignez ce que vous allez durcir. Des versions dépareillées ou une topologie ambiguë causent l'essentiel des mauvaises surprises.

Prérequis :

  • Vous disposez de droits d'admin cluster ou délégués pour créer/modifier Ingress, Secrets, RBAC et NetworkPolicy dans les espaces de noms cibles.
  • Vous connaissez le contrôleur Ingress utilisé (par exemple NGINX Ingress Controller) et son namespace.
  • Vous contrôlez ou pouvez mettre à jour le DNS des noms d'hôtes.
  • Vous avez ou pouvez émettre des certificats TLS valides pour vos domaines.

Inventaire (exemple construit) :

ÉlémentValeur d'exemplePourquoi c'est important
Version Kubernetes1.28 (exemple construit)Détermine les API disponibles (ex. ValidatingAdmissionPolicy).
Contrôleur Ingressingress-nginx 1.9.x (exemple construit)Définit les annotations et clés de ConfigMap supportées.
IngressClasspublic-nginx (exemple construit)Un lien explicite évite un routage par défaut accidentel.
Zone DNSexample.test (exemple construit)Contrôle le routage host et les SAN TLS.
Load balancerL4 cloud avec source ranges (exemple construit)Permet de restreindre les IP entrantes en bordure.
Source TLSAC interne et AC publique (exemple construit)Choisit les racines mTLS et les certifs serveur.

Commandes pour capturer l'état courant :

kubectl get ns
kubectl get deploy, ds, svc, cm -n ingress-nginx
kubectl get ingressclass
kubectl get ingress -A -o wide
kubectl version --short

Chemin de configuration sûr

Commencez par une cible étroite et à forte valeur que vous pouvez tester et rétablir facilement (par exemple un seul hostname). Puis étendez progressivement.

1) Lier à un IngressClass explicite

Assurez-vous que chaque ressource Ingress cible un contrôleur connu. Cela empêche des valeurs par défaut inconnues de capter le trafic.

IngressClass (exemple construit) :

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: public-nginx
spec:
  controller: k8s.io/ingress-nginx

2) Imposer TLS et des valeurs sûres par défaut

Utilisez un Secret TLS Kubernetes, redirigez HTTP vers HTTPS et activez HSTS. L'exemple suivant montre des annotations sûres pour NGINX Ingress Controller.

Création d'un secret TLS (exemple construit) :

kubectl create secret tls web-tls \
  --namespace app \
  --key server.key \
  --cert server.crt

Ingress avec annotations sécurisées (exemple construit) :

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
  namespace: app
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/ssl-protocols: "TLSv1.2 TLSv1.3"
    nginx.ingress.kubernetes.io/hsts: "true"
    nginx.ingress.kubernetes.io/hsts-max-age: "63072000"
    nginx.ingress.kubernetes.io/hsts-include-subdomains: "true"
    nginx.ingress.kubernetes.io/hsts-preload: "true"
    nginx.ingress.kubernetes.io/server-tokens: "false"
    nginx.ingress.kubernetes.io/proxy-body-size: "1m"
    # Optionnel : affinez les chiffrements si votre parc client est maîtrisé
    # nginx.ingress.kubernetes.io/ssl-ciphers: "ECDHE-ECDSA-AES256-GCM-SHA384: ECDHE-RSA-AES256-GCM-SHA384: TLS_AES_256_GCM_SHA384: TLS_AES_128_GCM_SHA256"
  labels:
    security-tier: hardened
spec:
  ingressClassName: public-nginx
  tls:
  - hosts:
    - app.example.test
    secretName: web-tls
  rules:
  - host: app.example.test
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-svc
            port:
              number: 80

Valeurs par défaut au niveau du contrôleur via ConfigMap (exemple construit) :

apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
data:
  server-tokens: "false"
  ssl-protocols: "TLSv1.2 TLSv1.3"
  # Gardez une liste de chiffrements concise ; évitez les suites obsolètes
  # ssl-ciphers: "TLS_AES_256_GCM_SHA384: TLS_AES_128_GCM_SHA256"

3) Ajouter l'authentification par certificat client (mTLS) quand c'est pertinent

Pour des portails d'admin ou des API internes, exigez un certificat client pour atteindre l'app. Stockez le bundle CA dans un Secret. Exemple (exemple construit) :

kubectl -n app create secret generic client-ca --from-file=ca.crt=ca.pem
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: admin
  namespace: app
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/auth-tls-secret: "app/client-ca"
    nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
    nginx.ingress.kubernetes.io/auth-tls-verify-depth: "1"
    nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "true"
    nginx.ingress.kubernetes.io/whitelist-source-range: "203.0.113.0/24,198.51.100.0/24"
  labels:
    security-tier: hardened
spec:
  ingressClassName: public-nginx
  tls:
  - hosts: ["admin.example.test"]
    secretName: web-tls
  rules:
  - host: admin.example.test
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: admin-svc
            port:
              number: 8443

4) Ajouter des allow-lists IP et de la limitation de débit

Restreignez les sources de trafic et limitez les abus.

Annotations (exemple construit) :

metadata:
  annotations:
    nginx.ingress.kubernetes.io/whitelist-source-range: "203.0.113.0/24,198.51.100.0/24"
    nginx.ingress.kubernetes.io/limit-rps: "10"
    nginx.ingress.kubernetes.io/limit-burst: "20"

Assurez la préservation de l'IP cliente au niveau du Service du contrôleur, afin que les allow-lists et le rate limiting évaluent les adresses réelles :

apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local
  loadBalancerSourceRanges:
  - 0.0.0.0/0   # resserrez pour les endpoints admin, ex. CIDR corporate

5) Sécuriser les Secrets et limiter les permissions

  • Conservez les secrets TLS dans le même namespace que l'Ingress qui les consomme.
  • Restreignez qui peut créer/modifier Ingress et Secrets.

RBAC limitant les changements d'Ingress à un groupe dans le namespace app (exemple construit) :

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: ingress-maintainer
  namespace: app
rules:
- apiGroups: ["networking.k8s.io"]
  resources: ["ingresses"]
  verbs: ["get","list","watch","create","update","patch"]
- apiGroups: [""]
  resources: ["secrets"]
  resourceNames: ["web-tls", "client-ca"]
  verbs: ["get","list","watch","update","patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ingress-maintainer-binding
  namespace: app
subjects:
- kind: Group
  name: app-team   # identité d'exemple
roleRef:
  kind: Role
  name: ingress-maintainer
  apiGroup: rbac.authorization.k8s.io

Contrôle d'admission imposant TLS et un IngressClass spécifique (exemple construit) :

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: enforce-ingress-tls-and-class
spec:
  matchConstraints:
    resourceRules:
    - apiGroups: ["networking.k8s.io"]
      apiVersions: ["v1"]
      operations: ["CREATE","UPDATE"]
      resources: ["ingresses"]
  validations:
  - expression: "has(object.spec.tls) && size(object.spec.tls) > 0"
    message: "Ingress must configure TLS."
  - expression: "object.spec.ingressClassName == 'public-nginx'"
    message: "Ingress must target approved ingressClassName."
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: enforce-ingress-tls-and-class-binding
spec:
  policyName: enforce-ingress-tls-and-class
  validationActions: ["Deny"]

6) Contraindre les chemins réseau

Assurez-vous que le contrôleur n'atteint que les backends nécessaires et que les pairs ne peuvent pas joindre le contrôleur de manière inattendue.

NetworkPolicy autorisant uniquement le contrôleur Ingress à appeler votre service (exemple construit) :

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-only-ingress
  namespace: app
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes: ["Ingress"]
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: ingress-nginx
      podSelector:
        matchLabels:
          app.kubernetes.io/name: ingress-nginx
    ports:
    - protocol: TCP
      port: 80

Vérifications et diagnostics

Effectuez ces contrôles après chaque changement. Validez d'abord sur un seul hostname.

Référence rapide (résultats d'exemple construits) :

VérificationCommandeAttendu
Ingress admiskubectl describe ingress -n app webIngressClass public-nginx ; règles et TLS renseignés.
Adresse allouéekubectl get ingress -n app web -o wideADDRESS renseignée avec IP/hostname du LB.
HTTP → HTTPScurl -I http://app.example.test301/308 avec Location: https://app.example.test/
Version TLS minopenssl s_client -connect app.example.test:443 -tls1_0Échec du handshake ; OK en TLSv1.2.
HSTS présentcurl -I https://app.example.testEn-tête Strict-Transport-Security présent.
mTLS appliquécurl -I https://admin.example.test400/401/403 sans cert client ; 200 avec cert.
Limitation de débitboucle curlCertains 429 sous forte pression RPS.

Détails :

  1. Admission et IngressClass
kubectl describe ingress -n app web

Attendu : annotations visibles, IngressClassName: public-nginx, pas de Deny dans Events.

  1. Redirection TLS et en-têtes
curl -I http://app.example.test
curl -I https://app.example.test

Attendu : HTTP renvoie 301/308 vers https. HTTPS renvoie 200 avec Strict-Transport-Security. Pas de fuite de version du serveur si server-tokens=false.

  1. Plancher de protocole (TLSv1.2+)
# Échec attendu avec protocoles obsolètes
openssl s_client -connect app.example.test:443 -tls1_0 </dev/null

# Succès attendu avec TLSv1.2
openssl s_client -connect app.example.test:443 -tls1_2 </dev/null | grep -i "protocol\|cipher"

Attendu : TLS 1.0 échoue ; TLS 1.2 réussit avec un chiffrement moderne.

  1. Application du mTLS

Sans certificat client :

curl -I https://admin.example.test

Attendu : 400/401/403 selon la configuration.

Avec certificat client (fichiers d'exemple construits) :

curl -I https://admin.example.test \
  --cert client.crt --key client.key

Attendu : 200 avec en-têtes de l'upstream.

  1. Rate limiting et allow-lists

Depuis un réseau autorisé, envoyez une rafale :

for i in {1..50}; do curl -s -o /dev/null -w "%{http_code}\n" https://app.example.test; done | sort | uniq -c

Attendu : 200 et possiblement 429 selon RPS et burst.

Depuis un réseau bloqué (ou en resserrant temporairement la whitelist), attendez-vous à 403.

  1. Logs du contrôleur et des requêtes
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller | tail -n 50

Recherchez des messages de handshake TLS, des notifications de rate limiting ou des échecs de certificat client. Des erreurs récurrentes indiquent une mauvaise configuration.

  1. Vérifications NetworkPolicy

Depuis un autre namespace, tentez d'atteindre le pod du service. Avec un pod de test temporaire, l'accès doit échouer si la policy est en place (exemple construit) :

kubectl run -n default tmp --image=alpine --restart=Never --rm -it -- sh -c "apk add --no-cache curl >/dev/null && curl -Is http://web.app.svc.cluster.local:80 || true"

Attendu : délai d'attente ou refus de connexion lorsque la policy bloque le trafic.

Modes de panne et reprise

Ce qui casse souvent et comment rétablir rapidement.

  1. Problèmes de secret TLS
  • Symptôme : erreurs TLS côté edge ou logs du contrôleur sans certificat valide.
  • Vérif : le type du secret est kubernetes.io/tls et correspond à tls.secretName de l'Ingress.
  • Correctif :
kubectl -n app get secret web-tls -o yaml | grep type
kubectl -n app delete secret web-tls
kubectl -n app create secret tls web-tls --key server.key --cert server.crt
kubectl -n app rollout restart deploy/ingress-nginx-controller # si nécessaire
  1. HTTP ne redirige pas vers HTTPS
  • Symptôme : HTTP 200 sur le port 80.
  • Vérif : annotation ssl-redirect="true" au niveau Ingress ou contrôleur.
  • Correctif : ajoutez l'annotation et réappliquez. Vérifiez avec curl -I.
  1. TLS 1.0/1.1 toujours acceptés
  • Symptôme : openssl -tls1_0 réussit.
  • Vérif : ssl-protocols dans annotations/ConfigMap.
  • Correctif : définissez "TLSv1.2 TLSv1.3" ; redémarrez le contrôleur si nécessaire.
  1. mTLS verrouille des utilisateurs valides
  • Symptôme : tout le monde reçoit 400/401/403.
  • Vérifs : nom/clé du Secret CA, verify-depth, et si les clients envoient bien un cert.
  • Retour arrière rapide : retirez les annotations auth-tls-* et réappliquez. Conservez un manifeste de secours pour restaurer vite.
  1. Limitation de débit trop agressive
  • Symptôme : de nombreux 429 en charge normale.
  • Correctif : augmentez limit-rps et limit-burst ou retirez temporairement. Vérifiez avec la boucle de rafale.
  1. Allow-list IP trop serrée
  • Symptôme : 403 pour des utilisateurs attendus.
  • Correctif : ajoutez les plages CIDR et réappliquez. Testez d'abord sur un host de staging.
  1. NetworkPolicy bloque les backends
  • Symptôme : 502/504 côté contrôleur ; logs montrant des échecs de connexion upstream.
  • Vérifs : sélecteurs de namespace/pod dans la policy, numéros de ports.
  • Correctif : ajustez sélecteurs/ports ; retestez depuis le namespace du contrôleur.
  1. Les source ranges du LB bloquent les sondes
  • Symptôme : LB jamais sain ; champ ADDRESS en attente ou trafic trou noir.
  • Correctif : incluez les IP des sondes du fournisseur dans loadBalancerSourceRanges. Pour confirmer, élargissez temporairement à 0.0.0.0/0, puis resserrez.

Guidage de rollback :

  • Exportez toujours le manifeste courant avant les changements :
kubectl -n app get ingress web -o yaml > web-backup-$(date +%Y%m%d%H%M%S).yaml
  • En cas de casse, réappliquez immédiatement le backup :
kubectl apply -f web-backup-20240101123456.yaml
  • Pour des changements globaux (ConfigMap, Service), mettez en scène hors production. Si la prod est impactée, revenez à la version précédente et redémarrez le déploiement du contrôleur pour reprendre les réglages.

Vérification d'expiration de certificat et rétablissement (exemple construit) :

# Décoder et vérifier la date Not After
kubectl -n app get secret web-tls -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -enddate
# Renouveler en remplaçant le secret, puis revérifier
kubectl -n app create secret tls web-tls --key new.key --cert new.crt --dry-run=client -o yaml | kubectl apply -f -

Liste de contrôle opérationnelle

À utiliser lors des revues régulières et avant/après changements.

  • Inventaire
  • Confirmez les versions de Kubernetes, du contrôleur et de l'IngressClass.
  • Dressez la liste des hosts exposés à Internet et leurs namespaces.
  • TLS et en-têtes
  • Tous les hosts publics imposent HTTPS avec HSTS ; TLSv1.2+ uniquement.
  • Les secrets sont de type kubernetes.io/tls et non partagés entre namespaces sans lien.
  • Pas de fuite de version serveur (server-tokens à false).
  • Contrôle d'accès
  • mTLS requis pour les endpoints admin ou internes.
  • Allow-lists IP présentes pour les services restreints.
  • Limites de débit ajustées avec marge.
  • Permissions et politiques
  • RBAC limite la modification d'Ingress et des secrets associés aux équipes autorisées.
  • ValidatingAdmissionPolicy impose TLS et l'IngressClass approuvé.
  • NetworkPolicies n'autorisent que le contrôleur à joindre les backends.
  • Load balancer
  • externalTrafficPolicy=Local si vous avez besoin de l'IP cliente.
  • loadBalancerSourceRanges restreint les IP entrantes quand c'est possible.
  • Vérification
  • Les checks curl et openssl passent pour chaque host.
  • Les logs du contrôleur ne montrent pas d'erreurs TLS ou upstream récurrentes.
  • Préparation à la reprise
  • Manifeste exporté avant changement ; backups fiables disponibles.
  • Étapes de rollback documentées et testées sur un host de staging.

Conclusion

Vous avez durci Kubernetes Ingress en liant explicitement un IngressClass, en imposant TLS et HSTS, en ajoutant mTLS quand nécessaire, en restreignant le trafic via allow-lists IP et limites de débit, en verrouillant secrets et RBAC, en appliquant des NetworkPolicies et en resserrant l'exposition du load balancer. Vous avez vérifié chaque contrôle avec des checks observables et préparé des procédures de retour arrière pour une reprise rapide. Étendez maintenant de l'hôte durci à tous les services exposés à Internet, en gardant des changements étroits, testables et réversibles. En itérant avec un plan clair et des vérifications mesurables, vous réduisez le rework et maintenez des points d'entrée sûrs.

Score de qualité de l’article

Utilité pour le lecteur 97%
  • check_circle Guide prêt à lire
  • check_circle Exemples pratiques inclus
  • check_circle URL d’article optimisée pour le SEO