Nginx SSL快速雙向認證配置(指令碼)

來源:互聯網
上載者:User
這篇文章主要介紹了關於Nginx SSL快速雙向認證配置(指令碼),有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下

目前遇到一個項目有安全性要求,要求只有個別使用者有許可權訪問。本著能用配置解決就絕不用代碼解決的原則,在Nginx上做一下限制和修改即可。

這種需求其實實現方式很多,經過綜合評估考慮,覺得SSL雙向認證方案對使用者使用最簡單,遂決定用此方案。

: 本方案在Ubuntu Server 16.04 LTS實施,其他動作系統請酌情修改

SSL雙向認證

絕大多數SSL應用都以單向認證為主,即用戶端只要信任服務端,就可以使用服務端的公開金鑰加密後向服務端發起請求,由服務端的私密金鑰解密之後獲得請求資料。

如果這個過程反過來,讓服務端信任用戶端,服務端使用用戶端的公開金鑰加密之後將資料返回給用戶端,其實也是可以做到的,原理和實現跟單向認證都差不多。

服務端信任用戶端的操作往往也會伴隨著用戶端認證服務端的過程,所以讓服務端信任用戶端的SSL認證方式往往也被稱為SSL雙向認證,並且要配置SSL雙向認證必須先開啟服務端SSL,先配置用戶端信任服務端。

Nginx的SSL雙向認證配置

第一步 開啟https訪問

根據理論知識,我們必須先開啟Nginx的SSL配置,即啟用https。這個過程較為簡單,目前有let's encrypt這種免費的認證方案,再也不用發愁自己搭建CA自簽了。申請免費認證的過程略過,直接貼啟用https的配置:

