Skip to content

Instantly share code, notes, and snippets.

@mayorova
Created August 10, 2017 14:44
Show Gist options
  • Star 38 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save mayorova/d7861790ce6957f2b0155ed7a7601498 to your computer and use it in GitHub Desktop.
Save mayorova/d7861790ce6957f2b0155ed7a7601498 to your computer and use it in GitHub Desktop.
Mutual SSL in NGINX

Securing traffic to upstream servers with client certificates

Info: https://www.nginx.com/resources/admin-guide/nginx-https-upstreams/

Creating and Signing Your Certs

Source: http://nategood.com/client-side-certificate-authentication-in-ngi

This is SSL, so you'll need an cert-key pair for you/the server, the api users/the client and a CA pair. You will be the CA in this case (usually a role played by VeriSign, thawte, GoDaddy, etc.), signing your client's certs. There are plenty of tutorials out there on creating and signing certificates, so I'll leave the details on this to someone else and just quickly show a sample here to give a complete tutorial. NOTE: This is just a quick sample of creating certs and not intended for production.

Create the CA Key and Certificate for signing Client Certs

openssl genrsa -des3 -out ca.key 4096
openssl req -new -x509 -days 365 -key ca.key -out ca.crt

Create the Server Key, CSR, and Certificate

openssl genrsa -des3 -out server.key 1024
openssl req -new -key server.key -out server.csr

Self-sign the certificate with our CA cert

openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

Create the Client Key and CSR

openssl genrsa -des3 -out client.key 1024
openssl req -new -key client.key -out client.csr

Sign the client certificate with our CA cert

openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt

Testing

Making calls to the API backend directly

curl -v -k "https://127.0.0.1:8443/hello/world"
curl -v -s -k --key client.key --cert client.crt "https://127.0.0.1:8443/hello/world"

On macOS

Issue:

curl -v -s -k --key client.key --cert client.crt "https://127.0.0.1:8443/hello/world"
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8443 (#0)
* WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure Transport. The private key must be in the Keychain.
* WARNING: SSL: Certificate type not set, assuming PKCS#12 format.
* SSL: Can't load the certificate "client.crt" and its private key: OSStatus -25299
* Curl_http_done: called premature == 0
* Closing connection 0

To solve this bundle the keys into pkcs12:

openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12 -name "client"

Then you can make the curl like this:

curl -v -s -k --cert client.p12:pass "https://127.0.0.1:8443/hello/world"

Verifying that proxy works the same way

curl -v -s "http://127.0.0.1:8080/hello/world"
worker_processes 1;
daemon off;
events {
multi_accept on;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
error_log stderr info;
# Gateway
server {
listen 8080;
server_name _;
location / {
proxy_pass https://127.0.0.1:8443;
proxy_ssl_certificate certs/client.crt;
proxy_ssl_certificate_key certs/client.key;
proxy_ssl_trusted_certificate certs/ca.crt;
proxy_ssl_verify off;
proxy_ssl_verify_depth 2;
proxy_ssl_session_reuse on;
# proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# proxy_ssl_ciphers HIGH:!aNULL:!MD5;
}
}
# Upstream
server {
listen 8443 ssl;
server_name _;
ssl_certificate certs/server.crt;
ssl_certificate_key certs/server.key;
ssl_password_file certs/password_file;
ssl_client_certificate certs/ca.crt;
# ssl_verify_client optional_no_ca; # | optional | off | on
ssl_verify_client optional_no_ca;
location / {
echo_duplicate 1 $echo_client_request_headers;
echo "\r";
echo $ssl_client_verify;
echo $ssl_client_s_dn;
echo "\r";
echo_read_request_body;
echo $request_body;
}
}
}
@webchi
Copy link

webchi commented Apr 2, 2019

Это офигенно!

@Leva-kleva
Copy link

  1. Сложность с 1024 следует изменить минимум на 2048, иначе nginx будет ругаться
  2. Также следует убрать проверку pass phrase: openssl rsa -in client.key -out client.key
    Спасибо.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment