How to Implement Nginx Client Certificate Authentication
When we need to collaborate with outside companies to manage web site's content, admin tool site is sometimes used. So admin tool has to be exposed on the Internet network. In this case password authentication function is often used to restrict other client's access. But Nginx can also use client certificate authentication function. So I would like to introduce client certificate implementation in this article.
client certificate authentication benefits
1. Nginx can deny irrelevant user's access.
2. Nginx can revoke issued client certificate at any time.
About 1, even if username and password is not leaked, hackers try to do a brute force attack indiscriminately. So password authentication might be broken someday. Client certificate authentication doesn't allow user access who doesn't have a client certificate. This feature makes the site more secure that is exposed to the Internet Network.
About 2, Nginx administrator can revoke the client certificate to deny admin tool access from unauthorized user when outside company's contract finishes.
How to implement client certificate authentication by Nginx
Nginx server side settings
Off course root user is used when configure Nginx settings. In this example Nginx is installed under "/usr/local/nginx" directory. Please adopt below instructions to your environment properly.
1. generate CA certificate and Key
mkdir -pv /usr/local/nginx/conf/client-certificates cd /usr/local/nginx/conf/client-certificates openssl genrsa -out ca.key 2048 # set proper certificate expiration date, in this example 2 years # set site's domain name on "CN" field openssl req -new -x509 -days 730 -key ca.key -out ca.crt -subj "/C=JP/ST=Tokyo/L=Ota-ku/O=Cat Inc./OU=Development/CN=tool.toripiyo.com/emailAddress=admin@toripiyo.com"
2. generate CRL
# configure CRL for revocation settings touch /etc/pki/CA/index.txt && echo '01' > /etc/pki/CA/crlnumber openssl ca -name CA_default -gencrl -keyfile ca.key -cert ca.crt -out ca.crl -crldays 730 diff -U0 <(openssl x509 -noout -modulus -in ca.crt) <(openssl rsa -noout -modulus -in ca.key)
3. generate client certificate for each user
# In this example "toripiyo" user's client certificate is generated # Please iterate this process as you require _CLIENTNAME='toripiyo' mkdir /usr/local/nginx/conf/client-certificates/${_CLIENTNAME} cd /usr/local/nginx/conf/client-certificates/${_CLIENTNAME} openssl genrsa -out ${_CLIENTNAME}.key 2048 openssl req -new -key ${_CLIENTNAME}.key -out ${_CLIENTNAME}.csr -subj "/C=JP/ST=Tokyo/L=Ota-ku/O=Cat Inc./OU=Development/CN=${_CLIENTNAME}/emailAddress=admin@toripiyo.com" openssl x509 -req -days 365 -in ${_CLIENTNAME}.csr -CA ../ca.crt -CAkey ../ca.key -CAcreateserial -CAserial ../ca.seq -out ${_CLIENTNAME}.crt # this command execution prompts the password input. don't forget the password. the password is used for client certificate registration openssl pkcs12 -export -clcerts -in ${_CLIENTNAME}.crt -inkey ${_CLIENTNAME}.key -out ${_CLIENTNAME}.p12 # set file permission to 640 chmod 640 ${_CLIENTNAME}.* ls -lta
4. configure Nginx settings
cd /usr/local/nginx/conf cp -ivp nginx.conf{,.$(date +%Y%m%d)} vi nginx.conf # add the following directives that are related to client authentication # - set clientcert log format # - ssl_verify_client on: enable client certificate authenticate. if client certificate is not shown, access is defied. ---------------------------------------------------------------------------------------------- log_format clientcert '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for" ' '$request_time $upstream_response_time ' '"$ssl_client_s_dn($ssl_client_serial)"'; ssl_client_certificate client-certificates/ca.crt; ssl_crl client-certificates/ca.crl; ssl_verify_client on; access_log logs/host.access.log clientcert; ----------------------------------------------------------------------------------------------
5. restart Nginx
# stop Nginx daemon ps aux | grep -i nginx /etc/init.d/nginx stop ps aux | grep -i nginx less /usr/local/nginx/logs/error.log # start Nginx daemon /etc/init.d/nginx start ps aux | grep -i nginx less /usr/local/nginx/logs/error.log
typical regular operations for Nginx client certificate management
issue new client certificate for new user
If new client(tama) joins our team, issue the new client certificate by following below procedure.
1. issue client certificate _CLIENTNAME='tama' mkdir /usr/local/nginx/conf/client-certificates/${_CLIENTNAME} cd /usr/local/nginx/conf/client-certificates/${_CLIENTNAME} openssl genrsa -out ${_CLIENTNAME}.key 2048 openssl req -new -key ${_CLIENTNAME}.key -out ${_CLIENTNAME}.csr -subj "/C=JP/ST=Tokyo/L=Ota-ku/O=Cat Inc./OU=Development/CN=${_CLIENTNAME}/emailAddress=admin@toripiyo.com" openssl x509 -req -days 365 -in ${_CLIENTNAME}.csr -CA ../ca.crt -CAkey ../ca.key -CAcreateserial -CAserial ../ca.seq -out ${_CLIENTNAME}.crt # password can be put on as a openssl option directly. "doraemon" is used as a password in this case openssl pkcs12 -password doraemon -export -clcerts -in ${_CLIENTNAME}.crt -inkey ${_CLIENTNAME}.key -out ${_CLIENTNAME}.p12 # set file permission to 640 chmod 640 ${_CLIENTNAME}.* ls -lta 2.Nginx restart is not required 3. Share new client certificate with new user
revoke specific client certificate
When tama leaves our team, following procedure makes the certificate to be revoked.
1. update index.txt _CLIENTNAME='tama' cd /usr/local/nginx/conf/client-certificates openssl ca -name CA_default \ -revoke ${_CLIENTNAME}/${_CLIENTNAME}.crt \ -keyfile ca.key \ -cert ca.crt 2. update ca.crl openssl ca -name CA_default -gencrl \ -keyfile ca.key \ -cert ca.crt \ -out ca.crl \ -crldays 730 3. restart nginx ps aux | grep -i nginx /etc/init.d/nginx stop ps aux | grep -i nginx less /usr/local/nginx/logs/error.log /etc/init.d/nginx start ps aux | grep -i nginx less /usr/local/nginx/logs/error.log
reactivate the revoked certificate
If tama withdraws team leaving, following procedure makes the certificate to be reactivated.
1. modify index.txt vi /etc/pki/CA/index.txt ==================== 1. change "R" => "V" on first column of corresponding certificate row 2. delete third column characters of corresponding certificate row (important: tabs between second and fourth colomn not to be deleted!! If not, openssl outputs error message.) ==================== 2. update ca.crl cd /usr/local/nginx/conf/client-certificates openssl ca -name CA_default -gencrl \ -keyfile ca.key \ -cert ca.crt \ -out ca.crl \ -crldays 730 3. restart nginx ps aux | grep -i nginx /etc/init.d/nginx stop ps aux | grep -i nginx less /usr/local/nginx/logs/error.log /etc/init.d/nginx start ps aux | grep -i nginx less /usr/local/nginx/logs/error.log