Purpose: describe steps to configure a Nginx server and cURL as clients for a two-way verification over TLS v1.3
Updated on: Apr 18, 2020
Prerequisites:
-
A server's private key, a CA chain certificate and a server's X.509 certificate with Extended Key Usage (EKU) 'TLS Web Server Authentication' and proper 'Subject Alternative Name' like '
DNS:srv.example.com
'. -
A client's private key and X.509 certificate with EKU 'TLS Web Client Authentication'
Out of Scope: The following will not be covered
- Generating a server and a client X.509 certificates. See miniPKI
- Installing and starting a Nginx server
Test environment: This mini How-To has been tested with the following:
- Nginx/1.14.0 on Ubuntu 18.04.4 LTS
- curl 7.69.1 with OpenSSL/1.1.1f
Step 1: Combine the server's certificate with CA chain certs. The server certificate is the first:
#cat ./srv.crt ./ca-chain.pem >srv-chain.crt
Step 2: Copy the server's private key, the combined X.509 certificate to your OpenSSL's directories. You can find the OpenSSL root directory for your distribution with the command $openssl version -d
But typically it is /etc/ssl/. Run the following as root:
#mv ./srv.key /etc/ssl/private/
#mv ./srv-chain.crt /etc/ssl/certs/
#mv ./ca-chain.pem /etc/ssl/certs/
Step 3: Verify ownership and permission (the group ssl-cert
for certificate management could be different for your distro):
#chown root:ssl-cert /etc/ssl/private/srv.key
#chmod 440 /etc/ssl/private/srv.key
#chown root:ssl-cert /etc/ssl/certs/srv-chain.crt /etc/ssl/certs/ca-chain.pem
#chmod 644 /etc/ssl/certs/srv-chain.crt /etc/ssl/certs/ca-chain.pem
Step 4: Add a custom log format to /etc/nginx/nginx.conf:
http {
...
log_format ssl_client
'$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"Client fingerprint" $ssl_client_fingerprint '
'"Client DN" $ssl_client_s_dn';
...
Step 5: Configure the TLS server by creating the file /etc/nginx/conf.d/site-tls.conf with the content:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name srv.example.com;
root /var/www/tls;
# Using the custom log format:
access_log /var/log/nginx/ssl.log ssl_client;
ssl_certificate /etc/ssl/certs/srv-chain.crt;
ssl_certificate_key /etc/ssl/private/srv.key;
ssl_protocols TLSv1.2 TLSv1.3;
}
Step 6: Start the server: #systemctl start nginx
Step 7: From another host verify the TLS connectivity using
OpenSSL: openssl s_client -showcerts -connect srv.example.com:443
Connect with cURL : curl -v --cacert /etc/ssl/certs/ca-chain.pem https://srv
Step 8: For client authentication add to the file /etc/nginx/conf.d/site-tls.conf the following:
server {
....
ssl_client_certificate /etc/ssl/certs/ca-chain.pem;
ssl_verify_client on;
ssl_verify_depth 10;
....
}
- For more granular access control add to the file /etc/nginx/conf.d/site-tls.conf the following:
server {
....
# Access control -- the if needs to be outside of the location sections
# Note https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/
if ($ssl_client_fingerprint != "d2818c5263a98ca63ce0cad359f912736cc3a0ce") {
return 403;
}
....
}
- To get the client’s certificate fingerprint:
openssl x509 -in clnt.crt -noout -fingerprint
Step 9: From another host verify the two-way TLS connectivity using cURL:
curl -v --cacert /etc/ssl/certs/ca-chain.pem \
--key /etc/ssl/private/client.key --cert /etc/ssl/certs/client.crt \
https://srv
See Also: