To encrypt traffic between pods in Deckhouse Kubernetes Platform (DKP),
you can use mTLS provided by Istio (via the istio module).
mTLS (mutual TLS) enables mutual authentication between services using TLS certificates: for all outgoing requests, the server certificate is verified; for incoming requests, the client certificate is checked. Once verification is successful, the sidecar proxy identifies the remote node and can use this information for authorization or other application-level purposes.
Each service receives a unique identifier in the format <TrustDomain>/ns/<Namespace>/sa/<ServiceAccount>.
Where:
TrustDomainis the cluster domain.ServiceAccountis the account name (eitherdefaultor a custom one).
This identifier is used as the verifiable name in TLS certificates.
The settings can be overridden at the namespace level.
mTLS configuration example
-
Enable the
istiomodule:d8 k create -f -<<EOF apiVersion: deckhouse.io/v1alpha1 kind: ModuleConfig metadata: name: istio spec: version: 2 enabled: true EOF -
Create a namespace and add labels:
d8 k create namespace test-istio-mtls d8 k label namespace test-istio-mtls istio-injection=enabled d8 k label namespace test-istio-mtls security.deckhouse.io/pod-policy=privileged -
Apply a policy that defines the mTLS mode. Available modes:
PERMISSIVE(default): Allows encrypted traffic between pods, but also permits unencrypted traffic.STRICT: Only encrypted traffic is allowed.
Example of applying
PERMISSIVEmode:d8 k -n test-istio-mtls create -f -<<EOF apiVersion: security.istio.io/v1beta1 kind: PeerAuthentication metadata: name: default spec: mtls: mode: PERMISSIVE EOF -
Create a Deployment:
-
If using a public registry:
d8 k -n test-istio-mtls create deployment webserver --image=docker.io/library/nginx:1.26-alpine --port 80 -
If using an all-in-one image (replace with your registry address):
d8 k -n test-istio-mtls create deployment webserver --image=registry.company.network/localrepo/all-in-one-image:0.1 --port 80 -- /bin/sh -c 'nginx -g "daemon off;"'
-
-
Expose the Deployment:
d8 k -n test-istio-mtls expose deployment webserver --port=80 -
Get the Pod IP or the associated node name. It will be required to run
tcpdumpon the respective node:d8 k -n test-istio-mtls get pods -l app=webserver -o wideExample output:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES webserver-76d6c9b8c-9mdtb 2/2 Running 0 48m 10.111.1.122 test-worker-e36e4712-5948b-sp9t8 <none> <none> -
Access the node via SSH as root and run
tcpdump:tcpdump -A -v -i any host 10.111.1.122 and port 80 -
Create a Deployment client in the same namespace so that it is part of the mesh network:
-
If using a public registry image:
d8 k -n test-istio-mtls create deployment client --image=docker.io/library/alpine:3.21 -- /bin/sh -c "sleep infinity" -
If using an all-in-one image (replace with your registry address):
d8 k -n test-istio-mtls create deployment client --image=registry.company.network/localrepo/all-in-one-image:0.1 -- /bin/sh -c "sleep infinity"
-
-
After the Pod is created, make a request to the
webserverservice:d8 k -n test-istio-mtls exec -ti deployments/client -- wget -S --spider --timeout 1 webserver`The
tcpdumpoutput will show only encrypted traffic:10.111.91.68.http > 10.111.91.167.54204: Flags [P.], cksum 0xd7c7 (incorrect -> 0xe83a), seq 1:3033, ack 518, win 134, options [nop,nop,TS val 3160034944 ecr 2239691194], length 3032: HTTP E....]@.@.T. o[D o[..P..'...;.i8........... .ZN..~......z...v...T......d.4p ..6j..V..G...0 d..U h...e....W.`.....4....;.......T.......3.$... [..%ex.....i<...*.[..C...jC....p.+..............Nt ................{..P%.+.,L......A........B..7}.v../...rg.o.)5......E.X;K8..%,..yb.^f...^+..Ble.j..w3 S......}.. |3...+.=...;H..#...Y...3h.....:.9.w.A.4X..g...|S;.`<....%.y..4.....D.m...../6.7[.......!+.J........2._r.D.C>`.3A..... ..H.^1...P1N....)..%... r.=..s.FB..i^..^....4{;...ED_.\...g`l,q........U*0.#..(......).h..|sc... .c(..kd....5C@..5.Z.L..C2 @.7>..y%....R.5........j9........!........H.a....b..].0..~..0x7..+N...o.6........ (%7:.Xr..N......'.O.a.j&v..Ba.....t..q. =U.t.fU.].......2g....Eat.D.3n........*G.N..!LY.......n)......._jL..9RD..gT.lX..p&..=.d..Tq%....qF`.....'..|..$!g..j.d. N%tb^...@- ..`...S:..D.....y...ckA.;}Y,.....X..6...=[,..|AD..._}......W.. ..u3G...<. ..&.0j.,.'!.# ....w..bx..............}U.;..y....J.K..fQ.#]..3.V..=.d._.'....q.;!.9.N......n.7.Zi.>....@...].u.A}.;.....c..s......d.*=..G..9......Nt@....v..s.>. ...h....Cm.Z.......n......L.......-_.......r...%Z.....h...........`..8A....yt.t..2d....oH?.1.O&.J....F..b.OV.............E1H..%~..2.H..{.I...=.I.*..2y1p0h..........P.....@r....vk.!".......{..`.3..<,.r&L.....M...t...;.z...Q...1+.,.......:._L.V.....e.. ..!]\..6*}....vT.A>.....A0.....{.?}AH.+R..g.[=?.X...|94....S+!..e...*..M`f...o..b.K#5.....@...5.......o.(. ... -
Create a namespace without the
istio-injection=enabledlabel and make a request to thewebserver.test-istio-mtlsservice (a request is made from a Pod that is not part of the mesh network):d8 k create namespace test-istio-mtls-without-injection -
Add a Deployment:
-
If using a public registry image:
d8 k -n test-istio-mtls-without-injection create deployment alpine --image=docker.io/library/alpine:3.21 -- /bin/sh -c "sleep infinity" -
If using an all-in-one image (replace with your registry address):
d8 k -n test-istio-mtls create deployment client --image=registry.company.network/localrepo/all-in-one-image:0.1 -- /bin/sh -c "sleep infinity"
-
-
After the Pod is created, make a request to the
webserver.test-istio-mtlsservice:d8 k -n test-istio-mtls-without-injection exec -ti deployments/alpine -- wget -S --spider --timeout 1 webserver.test-istio-mtls`.The
tcpdumpoutput will show only unencrypted (plain text) requests and responses:10.111.91.211.54424 > 10.111.91.68.http: Flags [P.], cksum 0xcc77 (incorrect -> 0xee57), seq 1:93, ack 1, win 128, options [nop,nop,TS val 305286128 ecr 3834507600], length 92: HTTP, length: 92 GET / HTTP/1.1 Host: webserver.test-istio-mtls User-Agent: Wget Accept: */* Connection: close E...y.@.?... o[. o[D...P....<Nb......w..... .2K....PGET / HTTP/1.1 Host: webserver.test-istio-mtls User-Agent: Wget Accept: */* Connection: close 09:14:20.960302 lxc4f4a182c887c In IP (tos 0x0, ttl 64, id 33396, offset 0, flags [DF], proto TCP (6), length 52) 10.111.91.68.http > 10.111.91.211.54424: Flags [.], cksum 0xcc1b (incorrect -> 0xa850), ack 93, win 128, options [nop,nop,TS val 3834507601 ecr 305286128], length 0 E..4.t@.@..Z o[D o[..P..<Nb................ ...Q.2K. 09:14:20.964496 lxc4f4a182c887c In IP (tos 0x0, ttl 64, id 33397, offset 0, flags [DF], proto TCP (6), length 1003) 10.111.91.68.http > 10.111.91.211.54424: Flags [P.], cksum 0xcfd2 (incorrect -> 0x44eb), seq 1:952, ack 93, win 128, options [nop,nop,TS val 3834507605 ecr 305286128], length 951: HTTP, length: 951 HTTP/1.1 200 OK server: istio-envoy date: Fri, 24 Jan 2025 09:14:20 GMT content-type: text/html content-length: 615 last-modified: Wed, 14 Aug 2024 05:42:07 GMT etag: "66bc43af-267" accept-ranges: bytes x-envoy-upstream-service-time: 0 connection: close x-envoy-decorator-operation: webserver.test-istio-mtls.svc.cluster.local:80/* <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>