Secure Your Kubernetes Ingress-Nginx with mTLS and HTTPS: Step‑by‑Step Guide
Learn how to configure Ingress‑Nginx in a running Kubernetes cluster for secure mTLS and HTTPS communication, covering prerequisites, certificate creation, deployment of HTTP and mTLS services, Ingress rules, SSL passthrough setup, and verification steps with practical kubectl and OpenSSL commands.
Preparation
Running Kubernetes cluster.
Ingress‑Nginx deployed.
At least one domain name that resolves to the Ingress‑Nginx service.
Environment Description
Business containers are accessed via Ingress rather than being exposed directly. Two TLS/HTTPS scenarios exist: (1) Backend service uses HTTP – Ingress terminates TLS/HTTPS and forwards HTTP to the backend. (2) Backend service uses HTTPS – Ingress passes TLS/HTTPS through to the backend.
Tip: When the backend service uses HTTPS, it usually requires mTLS. This article only demonstrates the HTTP‑backend case and the mTLS case.
Backend Service HTTP Protocol
1. Create a simple HTTP application
<code>$ cat <<'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: simple
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: simple
template:
metadata:
labels:
app: simple
spec:
containers:
- name: nginx
args:
- -p=1234
image: registry.cn-guangzhou.aliyuncs.com/jiaxzeng6918/simple:v2.0
imagePullPolicy: IfNotPresent
EOF</code>2. Create the Service for the simple app
<code>$ cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: simple
namespace: default
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 1234
selector:
app: simple
type: ClusterIP
EOF</code>3. Verify the simple service
<code>$ curl $(kubectl get svc simple -ojsonpath='{.spec.clusterIP}:{.spec.ports[0].port}')/who/hostname
simple-7b844c74dc-ptv4m
$ curl $(kubectl get svc simple -ojsonpath='{.spec.clusterIP}:{.spec.ports[0].port}')/who/hostname
simple-7b844c74dc-fnj2n</code>Backend Service HTTPS Protocol (mTLS)
1. Create certificates
<code># Self‑signed CA certificate
$ openssl req -newkey rsa:2048 -x509 -nodes -keyout ca.key -out ca.crt -days 3650 -subj "/CN=mTLS ca"
# Service certificate
$ openssl genrsa -out server.key 2048
$ openssl req -new -key server.key -out server.csr -subj "/CN=server simple"
$ openssl x509 -req -CA ca.crt -CAkey ca.key -in server.csr -out server.crt -CAcreateserial -days 365 -extfile <(printf "subjectAltName=IP:127.0.0.1,DNS:simple.jiaxzeng.com")
# Store CA and service certificates in a secret
$ kubectl create secret generic simple-mtls-certs --from-file=ca.crt=ca.crt --from-file=tls.crt=server.crt --from-file=tls.key=server.key</code>Tip: The certificate must include a
subjectAltNamethat contains the domain name; otherwise Ingress will fall back to the default SSL certificate.
2. Deploy the mTLS‑enabled simple application
<code>$ cat <<'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: simple-mtls
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: simple-mtls
template:
metadata:
labels:
app: simple-mtls
spec:
containers:
- name: simple-mtls
image: registry.cn-guangzhou.aliyuncs.com/jiaxzeng6918/simple:v2.0
imagePullPolicy: IfNotPresent
args:
- --mtls
- --cacert=/opt/ca.crt
- --cert=/opt/tls.crt
- --key=/opt/tls.key
volumeMounts:
- name: mtls
mountPath: /opt/
volumes:
- name: mtls
secret:
secretName: simple-mtls-certs
EOF</code>3. Create the Service for the mTLS app
<code>$ cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: simple-mtls
namespace: default
spec:
ports:
- name: https
port: 443
protocol: TCP
targetPort: 1234
selector:
app: simple-mtls
type: ClusterIP
EOF</code>4. Verify the mTLS service
<code># Generate a client certificate
$ openssl genrsa -out client.key 2048
$ openssl req -new -key client.key -out client.csr -subj "/CN=client simple"
$ openssl x509 -req -CA ca.crt -CAkey ca.key -in client.csr -out client.crt -CAcreateserial -days 365
# Access without a client certificate (expected to fail)
$ curl -k https://$(kubectl get svc simple-mtls -ojsonpath='{.spec.clusterIP}:{.spec.ports[0].port}')/who/hostname
curl: (58) NSS: client certificate not found (nickname not specified)
# Access with the client certificate
$ curl -k --cert ./client.crt --key ./client.key https://$(kubectl get svc simple-mtls -ojsonpath='{.spec.clusterIP}:{.spec.ports[0].port}')/who/hostname
simple-mtls-5b7f54bbbc-fhwk9</code>Enable SSL Passthrough for mTLS Backend
1. Enable SSL passthrough in the ingress‑nginx controller
<code># Helm installation – add two extra arguments
controller:
extraArgs:
enable-ssl-passthrough: "true"
$ helm -n kube-system upgrade ingress-nginx -f /etc/kubernetes/addons/ingress-nginx-value.yml /etc/kubernetes/addons/ingress-nginx
# Manifest‑based installation – edit the deployment args
$ kubectl -n kube-system edit deploy ingress-nginx-controller
# Add the following argument to spec.template.spec.containers.args
- --enable-ssl-passthrough=true</code>2. Configure Ingress for the HTTPS (mTLS) backend
<code>$ cat <<'EOF' | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
name: simple-mtls
namespace: default
spec:
ingressClassName: nginx
tls:
- hosts:
- mtls.jiaxzeng.com
secretName: simple-mtls-certs
rules:
- host: mtls.jiaxzeng.com
http:
paths:
- backend:
service:
name: simple-mtls
port:
number: 443
path: /
pathType: Prefix
EOF</code>3. Verify via Ingress using OpenSSL
<code>$ openssl s_client -connect 172.139.20.100:443 -cert ./client.crt -key ./client.key -CAfile ./ca.crt -servername mtls.jiaxzeng.com
... (full handshake output omitted for brevity) ...
GET /who/hostname HTTP/1.1
Host: mtls.jiaxzeng.com
Connection: close
HTTP/1.1 200 OK
... (headers) ...
simple-mtls-5b7f54bbbc-rw2lv</code>Configure Ingress Access (HTTP Backend)
1. Ingress for the simple HTTP application
<code>$ cat <<'EOF' | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: simple
namespace: default
spec:
ingressClassName: nginx
tls:
- hosts:
- simple.jiaxzeng.com
rules:
- host: simple.jiaxzeng.com
http:
paths:
- backend:
service:
name: simple
port:
number: 80
path: /
pathType: Prefix
EOF</code>2. Verify the HTTP Ingress
<code>$ curl -k -H "Host: simple.jiaxzeng.com" https://172.139.20.100/who/hostname
simple-7b844c74dc-ptv4m
$ curl -k -H "Host: simple.jiaxzeng.com" https://172.139.20.100/who/hostname
simple-7b844c74dc-fnj2n</code>Conclusion
By following these steps, TLS/HTTPS encryption is enabled for services running on Kubernetes, improving data‑in‑transit security and enhancing user trust.
Linux Ops Smart Journey
The operations journey never stops—pursuing excellence endlessly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.