When implementing secure service-to-service communication, we often face scenarios where:
- Frontend server (Server A) requires client certificate authentication
- Backend service (Server B) needs to communicate through a local proxy
- Client certificate must be properly injected during proxy pass
For Server B's nginx configuration (acting as reverse proxy):
server {
listen 8080;
server_name localhost;
location / {
proxy_pass https://serverA.example.com:443;
proxy_ssl_certificate /path/to/client.crt;
proxy_ssl_certificate_key /path/to/client.key;
proxy_ssl_trusted_certificate /path/to/ca.crt;
proxy_ssl_verify on;
proxy_ssl_verify_depth 2;
proxy_ssl_session_reuse on;
# Optional headers
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Ensure your certificate files are in proper format:
# Convert PEM to DER if needed
openssl x509 -in client.pem -outform der -out client.crt
# Verify key file
openssl rsa -in client.key -check
When debugging SSL handshake failures:
# Check nginx error logs
tail -f /var/log/nginx/error.log
# Test connection manually
openssl s_client -connect serverA:443 -cert client.crt -key client.key -CAfile ca.crt
For more complex scenarios:
# Multiple client certificates
proxy_ssl_certificate /path/to/client_chain.pem;
# Specific SSL protocols
proxy_ssl_protocols TLSv1.2 TLSv1.3;
# Cipher suite control
proxy_ssl_ciphers HIGH:!aNULL:!MD5;
- Set proper file permissions (600 for key files)
- Regularly rotate certificates
- Monitor certificate expiration dates
- Consider using hardware security modules (HSM) for production
When implementing secure inter-server communication with mutual TLS authentication, we often encounter scenarios where an internal service needs to communicate through an Nginx proxy while presenting a client SSL certificate. The key challenge is propagating the client certificate through the proxy chain.
First, let's establish our upstream server configuration that requires client certificate authentication:
server {
listen 443 ssl;
server_name serverA.example.com;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
# Require client certificate
ssl_client_certificate /etc/nginx/ssl/ca.crt;
ssl_verify_client on;
ssl_verify_depth 2;
location / {
proxy_pass http://localhost:8000;
proxy_set_header X-Client-Cert $ssl_client_cert;
}
}
Now, let's configure the reverse proxy on Server B that will forward requests while injecting the client certificate:
server {
listen 8080;
server_name localhost;
location / {
proxy_pass https://serverA.example.com;
# SSL configuration for outbound connection
proxy_ssl_certificate /etc/nginx/ssl/client.crt;
proxy_ssl_certificate_key /etc/nginx/ssl/client.key;
# Verify upstream server's certificate
proxy_ssl_trusted_certificate /etc/nginx/ssl/ca.crt;
proxy_ssl_verify on;
proxy_ssl_verify_depth 2;
# Preserve client certificate information
proxy_set_header X-Original-Client-Cert $http_x_client_cert;
}
}
For this setup to work properly, ensure:
- The client certificate (client.crt) is signed by a CA trusted by Server A
- The Server A's certificate is trusted by Server B (for proxy_ssl_verify)
- All certificates include the full chain if necessary
When troubleshooting SSL handshake issues between the proxy and upstream server:
# Check SSL handshake details
openssl s_client -connect serverA.example.com:443 -cert client.crt -key client.key -CAfile ca.crt
# Verify Nginx error logs
tail -f /var/log/nginx/error.log
# Test proxy connectivity
curl -v http://localhost:8080 --header "X-Client-Cert: $(awk 'NF {sub(/\\r/, ""); printf "%s\\\\n",$0;}' client.crt)"
For cases where you need to pass through the original client certificate from an external client:
location / {
proxy_pass https://serverA.example.com;
proxy_ssl_certificate /etc/nginx/ssl/client.crt;
proxy_ssl_certificate_key /etc/nginx/ssl/client.key;
# Pass through the original client certificate if present
if ($http_x_ssl_cert) {
proxy_set_header X-SSL-CERT $http_x_ssl_cert;
}
}