Aller au contenu

mTLS service mesh — runbook d'activation Linkerd

AKKO embarque un sub-chart akko-mtls (ADR-037) qui enveloppe Linkerd pour chiffrer et authentifier mutuellement chaque appel pod-à-pod dans le namespace akko. Désactivé par défaut — cette page documente l'activation lorsque vous décidez de l'enclencher.

Pourquoi mTLS

Aujourd'hui, chaque appel service-à-service (Trino → Polaris, Airflow → PostgreSQL, ADEN → OPA, …) circule en clair sur HTTP. Les NetworkPolicy contrôlent qui peut parler à qui, mais pas ce qui transite. mTLS apporte deux garanties :

  1. Chiffrement — Un pod compromis ou un opérateur malveillant avec kubectl exec ne peut plus capturer du trafic sensible via tcpdump.
  2. Authentification mutuelle — Chaque pod prouve son identité via un certificat éphémère émis par Linkerd. Plus de "confiance aveugle" entre services partageant un namespace.

Bénéfice conformité : les contrôles SOC2 / ISO27001 / PCI-DSS sur le chiffrement en transit sont satisfaits sans configuration par-service.

Pourquoi Linkerd (et pas Istio / Cilium)

Voir ADR-037. Version courte :

  • Linkerd est CNCF Graduated, Apache 2.0, gouvernance Foundation-neutre
  • ~10 Mo RAM par sidecar (Istio est 15× plus lourd ; coule la box démo Netcup)
  • CNI-agnostique — fonctionne sur k3s/EKS/GKE existants sans rupture
  • Un seul sub-chart, pas d'explosion de couplage Lego

