Authenticating Users in Nginx Using Both User Password and Client Certificates

In some use cases, you want to protect different parts of a Web application with different approaches. For example, the admin related resources normally require stronger mechanism than the user related ones. The following I will show how to use Nginx with client side certificate for the resources under /admin namespace for admins, and user/name for normal users.

Generating Certificates and Keys

Bothered by SLOW Web UI to manage vSphere? Want to manage ALL your VMware vCenters, AWS, Azure, Openstack, container behind a SINGLE pane of glass? Want to search, analyze, report, visualize VMs, hosts, networks, datastores, events as easily as Google the Web? Find out more about vSearch 3.0: the search engine for all your private and public clouds.

First, let’s take a look on how to generate certificates/keys for the client, server, and CA, based on the instructions from this blog. If you want to know details on these commands, you should definitely check it out.

Note: before you started out, I would recommend you to use one password for all these commands because it would make your life easier than using multiple passwords. This is not recommended for production environment though. We also assume you’ve got nginx installed. If not yet, read this article.

# mkdir -p /etc/nginx/certs
# cd /etc/nginx/certs
# openssl genrsa -des3 -out ca.key 4096
# openssl req -new -x509 -days 365 -key ca.key -out ca.crt
# openssl genrsa -des3 -out server.key 1024
# openssl req -new -key server.key -out server.csr
# openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
# openssl genrsa -des3 -out client.key 1024
# openssl req -new -key client.key -out client.csr
# openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt

After the above commands, you should have these files in the /etc/nginx/certs directory:

root@10:/etc/nginx/certs# ls
ca.crt  ca.key  client.crt  client.csr  client.key  server.crt  server.csr  server.key

Configuring Nginx

Assume that we’ll have two resource groups: one starts /admin and the other is the rest. All these are protected under using HTTPS on port 443. To use basic authentication, you should always use HTTPS instead of HTTP which can be intercepted by a network sniffer. The user name and password are not encrypted but encoded with BASE64, which can very easily decoded.

With the resources under /admin, we’ll require CA signed client certificate. If the certificate is a valid one, it would proxy through; otherwise, it’s blocked. For the rest of the resources, it would ask for user name and password, which has been covered in my previous article. We assume there is a Tomcat server running at 8000. If not and you can change it to another server, say, http://www.doublecloud.org.

Here is the configuration which can be placed at /etc/nginx/conf.d/proxy.conf. You can change the name, but the extension should be .conf.

server
{
    ### server port and name ###
    listen          443;
    ssl             on;
 
    ### SSL log files ###
    access_log      /var/log/nginx/ssl-access.log;
    error_log       /var/log/nginx/ssl-error.log;
 
    ### SSL cert files ###
    ssl_certificate      certs/server.crt;
    ssl_certificate_key  certs/server.key;
    ssl_client_certificate  certs/ca.crt;
    ssl_verify_client   optional;
 
    ssl_protocols        SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers RC4:HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    keepalive_timeout    60;
    ssl_session_cache    shared:SSL:10m;
    ssl_session_timeout  10m;
 
    location /admin
    {
        if ($ssl_client_verify != SUCCESS) {
             return 403;
        }
 
        proxy_pass  http://127.0.0.1:8080;
 
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
 
        ### Set headers ####
        proxy_headers_hash_max_size 51200;
        proxy_headers_hash_bucket_size 6400;
        proxy_set_header        Accept-Encoding   "";
        proxy_set_header        Host            $host;
        proxy_set_header        X-Real-IP       $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
 
        proxy_set_header        X-Forwarded-Proto $scheme;
        add_header              Front-End-Https   on;
 
        proxy_redirect     off;
    }
 
    location /
    {
        auth_pam    "Secure Zone";
        auth_pam_service_name   "nginx";
        proxy_pass  http://127.0.0.1:8080;
 
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
 
        ### Set headers ####
        proxy_headers_hash_max_size 51200;
        proxy_headers_hash_bucket_size 6400;
        proxy_set_header        Accept-Encoding   "";
        proxy_set_header        Host            $host;
        proxy_set_header        X-Real-IP       $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
 
        proxy_set_header        X-Forwarded-Proto $scheme;
        add_header              Front-End-Https   on;
 
        proxy_redirect     off;
      }
}

As shown above, the ssl_verify_client is defined as optional. Within the /admin location, the following logic checks if the ssl client has been successfully verified. (see more at: http://forum.nginx.org/read.php?10,214169)

      if ($ssl_client_verify != SUCCESS) {
             return 403;
        }

Testing

After you change any nginx configuration, don’t forget to run reload command as “nginx -s reload” (sometimes it’s not enough and you need to restart it). When the new configuration takes effect, you can use curl commands to test it as follows. It assume the password for the root user is “doublecloud” and server is 192.168.8.118. Change them to yours when you run them. If you try them on another machine, you want to copy client key/cert over. You can also use browser to try out the https://192.168.8.118/.

# curl -v -s -k --key client.key --cert client.crt https://192.168.8.118/admin
# curl -v -s -k --key client.key --cert client.crt https://192.168.8.118/admin/index.html
# curl -v -s -k -u root:doublecloud https://192.168.8.118/admin/
# curl -v -s -k -u root:doublecloud https://192.168.8.118

Which of them works and which not? It’ll leave it for you to try out.

This entry was posted in Applications & Tools and tagged , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

  • NEED HELP?


    My company has created products like vSearch ("Super vCenter"), vijavaNG APIs, EAM APIs, ICE tool. We also help clients with virtualization and cloud computing on customized development, training. Should you, or someone you know, need these products and services, please feel free to contact me: steve __AT__ doublecloud.org.

    Me: Steve Jin, VMware vExpert who authored the VMware VI and vSphere SDK by Prentice Hall, and created the de factor open source vSphere Java API while working at VMware engineering. Companies like Cisco, EMC, NetApp, HP, Dell, VMware, are among the users of the API and other tools I developed for their products, internal IT orchestration, and test automation.