Verkeer tussen pods is in een standaard Kubernetes-cluster niet automatisch versleuteld. Als je wilt afdwingen dat services onderling alleen via TLS of mTLS communiceren, moet je dat zelf configureren of een service mesh gebruiken.
In deze handleiding configureer je app-level mTLS zonder extra service mesh (bijv. Linkerd). Je maakt een eigen Certificate Authority (CA), server- en clientcertificaten, publiceert een interne service via Nginx met verplichte clientauthenticatie en test daarna zowel de geslaagde als de geweigerde verbinding.
- Gebruik deze aanpak als je mTLS gericht voor een specifieke applicatie of interne API wilt afdwingen.
- Wil je mTLS clusterbreed en centraal afdwingen, gebruik dan een service mesh zoals Linkerd of Istio.
- Bewaar private keys nooit in Git. Sla ze op in Secrets of in een externe secret manager.
- Voor deze handleiding heb je kubectl nodig.
Wanneer gebruik je mTLS?
- Gebruik dit wel: voor interne API's, compliance-eisen of services die geen onbeveiligd pod-naar-podverkeer mogen accepteren.
- Gebruik dit niet als enige maatregel: combineer mTLS altijd met namespaces, NetworkPolicies en least privilege.
- Gebruik een service mesh: als je niet per applicatie certificaten en Nginx-configuraties wilt beheren.
Met de opzet in deze handleiding versleutel en authenticeer je verkeer tussen pods expliciet. Zo voorkom je dat interne services zomaar onbeveiligde verbindingen accepteren.
Maak de TLS-certificaten aan
Stap 1
via en maak lokaal een werkdirectory aan voor de certificaten:
mkdir -p ~/kb-mtls
cd ~/kb-mtls
Stap 2
Maak een CA-certificaat aan dat de server- en clientcertificaten gaat ondertekenen:
openssl req -x509 -newkey rsa:2048 -nodes \
-keyout ca.key \
-out ca.crt \
-subj "/CN=kb-mtls-ca" \
-days 365De vlag `-nodes` voorkomt dat OpenSSL om een passphrase vraagt. Dat is praktisch voor testomgevingen, maar in productie gebruik je voor private keys bij voorkeur extra bescherming.
Stap 3
Maak daarna een servercertificaat aan voor de interne service:
openssl req -newkey rsa:2048 -nodes \
-keyout server.key \
-out server.csr \
-subj "/CN=mtls-server.kb-mtls-test.svc.cluster.local"Maak vervolgens een extensiebestand aan met de DNS-namen van je service:
nano server.extPlaats de volgende inhoud in het bestand:
subjectAltName=DNS:mtls-server,DNS:mtls-server.kb-mtls-test.svc,DNS:mtls-server.kb-mtls-test.svc.cluster.localSla de wijzigingen op en sluit het bestand (ctrl + x > y > enter).
Onderteken daarna het servercertificaat:
openssl x509 -req \
-in server.csr \
-CA ca.crt \
-CAkey ca.key \
-CAcreateserial \
-out server.crt \
-days 365 \
-sha256 \
-extfile server.ext
Stap 4
Maak ook een clientcertificaat aan voor de pod die met de service mag praten:
openssl req -newkey rsa:2048 -nodes \
-keyout client.key \
-out client.csr \
-subj "/CN=mtls-client"
openssl x509 -req \
-in client.csr \
-CA ca.crt \
-CAkey ca.key \
-CAcreateserial \
-out client.crt \
-days 365 \
-sha256
Maak de Secrets en workloads aan
Stap 1
Maak eerst een namespace en twee Secrets aan: één voor de server en één voor de client:
kubectl create namespace kb-mtls-test
kubectl -n kb-mtls-test create secret generic mtls-server \
--from-file=ca.crt=ca.crt \
--from-file=server.crt=server.crt \
--from-file=server.key=server.key
kubectl -n kb-mtls-test create secret generic mtls-client \
--from-file=ca.crt=ca.crt \
--from-file=client.crt=client.crt \
--from-file=client.key=client.keyDe server gebruikt `ca.crt` om clientcertificaten te controleren. De client gebruikt zijn eigen certificaat en private key om zich bij de server te authenticeren.
Stap 2
Maak daarna een manifest aan voor de server, service en twee clientpods:
nano mtls-demo.yamlPlaats de volgende configuratie in het bestand:
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-mtls
namespace: kb-mtls-test
data:
default.conf: |
server {
listen 8443 ssl;
server_name mtls-demo;
ssl_certificate /etc/nginx/tls/server.crt;
ssl_certificate_key /etc/nginx/tls/server.key;
ssl_client_certificate /etc/nginx/tls/ca.crt;
ssl_verify_client on;
location / {
default_type text/plain;
return 200 "mtls-ok\n";
}
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mtls-server
namespace: kb-mtls-test
spec:
replicas: 1
selector:
matchLabels:
app: mtls-server
template:
metadata:
labels:
app: mtls-server
spec:
containers:
- name: nginx
image: nginx:1.27-alpine
ports:
- containerPort: 8443
volumeMounts:
- name: config
mountPath: /etc/nginx/conf.d/default.conf
subPath: default.conf
- name: tls
mountPath: /etc/nginx/tls
readOnly: true
volumes:
- name: config
configMap:
name: nginx-mtls
- name: tls
secret:
secretName: mtls-server
---
apiVersion: v1
kind: Service
metadata:
name: mtls-server
namespace: kb-mtls-test
spec:
selector:
app: mtls-server
ports:
- port: 8443
targetPort: 8443
---
apiVersion: v1
kind: Pod
metadata:
name: mtls-client
namespace: kb-mtls-test
spec:
restartPolicy: Never
containers:
- name: curl
image: curlimages/curl:8.12.1
command: ["sh", "-c", "sleep 3600"]
volumeMounts:
- name: client-tls
mountPath: /etc/mtls/client
readOnly: true
volumes:
- name: client-tls
secret:
secretName: mtls-client
---
apiVersion: v1
kind: Pod
metadata:
name: mtls-client-no-cert
namespace: kb-mtls-test
spec:
restartPolicy: Never
containers:
- name: curl
image: curlimages/curl:8.12.1
command: ["sh", "-c", "sleep 3600"]Sla de wijzigingen op en sluit het bestand (ctrl + x > y > enter).
Stap 3
Maak de resources aan:
kubectl apply -f mtls-demo.yaml
kubectl -n kb-mtls-test rollout status deploy/mtls-server
kubectl -n kb-mtls-test wait --for=condition=Ready pod/mtls-client --timeout=180s
kubectl -n kb-mtls-test wait --for=condition=Ready pod/mtls-client-no-cert --timeout=180s
Test geslaagde en geweigerde verbindingen
Stap 1
Test de verbinding vanaf de clientpod met clientcertificaat:
kubectl -n kb-mtls-test exec mtls-client -- sh -c \
"curl --cacert /etc/mtls/client/ca.crt \
--cert /etc/mtls/client/client.crt \
--key /etc/mtls/client/client.key \
https://mtls-server:8443"Als alles correct is geconfigureerd, krijg je als antwoord `mtls-ok` terug.
Stap 2
Test daarna een verbinding zonder clientcertificaat:
kubectl -n kb-mtls-test exec mtls-client -- sh -c \
"curl -k -sv https://mtls-server:8443 2>&1 | tail -n 20"Je hoort hier een foutmelding te zien zoals `400 No required SSL certificate was sent`. Daarmee dwingt de service dus mTLS af voor intern verkeer.