Pré-requis

  • Kubernetes 1.27+ (Linkerd 2.16 le requiert)
  • cert-manager déjà installé (réutilisé comme issuer d'identité Linkerd)
  • Helm 3.13+
  • ~500 Mo de RAM libre cluster-wide pour les sidecars
  • Un redémarrage one-shot des pods (l'injection se fait à l'admission)

Activation

Étape 1 — Installer les CRD Linkerd (one-time par cluster)

helm repo add linkerd https://helm.linkerd.io/stable
helm repo update
helm install linkerd-crds linkerd/linkerd-crds \
  -n linkerd --create-namespace

Étape 2 — Installer le control plane Linkerd

L'ancre de confiance + le certificat d'issuer sont mieux provisionnés via cert-manager. AKKO fournit un exemple Issuer aligné avec le ClusterIssuer wildcard existant :

# Générer une ancre de confiance cluster-wide (CA root, gardée hors-ligne)
step certificate create root.linkerd.cluster.local \
  ca.crt ca.key --profile root-ca \
  --no-password --insecure

# Générer le cert d'issuer per-cluster
step certificate create identity.linkerd.cluster.local \
  issuer.crt issuer.key --profile intermediate-ca \
  --not-after 8760h --no-password --insecure \
  --ca ca.crt --ca-key ca.key

# Installer le control plane Linkerd avec les certs
helm install linkerd-control-plane linkerd/linkerd-control-plane \
  -n linkerd \
  --set-file identityTrustAnchorsPEM=ca.crt \
  --set-file identity.issuer.tls.crtPEM=issuer.crt \
  --set-file identity.issuer.tls.keyPEM=issuer.key

Étape 3 — Activer le sub-chart AKKO mTLS

helm upgrade akko helm/akko -n akko \
  --set akko-mtls.enabled=true \
  --set akko-mtls.injectNamespace=true \
  -f helm/examples/values-domain.yaml \
  -f helm/examples/values-dev-secrets.yaml

Étape 4 — Redémarrer les workloads AKKO pour injecter les sidecars

kubectl rollout restart deploy -l app.kubernetes.io/part-of=akko -n akko
kubectl rollout restart statefulset -l app.kubernetes.io/part-of=akko -n akko

Cela redémarre ~50 deployments en rolling — bascule cluster complète typiquement ~5 min sur la box démo Netcup.

Étape 5 — Vérifier que mTLS est actif

Installer le CLI Linkerd :

curl -sL https://run.linkerd.io/install | sh
export PATH=$PATH:$HOME/.linkerd2/bin

Lancer le check cluster :

linkerd check

Attendu : chaque section ✓.

Vérifier la handshake mTLS sur un appel échantillon :

linkerd viz tap deploy/akko-akko-cockpit -n akko --output json | head -5

Chercher "tls": "true" dans la sortie.

Déploiement progressif (recommandé)

  1. Sprint N (audit)injectNamespace=false. Choisir un workload (par exemple akko-akko-aden), annoter son pod template avec linkerd.io/inject: enabled, redémarrer, observer linkerd check pendant 24h.
  2. Sprint N+1 (audit cluster-wide)injectNamespace=true, redémarrer tous les workloads, surveiller la métrique Prometheus request_total{tls="true"} qui doit atteindre ~100%.
  3. Sprint N+2 (enforce) — annoter chaque workload avec config.linkerd.io/default-inbound-policy: cluster-authenticated pour que les requêtes plaintext soient REJETÉES.

Dépannage

Expiration du cert issuer Linkerd

Linkerd utilise par défaut une durée de vie de 24h avec auto-rotation. Si linkerd check indique l'expiration prochaine de l'issuer, lancer :

helm upgrade linkerd-control-plane linkerd/linkerd-control-plane \
  -n linkerd \
  --set-file identityTrustAnchorsPEM=ca.crt \
  --set-file identity.issuer.tls.crtPEM=issuer-renewed.crt \
  --set-file identity.issuer.tls.keyPEM=issuer-renewed.key \
  --reuse-values

Pods bloqués en pending après redémarrage

L'injection sidecar ajoute ~50 Mo de demande mémoire par pod. Si Netcup atteint son plafond de 16 Go, abaisser la demande mémoire par sidecar via linkerd-control-plane.proxy.resources.requests.memory.

Spark / Trino federation cassent

Spark Connect et la fédération Trino utilisent HTTP/2 + gRPC. Linkerd les gère de façon transparente — mais le premier appel après activation du sidecar peut échouer en "EOF" pendant que le proxy négocie la handshake TLS. Ré-essayer une fois. Si ça persiste, vérifier linkerd viz stat deploy/akko-akko-spark-master.

Désactiver mTLS (rollback)

helm upgrade akko helm/akko -n akko \
  --set akko-mtls.enabled=false \
  --set akko-mtls.injectNamespace=false

kubectl rollout restart deploy -l app.kubernetes.io/part-of=akko -n akko

Rollout service-par-service (Sprint 60.1)

Deux stratégies d'activation supportées. Choisir l'une ou l'autre — jamais les deux.

Stratégie A : namespace entier

Injection sur tous les pods du namespace akko. Plus simple mais bascule tous les services en même temps.

akko-mtls:
  enabled: true
  injectNamespace: true

Stratégie B : opt-in par service (recommandée)

Activer un service à la fois, valider le sidecar, puis passer au suivant. Les flags sont à false par défaut donc un helm upgrade n'ajoute rien.

global:
  serviceMesh:
    linkerdInject:
      aden: true       # phase 1 — API interne, rollback facile
      keycloak: false  # phase 2
      postgres: false  # phase 3 (StatefulSet — drainer prudemment)
      trino: false     # phase 4 — blast radius le plus large

akko-mtls:
  enabled: true
  injectNamespace: false   # PAS namespace-wide — opt-in par service

Après avoir basculé un flag :

kubectl -n akko rollout restart deploy/akko-akko-aden    # ou sts/akko-akko-postgresql
kubectl -n akko get pods -l app.kubernetes.io/name=akko-aden -o jsonpath='{.items[*].spec.containers[*].name}'
# Sortie attendue : "aden linkerd-proxy"  ← sidecar présent

Vérification end-to-end : lancer la marathon spec AKKO ; la marathon du founder (B1..B14) couvre chaque appel cross-service que ADEN fait (Trino, OPA, OpenMetadata, LiteLLM). Les 13 tests doivent rester verts après injection.

Cas Trino

Trino est un chart Helm community — ses valeurs dictent le point d'injection de l'annotation. Activer via :

trino:
  coordinator:
    podAnnotations:
      linkerd.io/inject: enabled
  worker:
    podAnnotations:
      linkerd.io/inject: enabled

L'umbrella global.serviceMesh.linkerdInject.trino n'est câblé que pour la documentation et la parité avec les 3 autres services ; il ne se propage PAS au pod template du chart community par lui-même.

Rollback

Repasser le flag à false et redémarrer le workload. Les certificats d'identité Linkerd tournent toutes les 24 h ; le proxy disparaît au prochain rollout.

Référence

  • ADR-037 — sélection mTLS service mesh
  • helm/akko/charts/akko-mtls/ — source du sub-chart
  • Documentation Linkerd : https://linkerd.io/2-edge/getting-started/