TLS et sécurité avec Envoy Gateway : configurer HTTPS et éviter que votre API tourne à nu

6 min read

Faire fonctionner HTTP n'est que l'échauffement. À moins que votre service ne vive à l'âge de pierre, la production a presque certainement besoin de HTTPS. Cet article couvre les fondamentaux TLS d'Envoy Gateway pour que vos API cessent de circuler en clair.

Comment TLS fonctionne dans Gateway

L'approche la plus courante : terminer TLS au niveau du listener du Gateway.

Cela signifie :

  • Le client se connecte en HTTPS
  • Le Gateway gère la négociation et le certificat
  • Le trafic est ensuite transféré à votre Service sans chiffrement en interne

Un listener HTTPS de base ressemble à ceci :

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: eg
spec:
  gatewayClassName: eg
  listeners:
    - name: http
      protocol: HTTP
      port: 80
    - name: https
      protocol: HTTPS
      port: 443
      tls:
        mode: Terminate
        certificateRefs:
          - kind: Secret
            group: ""
            name: example-cert

Deux choses comptent ici :

  • protocol: HTTPS
  • tls.mode: Terminate

Autrement dit : TLS se termine ici, et le Gateway gère le certificat.

HTTPS + HTTPRoute vs TLSRoute : quelle différence

C'est important, parce que beaucoup de gens voient TLSRoute et demandent immédiatement :

"Un listener HTTPS ne suffit-il pas déjà ? Pourquoi a-t-on besoin d'un TLSRoute séparé ?"

La différence tient à la question de savoir si le Gateway termine TLS :

Scénario Combinaison courante Description
Le Gateway termine TLS, puis applique des règles HTTP HTTPS listener + HTTPRoute Le cas le plus courant pour les sites web et les API
Le Gateway ne déchiffre pas, il route seulement le trafic chiffré selon le SNI TLS listener + TLSRoute Scénario de TLS passthrough

Autrement dit :

  • Si vous voulez inspecter path, header, method au niveau du Gateway, vous devez d'abord terminer TLS, puis utiliser HTTPRoute
  • Si vous voulez conserver un chiffrement de bout en bout et ne pas déchiffrer au niveau du Gateway, TLSRoute est le bon chemin

Aucune des deux approches n'est "plus avancée" : l'essentiel est de savoir ce que vous voulez, entre "terminer TLS et faire du routage L7" ou "garder le chiffrement intact et faire du routage basé sur SNI".

Préparer le Secret de certificat

Pour les environnements de test, un certificat auto-signé suffit. Les exemples officiels utilisent exactement cette approche :

openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 \
  -subj '/O=example Inc./CN=example.com' \
  -keyout example.com.key \
  -out example.com.crt
 
openssl req -out www.example.com.csr -newkey rsa:2048 -nodes \
  -keyout www.example.com.key \
  -subj "/CN=www.example.com/O=example organization"
 
openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key \
  -set_serial 0 -in www.example.com.csr -out www.example.com.crt

Stockez le certificat et la clé sous forme de Secret Kubernetes :

kubectl create secret tls example-cert \
  --key=www.example.com.key \
  --cert=www.example.com.crt

Le Gateway pourra ensuite référencer ce Secret via certificateRefs.

⚠️ Les certificats auto-signés servent uniquement au test. En production, utilisez cert-manager ou votre processus existant de gestion de certificats. Ne transportez pas tel quel le setup de démonstration en production, sinon c'est comme vivre de nouilles instantanées : acceptable de temps en temps, mais impossible à tenir sur la durée.

Ajouter un listener HTTPS à un Gateway existant

Si vous avez déjà un Gateway eg depuis l'article précédent, vous pouvez le patcher directement :

kubectl patch gateway eg --type=json --patch '
  - op: add
    path: /spec/listeners/-
    value:
      name: https
      protocol: HTTPS
      port: 443
      tls:
        mode: Terminate
        certificateRefs:
        - kind: Secret
          group: ""
          name: example-cert
