From Simple HTTPS to Enterprise‑Grade mTLS: Build a Secure Nginx Infrastructure
This guide explains why HTTPS only encrypts traffic while mTLS authenticates both parties, and provides a step‑by‑step solution—including environment setup, CA design, certificate generation, Nginx mutual‑TLS configuration, role‑based access, Kubernetes deployment, logging, and best‑practice recommendations—to create a production‑ready, enterprise‑level security infrastructure.
1. Environment Preparation
Required software: Nginx ≥ 1.14, OpenSSL ≥ 1.1.1, and a Linux/Unix system.
Create the directory hierarchy for certificates:
mkdir -p /etc/nginx/ssl/{ca,server,client}2. Certificate Authority Design (CA Standardization)
In production you need a full CA directory structure:
mkdir -p /etc/nginx/ssl/ca/{certs,crl,newcerts,private}
chmod 700 /etc/nginx/ssl/ca/private
touch /etc/nginx/ssl/ca/index.txt
echo 1000 > /etc/nginx/ssl/ca/serialKey openssl.cnf snippet:
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = /etc/nginx/ssl/ca
database = $dir/index.txt
new_certs_dir = $dir/newcerts
certificate = $dir/ca.crt
serial = $dir/serial
private_key = $dir/private/ca.key
default_md = sha256
policy = policy_any
[ policy_any ]
commonName = suppliedWith this layout you gain certificate tracking, revocation capability, and auditability.
3. Certificate Generation
3.1 Create the Root CA
openssl genrsa -out ca/ca.key 4096
openssl req -new -x509 -days 3650 \
-key ca/ca.key \
-out ca/ca.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/OU=CA/CN=MyRootCA"3.2 Server Certificate
openssl genrsa -out server/server.key 2048
openssl req -new -key server/server.key \
-out server/server.csr \
-subj "/C=CN/O=MyCompany/OU=Web/CN=server.example.com"
openssl x509 -req -days 365 \
-in server/server.csr \
-CA ca/ca.crt \
-CAkey ca/ca.key \
-CAcreateserial \
-out server/server.crt \
-extfile <(printf "subjectAltName=DNS:server.example.com,IP:127.0.0.1")3.3 Client Certificate
openssl genrsa -out client/client.key 2048
openssl req -new -key client/client.key \
-out client/client.csr \
-subj "/C=CN/O=MyCompany/OU=Client/CN=client1"
openssl x509 -req -days 365 \
-in client/client.csr \
-CA ca/ca.crt -CAkey ca/ca.key \
-CAcreateserial -out client/client.crtExport the client certificate for browsers:
openssl pkcs12 -export \
-inkey client/client.key \
-in client/client.crt \
-out client/client.p12 \
-password pass:ChangeMe1234. Nginx Mutual‑TLS Configuration
server {
listen 443 ssl;
server_name server.example.com;
ssl_certificate /etc/nginx/ssl/server/server.crt;
ssl_certificate_key /etc/nginx/ssl/server/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_client_certificate /etc/nginx/ssl/ca/ca.crt;
ssl_verify_client on;
ssl_verify_depth 2;
location / {
if ($ssl_client_verify != SUCCESS) { return 401; }
proxy_set_header X-SSL-Client-DN $ssl_client_s_dn;
proxy_set_header X-SSL-Client-Verify $ssl_client_verify;
root /var/www/html;
}
}
# Force HTTPS
server {
listen 80;
return 301 https://$host$request_uri;
}5. Certificate‑Based Role Model
Define Organizational Units (OU) as role identifiers:
Client → ordinary client → access /api Admin → administrator → access /admin Ops → operations → access /ops Gateway → gateway → unrestricted
Map OU to a role header in Nginx:
map $ssl_client_s_dn $client_role {
default "none";
~OU=Admin "admin";
~OU=Client "client";
~OU=Ops "ops";
}
proxy_set_header X-Client-Role $client_role;6. Prevent Certificate Copy Attacks (Cert + IP Binding)
map $ssl_client_s_dn $allowed_ip {
default "";
"CN=client1,OU=Client,O=MyCompany" 10.0.0.5;
}
if ($remote_addr != $allowed_ip) { return 403; }7. Path‑Specific Authentication Levels
location /public { ssl_verify_client off; }
location /admin { ssl_verify_client on; }8. Certificate Lifecycle Management Model
9. Kubernetes Scenario
kubectl create secret generic mtls-cert \
--from-file=client.crt \
--from-file=client.key \
--from-file=ca.crtMount the secret in a pod:
volumeMounts:
- name: mtls
mountPath: /etc/ssl
volumes:
- name: mtls
secret:
secretName: mtls-cert10. Logging and Auditing
log_format ssl_log '$remote_addr [$time_local] '
'ClientVerify:$ssl_client_verify DN:$ssl_client_s_dn';
access_log /var/log/nginx/ssl_access.log ssl_log;11. Security Best Practices
Private key permissions: chmod 600 One certificate per client
Enable CRL/OCSP for revocation
Rotate client certificates every 3‑6 months
Prefer TLS 1.3
12. Position of Mutual TLS in the Security Stack
HTTPS provides encryption, mTLS supplies machine‑level identity, tokens handle session identity, and OAuth2 manages user authorization.
Token answers “who are you”, mTLS answers “which trusted machine are you coming from”.
13. Common Misconceptions
Do not share a single certificate; use one‑per‑client.
Always support revocation (CRL/OCSP).
Use OU to build RBAC roles.
Never trust client‑supplied headers; rely on Nginx‑injected values.
14. Final Summary
When a system reaches “multiple services + multiple clients + multiple environments”, mTLS is no longer an optional hardening measure but the foundational security layer. Without mTLS, identity is logical; with mTLS, identity is physically trusted.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Ray's Galactic Tech
Practice together, never alone. We cover programming languages, development tools, learning methods, and pitfall notes. We simplify complex topics, guiding you from beginner to advanced. Weekly practical content—let's grow together!
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.
