Configuration mTLS
Guide complet pour implémenter TLS mutuel pour la communication de maillage de services sans confiance.
Quand utiliser cette compétence
- Implémenter une mise en réseau sans confiance
- Sécuriser la communication de service à service
- Rotation et gestion des certificats
- Déboguer les problèmes de poignée de main TLS
- Exigences de conformité (PCI-DSS, HIPAA)
- Communication sécurisée multi-cluster
Concepts fondamentaux
1. Flux mTLS
┌─────────┐ ┌─────────┐
│ Service │ │ Service │
│ A │ │ B │
└────┬────┘ └────┬────┘
│ │
┌────┴────┐ Poignée de main TLS ┌────┴────┐
│ Proxy │◄───────────────────────────►│ Proxy │
│(Sidecar)│ 1. ClientHello │(Sidecar)│
│ │ 2. ServerHello + Cert │ │
│ │ 3. Client Cert │ │
│ │ 4. Vérifier les deux Certs │ │
│ │ 5. Canal chiffré │ │
└─────────┘ └─────────┘
2. Hiérarchie des certificats
Root CA (Auto-signé, longue durée)
│
├── Intermediate CA (Niveau cluster)
│ │
│ ├── Workload Cert (Service A)
│ └── Workload Cert (Service B)
│
└── Intermediate CA (Multi-cluster)
│
└── Certificats cross-cluster
Templates
Template 1 : Istio mTLS (Mode strict)
# Activer mTLS strict sur tout le maillage
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system
spec:
mtls:
mode: STRICT
---
# Remplacement au niveau de l'espace de noms (permissif pour migration)
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: legacy-namespace
spec:
mtls:
mode: PERMISSIVE
---
# Politique spécifique à la charge de travail
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: payment-service
namespace: production
spec:
selector:
matchLabels:
app: payment-service
mtls:
mode: STRICT
portLevelMtls:
8080:
mode: STRICT
9090:
mode: DISABLE # Port des métriques, pas de mTLS
Template 2 : Istio Destination Rule pour mTLS
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: default
namespace: istio-system
spec:
host: "*.local"
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
---
# TLS vers un service externe
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: external-api
spec:
host: api.external.com
trafficPolicy:
tls:
mode: SIMPLE
caCertificates: /etc/certs/external-ca.pem
---
# TLS mutuel vers un service externe
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: partner-api
spec:
host: api.partner.com
trafficPolicy:
tls:
mode: MUTUAL
clientCertificate: /etc/certs/client.pem
privateKey: /etc/certs/client-key.pem
caCertificates: /etc/certs/partner-ca.pem
Template 3 : Cert-Manager avec Istio
# Installer l'émetteur cert-manager pour Istio
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: istio-ca
spec:
ca:
secretName: istio-ca-secret
---
# Créer le secret CA Istio
apiVersion: v1
kind: Secret
metadata:
name: istio-ca-secret
namespace: cert-manager
type: kubernetes.io/tls
data:
tls.crt: <base64-encoded-ca-cert>
tls.key: <base64-encoded-ca-key>
---
# Certificat pour la charge de travail
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: my-service-cert
namespace: my-namespace
spec:
secretName: my-service-tls
duration: 24h
renewBefore: 8h
issuerRef:
name: istio-ca
kind: ClusterIssuer
commonName: my-service.my-namespace.svc.cluster.local
dnsNames:
- my-service
- my-service.my-namespace
- my-service.my-namespace.svc
- my-service.my-namespace.svc.cluster.local
usages:
- server auth
- client auth
Template 4 : Intégration SPIFFE/SPIRE
# Configuration du serveur SPIRE
apiVersion: v1
kind: ConfigMap
metadata:
name: spire-server
namespace: spire
data:
server.conf: |
server {
bind_address = "0.0.0.0"
bind_port = "8081"
trust_domain = "example.org"
data_dir = "/run/spire/data"
log_level = "INFO"
ca_ttl = "168h"
default_x509_svid_ttl = "1h"
}
plugins {
DataStore "sql" {
plugin_data {
database_type = "sqlite3"
connection_string = "/run/spire/data/datastore.sqlite3"
}
}
NodeAttestor "k8s_psat" {
plugin_data {
clusters = {
"demo-cluster" = {
service_account_allow_list = ["spire:spire-agent"]
}
}
}
}
KeyManager "memory" {
plugin_data {}
}
UpstreamAuthority "disk" {
plugin_data {
key_file_path = "/run/spire/secrets/bootstrap.key"
cert_file_path = "/run/spire/secrets/bootstrap.crt"
}
}
}
---
# DaemonSet de l'agent SPIRE (abrégé)
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: spire-agent
namespace: spire
spec:
selector:
matchLabels:
app: spire-agent
template:
spec:
containers:
- name: spire-agent
image: ghcr.io/spiffe/spire-agent:1.8.0
volumeMounts:
- name: spire-agent-socket
mountPath: /run/spire/sockets
volumes:
- name: spire-agent-socket
hostPath:
path: /run/spire/sockets
type: DirectoryOrCreate
Template 5 : Linkerd mTLS (Automatique)
# Linkerd active mTLS automatiquement
# Vérifier avec :
# linkerd viz edges deployment -n my-namespace
# Pour les services externes sans mTLS
apiVersion: policy.linkerd.io/v1beta1
kind: Server
metadata:
name: external-api
namespace: my-namespace
spec:
podSelector:
matchLabels:
app: my-app
port: external-api
proxyProtocol: HTTP/1 # ou TLS pour passthrough
---
# Ignorer TLS pour un port spécifique
apiVersion: v1
kind: Service
metadata:
name: my-service
annotations:
config.linkerd.io/skip-outbound-ports: "3306" # MySQL
Rotation des certificats
# Istio - Vérifier l'expiration du certificat
istioctl proxy-config secret deploy/my-app -o json | \
jq '.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' | \
tr -d '"' | base64 -d | openssl x509 -text -noout
# Forcer la rotation du certificat
kubectl rollout restart deployment/my-app
# Vérifier l'identité Linkerd
linkerd identity -n my-namespace
Déboguer les problèmes mTLS
# Istio - Vérifier si mTLS est activé
istioctl authn tls-check my-service.my-namespace.svc.cluster.local
# Vérifier l'authentification par pairs
kubectl get peerauthentication --all-namespaces
# Vérifier les règles de destination
kubectl get destinationrule --all-namespaces
# Déboguer la poignée de main TLS
istioctl proxy-config log deploy/my-app --level debug
kubectl logs deploy/my-app -c istio-proxy | grep -i tls
# Linkerd - Vérifier l'état de mTLS
linkerd viz edges deployment -n my-namespace
linkerd viz tap deploy/my-app --to deploy/my-backend
Bonnes pratiques
À faire
- Commencer avec PERMISSIVE - Migrer progressivement vers STRICT
- Surveiller l'expiration des certificats - Configurer des alertes
- Utiliser des certificats à courte durée de vie - 24 h ou moins pour les charges de travail
- Renouveler le CA périodiquement - Planifier la rotation du CA
- Enregistrer les erreurs TLS - Pour le débogage et l'audit
À éviter
- Ne pas désactiver mTLS - Pour des raisons de commodité en production
- Ne pas ignorer l'expiration des certificats - Automatiser la rotation
- Ne pas utiliser de certificats auto-signés - Utiliser une hiérarchie CA appropriée
- Ne pas ignorer la vérification - Vérifier la chaîne complète