'

Vérifiez le status :

kubectl get gateway/eg -o yaml

Si le listener semble sain, testez HTTPS :

curl -v -HHost:www.example.com \
  --resolve "www.example.com:443:${GATEWAY_HOST}" \
  --cacert example.com.crt \
  https://www.example.com/get

Cette commande est excellente pour une validation locale, surtout lorsque le DNS n'est pas encore câblé.

Un Gateway, plusieurs domaines HTTPS

Si vous avez plusieurs domaines, ajoutez plusieurs listeners HTTPS au même Gateway. Par exemple, pour ajouter foo.example.com :

listeners:
  - name: https-main
    protocol: HTTPS
    port: 443
    hostname: www.example.com
    tls:
      mode: Terminate
      certificateRefs:
        - name: example-cert
  - name: https-foo
    protocol: HTTPS
    port: 443
    hostname: foo.example.com
    tls:
      mode: Terminate
      certificateRefs:
        - name: foo-cert

N'oubliez pas de mettre à jour le HTTPRoute correspondant avec le bon hostname ; sinon, le listener peut bien écouter, mais la route ne saura pas où envoyer le trafic.

Modèle mental pour TLSRoute

Pour le TLS passthrough, voyez TLSRoute ainsi :

💡 L'apiVersion de TLSRoute peut différer selon la version des CRD Gateway API installée. L'exemple ci-dessous sert à illustrer le concept ; vérifiez la version installée dans votre cluster avant de l'appliquer.

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: eg-tls
spec:
  gatewayClassName: eg
  listeners:
    - name: tls
      protocol: TLS
      port: 443
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TLSRoute
metadata:
  name: passthrough-route
spec:
  parentRefs:
    - name: eg-tls
  hostnames:
    - "db.example.com"
  rules:
    - backendRefs:
        - name: db-service
          port: 5432

Cas d'usage courants pour ce pattern :

  • Routage uniquement selon le hostname SNI
  • Conservation du chiffrement jusqu'au backend
  • Pas d'analyse des paths/headers HTTP au niveau du Gateway

Donc la plus grande différence entre TLSRoute et HTTPRoute n'est pas seulement le nom : ils opèrent à des couches de trafic complètement différentes.

Références de certificats inter-namespace

La documentation officielle met en avant une capacité utile : Un Gateway peut référencer des Secrets de certificats d'autres namespaces, mais cela nécessite un ReferenceGrant.

Par exemple, si l'équipe plateforme stocke les certificats de manière centralisée dans envoy-gateway-system, mais que le Gateway applicatif se trouve dans default, vous ne pouvez pas simplement faire une référence à travers les namespaces sans autorisation explicite.

Exemple :

apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: allow-default-to-read-cert
  namespace: envoy-gateway-system
spec:
  from:
    - group: gateway.networking.k8s.io
      kind: Gateway
      namespace: default
  to:
    - group: ""
      kind: Secret

Cela signifie :

  • Un Gateway dans le namespace default
  • Est autorisé à référencer des ressources Secret dans envoy-gateway-system

Sans ReferenceGrant, cette référence inter-namespace est considérée comme invalide. C'est un mécanisme de protection, pas un excès de rigidité de Gateway API.

Résumé en une ligne

Le TLS d'Envoy Gateway n'est pas aussi mystérieux qu'il en a l'air : préparez le Secret de certificat, configurez le listener HTTPS, vérifiez que votre route et votre hostname sont alignés — et c'est essentiellement tout.

💡 L'erreur de débutant la plus courante n'est pas que TLS soit difficile, c'est que trois éléments ne sont pas alignés : hostname, certificateRefs et HTTPRoute hostnames. Si un seul de ces trois points dévie, le trafic commence à mal se comporter.

Étape suivante

Maintenant que vous avez couvert l'installation, les concepts, le routage et TLS, l'article suivant condense tout cela en un ensemble de pratiques moins susceptibles d'exploser en production : 👉 Bonnes pratiques