server {  listen 80;  listen 443 ssl http2;  server_name example.com;  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;  # 只有Nginx >= 1.13.0 版本才支援TLSv1.3協議  # ssl_protocols TLSv1.3;  # Nginx低於1.13.0版本用這個配置  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;  ssl_prefer_server_ciphers on;   ssl_dhparam dhparam.pem; # openssl dhparam -out /etc/nginx/dhparam.pem 4096  ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';  ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0  ssl_session_timeout  10m;  ssl_session_cache shared:SSL:10m;  ssl_session_tickets off; # Requires nginx >= 1.5.9  ssl_stapling on; # Requires nginx >= 1.3.7  ssl_stapling_verify on; # Requires nginx => 1.3.7  resolver 223.5.5.5 114.114.114.114 valid=300s;  resolver_timeout 5s;   # 啟用HSTS的配置,如果你的網域名稱下還有非標準連接埠訪問的http應用,請勿啟用HSTS  # add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";  # 下面這個配置會拒絕Frame標籤內容,請確認你的網站沒有frame / iframe  add_header X-Frame-Options DENY;  add_header X-Content-Type-Options nosniff;  add_header X-XSS-Protection "1; mode=block";  # 為了let's encrypt續期用,不用let's encrypt不需要這個location  location /.well-known {    root /usr/share/nginx/html;  }   ... SNIP ...  # 強制http跳轉為https  if ($scheme != "https") {    return 301 https://$http_host$request_uri;  }}
以上那一大堆ssl的配置參考來自於: https://cipherli.st/ 加強SSL的安全性配置

特別注意最後的強制https跳轉,我們的目的是SSL雙向認證,不走https無任何意義,所以必須強制跳轉https。

第二步 產生用戶端認證並簽證(指令碼)

這個過程詳細描述的文章太多了,這裡就不囉嗦介紹openssl和簽證過程了,本篇內容是快速產生雙向認證配置的認證,所以直接貼指令碼就行了,命令都是參考互連網上各種openssl雙向配置文檔,在此基礎之上進行了命令上的簡化與非互動支援。

整個目錄結構:

# tree /etc/nginx/ssl_certs//etc/nginx/ssl_certs/├── create_ca_cert.sh├── create_client_cert.sh├── revoke_cert.sh0 directories, 3 files

自行建立/etc/nginx/ssl_certs/,放入三個指令碼,分別用於產生CA認證以及CA目錄(create_ca_cert.sh指令碼的作用,只有第一次需要運行),建立用戶端認證,並用CA認證簽證(create_client_cert.sh指令碼的作用,必須先產生CA認證),revoke_cert.sh指令碼用於吊銷認證,需要收回許可權的時候可以使用。

每個指令碼內容如下:

  • create_ca_cert.sh

#!/bin/bash -e# 建立CA根憑證# 非互動式方式建立以下內容:# 國家名(2個字母的代號)C=CN# 省ST=Shannxi# 市L=Xian# 公司名O=My Company# 組織或部門名OU=技術部# 伺服器FQDN或頒發者名CN=www.example.com# 郵箱地址emailAddress=admin@example.commkdir -p ./demoCA/{private,newcerts}touch ./demoCA/index.txt[ ! -f ./demoCA/seria ] && echo 01 > ./demoCA/serial[ ! -f ./demoCA/crlnumber ] && echo 01 > ./demoCA/crlnumber[ ! -f ./demoCA/cacert.pem ] && openssl req -utf8 -new -x509 -days 36500 -newkey rsa:2048 -nodes -keyout ./demoCA/private/cakey.pem -out ./demoCA/cacert.pem -subj "/C=${C}/ST=${ST}/L=${L}/O=${O}/OU=${OU}/CN=${CN}/emailAddress=${emailAddress}"[ ! -f ./demoCA/private/ca.crl ] && openssl ca -crldays 36500 -gencrl -out "./demoCA/private/ca.crl"
  • create_client_cert.sh

#!/bin/bash -eshow_help() {    echo "$0 [-h|-?|--help] [--ou ou] [--cn cn] [--email email]"    echo "-h|-?|--help    顯示協助"    echo "--ou            設定組織或部門名,如: 技術部"    echo "--cn            設定FQDN或所有者名,如: 馮宇"    echo "--email         設定FQDN或所有者郵件,如: fengyu@example.com"}while [[ $# -gt 0 ]]do    case $1 in        -h|-\?|--help)            show_help            exit 0            ;;        --ou)            OU="${2}"            shift            ;;                --cn)            CN="${2}"                        shift            ;;        --email)            emailAddress="${2}"                        shift            ;;        --)            shift            break        ;;        *)            echo -e "Error: $0 invalid option '$1'\nTry '$0 --help' for more information.\n" >&2            exit 1        ;;    esacshiftdone# 建立用戶端認證# 非互動式方式建立以下內容:# 國家名(2個字母的代號)C=CN# 省ST=Shannxi# 市L=Xian# 公司名O=My Company# 組織或部門名OU=${OU:-測試部門}# 伺服器FQDN或授予者名CN=${CN:-demo}# 郵箱地址emailAddress=${emailAddress:-demo@example.com}mkdir -p "${CN}"[ ! -f "${CN}/${CN}.key" ] && openssl req -utf8 -nodes -newkey rsa:2048 -keyout "${CN}/${CN}.key" -new -days 36500 -out "${CN}/${CN}.csr" -subj "/C=${C}/ST=${ST}/L=${L}/O=${O}/OU=${OU}/CN=${CN}/emailAddress=${emailAddress}"[ ! -f "${CN}/${CN}.crt" ] && openssl ca -utf8 -batch -days 36500 -in "${CN}/${CN}.csr" -out "${CN}/${CN}.crt"[ ! -f "${CN}/${CN}.p12" ] && openssl pkcs12 -export -clcerts -CApath ./demoCA/ -inkey "${CN}/${CN}.key" -in "${CN}/${CN}.crt" -certfile "./demoCA/cacert.pem" -passout pass: -out "${CN}/${CN}.p12"
  • revoke_cert.sh

#!/bin/bash -e# 吊銷一個簽證過的認證openssl ca -revoke "${1}/${1}.crt"openssl ca -gencrl -out "./demoCA/private/ca.crl"

簡單分析一波指令碼,首先是建立CA,對於Ubuntu系統來說,/etc/ssl/openssl.cnf配置中預設的CA路徑就是./demoCA,為了不改動預設配置,直接按照預設配置的內容建立這些目錄和檔案即可。還有就是openssl子命令非常多,但是也和git一樣,可以合并命令,比如用一條命令同時產生私密金鑰和簽證請求openssl req -nodes -newkey rsa:2048 -keyout client.key -new -out client.csr,在req的同時就做了genrsa。由於建立CA指令碼只是第一次運行需要,因此把認證配置直接寫死在指令碼中就完事了。

接下來是建立用戶端認證,為了簡化使用者的使用,在服務端協助使用者產生認證並簽證,把簽證過的認證下發給使用者就可以了。由於使用者可能是不同部門,不同姓名,不同郵件地址,因此將這三個參數外部化,做一下參數解析,加上友好的命令列提示防止遺忘。這個指令碼特別注意最後一行,會產生一個PKCS12格式的認證。openssl預設產生的認證格式都是PEM的,會將公開金鑰和私密金鑰分開,但是瀏覽器匯入的時候需要將這些內容合并起來形成憑證鏈結,所以需要將簽證過的認證和私密金鑰檔案合并成一個PKCS12格式的認證,直接將這個.p12格式的認證交給使用者就可以了。

最後是吊銷認證了,當希望收回某個使用者的存取權限時,直接運行這個指令碼跟上目錄名就可以了。

接下來運行建立CA的指令碼:

./create_ca_cert.shGenerating a 2048 bit RSA private key.......................+++........................................................................................................+++writing new private key to './demoCA/private/cakey.pem'-----Using configuration from /usr/ssl/openssl.cnf

此時產生的./demoCA目錄結構如下:

demoCA/├── cacert.pem├── crlnumber├── crlnumber.old├── index.txt├── newcerts├── private│   ├── ca.crl│   └── cakey.pem└── serial2 directories, 7 files

此時就可以配置nginx了,在上面單向ssl的配置中,追加以下配置:

  ssl_client_certificate ssl_certs/demoCA/cacert.pem;  ssl_crl ssl_certs/demoCA/private/ca.crl;  ssl_verify_client on;

ssl_client_certificate就是用戶端認證的CA認證了,代表此CA簽發的認證都是可信的,ssl_verify_client on;代表強制啟用用戶端認證,非法用戶端(無認證,認證不可信)都會返回400錯。

特別注意ssl_crl這個配置,代表Nginx會讀取一個CRL(Certificate Revoke List)檔案,之前說過,可能會有收回使用者權限的需求,因此我們必須有吊銷認證的功能,產生一個CRL檔案讓Nginx知道哪些認證被吊銷了即可。

注意: Nginx配置都是靜態,讀取設定檔之後都會載入到記憶體中,即使檔案內容變化也不會重新讀取。因此當CRL檔案發生變更之後,Nginx並不能意識到有新的認證被吊銷了,所以必須使用 reload指令讓Nginx重新讀取設定檔: service nginx reloadnginx -s reload

此時重啟Nginx服務,就可以完成SSL雙向認證配置了。

我們簽發一個認證看看:

 ./create_client_cert.sh --ou 財務部 --cn 財務經理 --email cy@example.comGenerating a 2048 bit RSA private key................................+++.............................................................................+++writing new private key to '財務經理/財務經理.key'-----Using configuration from /usr/ssl/openssl.cnfCheck that the request matches the signatureSignature okCertificate Details:        Serial Number: 1 (0x1)        Validity            Not Before: Jun 14 16:03:46 2018 GMT            Not After : May 21 16:03:46 2118 GMT        Subject:            countryName               = CN            stateOrProvinceName       = Shannxi            organizationName          = My Company            organizationalUnitName    = \U8D22\U52A1\U90E8            commonName                = \U8D22\U52A1\U7ECF\U7406            emailAddress              = cy@example.com        X509v3 extensions:            X509v3 Basic Constraints:                CA:FALSE            Netscape Comment:                OpenSSL Generated Certificate            X509v3 Subject Key Identifier:                B5:91:0B:1F:FC:25:3B:2A:F9:EF:39:39:51:E3:1F:64:78:8A:C3:75            X509v3 Authority Key Identifier:                keyid:86:55:76:15:A3:F5:58:CB:8F:39:A3:56:8E:FF:18:97:AE:27:60:0FCertificate is to be certified until May 21 16:03:46 2118 GMT (36500 days)Write out database with 1 new entriesData Base Updatedtree 財務經理/財務經理/├── 財務經理.crt├── 財務經理.csr├── 財務經理.key└── 財務經理.p120 directories, 4 files

這個指令碼產生了私密金鑰檔案key,簽證請求檔案csr,經過CA簽證後的認證檔案crt(裡面沒有私密金鑰),以及將crt檔案和key進行bundle之後的PKCS12格式的認證檔案p12,將p12檔案下載到本地,雙擊一路Next匯入認證即可。

: 由於CA的認證檔案不會發生變化,因此簽證新的用戶端認證不需要restart或reload nginx

這次開啟我們的網站https://www.example.com,瀏覽器就會提示我們選擇一個已有的用戶端認證進行認證了,沒問題就可以看到網站內容了

: 每次匯入新的認證之後,必須重啟瀏覽器才能提示使用新的認證檔案

按照這種方式,有多少人需要授權,就可以用這個指令碼簽發多少個這樣的認證,使用者將p12認證匯入本地就可以正常訪問網站了。

當我們需要收回某人的許可權的時候(比如離職了),我們需要吊銷他的認證:

 ./revoke_cert.sh 財務經理Using configuration from /usr/ssl/openssl.cnfRevoking Certificate 01.Data Base UpdatedUsing configuration from /usr/ssl/openssl.cnfservice nginx reload

這個指令碼會自動吊銷他的簽證檔案crt,並且自動更新CRL檔案。特別注意需要reload或restart nginx才能讓nginx重新載入CRL。這樣被撤銷憑證將無法訪問網站了。

小結

本文我們通過Nginx配置SSL雙向認證實現對用戶端的加密認證,我們使用了簡易的指令碼協助我們快速產生各種認證與簽證,免除記憶繁瑣openssl命令列,簡化使用。

當然這隻是一個最小可用集,當規模比較大的時候可能需要做很多改進,比如加入CA的web ui,直接可以操作簽證和吊銷認證,並且可以自動重啟nginx。

再比如CRL這種靜態設定檔不適合你的情境,希望的動態更新吊銷認證列表,那麼可以考慮OCSP方案,這個Nginx也是支援的,通過ssl_stapling_responder配置指定一個OCSP地址,這樣將不需要每次吊銷認證的時候都去重啟nginx了,openssl也提供了ocsp服務端的功能,這裡就不贅述了,可以自行尋找相關資料。

以上就是本文的全部內容,希望對大家的學習有所協助,更多相關內容請關注topic.alibabacloud.com!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.