圖文:CentOS 下對 Nginx + Tomcat 配置 SSL 實現服務器 / 客戶端雙向認證

1. 安裝 nginx

1.1 nginx 包及其依賴包下載

出於模塊的依賴性,Nginx 依賴如下三個包:
html

分別下載它們的最新穩定版(截至本文最新穩定版分別是 zlib-1.2.8.tar.gz、pcre-8.36.tar.gz、openssl-fips-2.0.9.tar.gz),最後下載 Nginx 最新( http://nginx.org/en/download.html)穩定版(截至本文最新穩定版是 nginx-1.7.10.tar.gz)。
依賴包安裝次序爲:openssl、zlib、pcre,最後安裝 Nginx 包。
swift

1.2 nginx 包及其依賴包安裝

1.2.1 安裝 openssl

$ tar -zxvf openssl-fips-2.0.9.tar.gz
$ cd openssl-fips-2.0.9
$ ./config
$ make
$ sudo make install

windows

1.2.2 安裝 zlib

$ tar -zxvf zlib-1.2.8.tar.gz
$ cd zlib-1.2.8
$ ./configure
$ make
$ sudo make install

瀏覽器

1.2.3 安裝 pcre

$ tar -zxvf pcre-8.36.tar.gz
$ cd pcre-8.36
$ ./configure
$ make
$ sudo make install

tomcat

1.2.4 安裝 nginx

$ tar -zxvf nginx-1.7.10.tar.gz
$ cd nginx-1.7.10
$ ./configure --with-pcre=../pcre-8.36 --with-zlib=../zlib-1.2.8 --with-openssl=../openssl-fips-2.0.9
$ make
$ sudo make install

nginx 被默認安裝在 /usr/local/nginx 目錄。
安全

1.3 驗證 Nginx 是否安裝成功

$ sudo /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

服務器

證實 Nginx 安裝成功。


2. SSL 服務器 / 客戶端雙向驗證證書的生成

2.1 建立一個新的 CA 根證書

在 nginx 安裝目錄下新建 ca 文件夾,進入 ca,建立幾個子文件夾:
$ sudo mkdir ca
$ cd ca
$ sudo mkdir newcerts private conf server

newcerts 子目錄將用於存放 CA 簽署過的數字證書(證書備份目錄);private 用於存放 CA 的私鑰;conf 目錄用於存放一些簡化參數用的配置文件;server 存放服務器證書文件。

2.1.1 conf 目錄新建 openssl.conf 文件

編輯其內容以下:

[ ca ]
default_ca      = foo                   # The default ca section
 
[ foo ]
dir            = /usr/local/nginx/ca         # top dir
database       = /usr/local/nginx/ca/index.txt          # index file.
new_certs_dir  = /usr/local/nginx/ca/newcerts           # new certs dir
 
certificate    = /usr/local/nginx/ca/private/ca.crt         # The CA cert
serial         = /usr/local/nginx/ca/serial             # serial no file
private_key    = /usr/local/nginx/ca/private/ca.key  # CA private key
RANDFILE       = /usr/local/nginx/ca/private/.rand      # random number file
 
default_days   = 365                     # how long to certify for
default_crl_days= 30                     # how long before next CRL
default_md     = md5                     # message digest method to use
unique_subject = no                      # Set to 'no' to allow creation of
                                         # several ctificates with same subject.
policy         = policy_any              # default policy
 
[ policy_any ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = match
localityName            = optional
commonName              = supplied
emailAddress            = optional


2.1.2 生成私鑰 key 文件

$ cd /usr/local/nginx/ca
$ sudo openssl genrsa -out private/ca.key

輸出
Generating RSA private key, 512 bit long modulus
..++++++++++++
.++++++++++++
e is 65537 (0x10001)

private 目錄下有 ca.key 文件生成。

博主 20150520 加註:openssl 默認生成 512 位的。通常是用 2048 位的。

2.1.3 生成證書請求 csr 文件

$ sudo openssl req -new -key private/ca.key -out private/ca.csr
Country Name
提示輸入 Country Name,輸入 CN 並回車後:
State or Province Name
提示輸入 State or Province Name (full name),輸入 Shanghai 並回車後:
Locality Name
提示輸入 Locality Name,輸入 Shanghai 並回車後:
Organization Name
提示輸入 Organization Name,輸入 Defonds 並回車後:
Organizational Unit Name
提示輸入 Organizational Unit Name,輸入 Dev 並回車後:
Common Name
提示輸入 Common Name,若是沒有域名的話,輸入 localhost 並回車後:
Email Address

提示輸入 Email Address,輸入 defonds@163.com 並回車後:

CA口令

提示輸入 A challenge password,這個是根證書口令。輸入 defonds 並回車後:

An optional company name
提示輸入 An optional company name,輸入 df 並回車。private 目錄下有 ca.csr 文件生成。

2.1.4 生成憑證 crt 文件

$ sudo openssl x509 -req -days 365 -in private/ca.csr -signkey private/ca.key -out private/ca.crt
控制檯輸出
Signature ok
subject=/C=CN/ST=Shanghai/L=Shanghai/O=Defonds/OU=Dev/CN=localhost/emailAddress=defonds@163.com
Getting Private key

private 目錄下有 ca.crt 文件生成。

2.1.5 爲咱們的 key 設置起始序列號

$ sudo echo FACE > serial
能夠是任意四個字符

2.1.6 建立 CA 鍵庫

$ sudo touch index.txt

2.1.7 爲 "用戶證書" 的移除建立一個證書撤銷列表

$ sudo openssl ca -gencrl -out /usr/local/nginx/ca/private/ca.crl -crldays 7 -config "/usr/local/nginx/ca/conf/openssl.conf"
輸出
Using configuration from /usr/local/nginx/ca/conf/openssl.conf
private 目錄下有 ca.crl 文件生成。

2.2 服務器證書的生成

2.2.1 建立一個 key

$ sudo openssl genrsa -out server/server.key
輸出
Generating RSA private key, 512 bit long modulus
...........................++++++++++++
.................++++++++++++
e is 65537 (0x10001)

server 目錄下有 server.key 文件生成。

博主 20150520 加註:openssl 默認生成 512 位的。通常是用 2048 位的:sudo openssl genrsa -out server/server.key 2048

2.2.2 爲咱們的 key 建立一個證書籤名請求 csr 文件

$ sudo openssl req -new -key server/server.key -out server/server.csr
這時會要求你輸入和 2.1.2.2 步同樣的那些問題,全部輸入須要和那一步一致。但 A challenge password 是服務器證書口令,能夠與根證書口令一致。這裏:
服務器csr的建立
server 目錄下有 server.csr 文件生成。

2.2.3 使用咱們私有的 CA key 爲剛纔的 key 簽名

$ sudo openssl ca -in server/server.csr -cert private/ca.crt -keyfile private/ca.key -out server/server.crt -config "/usr/local/nginx/ca/conf/openssl.conf"
輸出
服務器key簽名
兩次都輸入 y,server 目錄下有 server.crt 文件生成。

2.3 客戶端證書的生成

2.3.1 建立存放 key 的目錄 users

$ sudo mkdir users
位置 /usr/local/nginx/ca/users。

2.3.2 爲用戶建立一個 key

$ sudo openssl genrsa -des3 -out /usr/local/nginx/ca/users/client.key 1024
爲用戶建立一個 key
要求輸入 pass phrase,這個是當前 key 的口令,以防止本密鑰泄漏後被人盜用。兩次輸入同一個密碼(好比我這裏輸入 defonds),users 目錄下有 client.key 文件生成。

2.3.3 爲 key 建立一個證書籤名請求 csr 文件

$ sudo openssl req -new -key /usr/local/nginx/ca/users/client.key -out /usr/local/nginx/ca/users/client.csr
Enter pass phrase
提示輸入 pass phrase,即 client.key 的口令。將 2.3.2 步保存的 pass phrase 輸入後並回車:
將 2.3.2 步輸入的密碼輸入後並回車
要求你輸入和 2.1.3 步同樣的那些問題。輸入須要和那一步一致。但 A challenge password 是客戶端證書口令(請注意將它和 client.key 的口令區分開!),能夠與服務器端證書或者根證書口令一致:
爲 key 建立一個證書籤名請求 csr 文件
users 目錄下有 client.csr 文件生成。

2.3.4 使用咱們私有的 CA key 爲剛纔的 key 簽名

$ sudo openssl ca -in /usr/local/nginx/ca/users/client.csr -cert /usr/local/nginx/ca/private/ca.crt -keyfile /usr/local/nginx/ca/private/ca.key -out /usr/local/nginx/ca/users/client.crt -config "/usr/local/nginx/ca/conf/openssl.conf"
輸出
Using configuration from /usr/local/nginx/ca/conf/openssl.conf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'CN'
stateOrProvinceName   :PRINTABLE:'Shanghai'
localityName          :PRINTABLE:'Shanghai'
organizationName      :PRINTABLE:'Defonds'
organizationalUnitName:PRINTABLE:'Dev'
commonName            :PRINTABLE:'localhost'
emailAddress          :IA5STRING:'defonds@163.com'
Certificate is to be certified until Mar 16 11:47:48 2016 GMT (365 days)
Sign the certificate? [y/n]:y

1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

兩次都輸入 y,users 目錄下有 client.crt 文件生成。

2.3.5 將證書轉換爲大多數瀏覽器都能識別的 PKCS12 文件

$ sudo openssl pkcs12 -export -clcerts -in /usr/local/nginx/ca/users/client.crt -inkey /usr/local/nginx/ca/users/client.key -out /usr/local/nginx/ca/users/client.p12
Enter pass phrase for
要求輸入 client.key 的 pass phrase,輸入 2.3.2 步輸入的 pass phrase 並回車後:
Enter Export Password

要求輸入 Export Password,這個是客戶端證書的保護密碼(其做用相似於 2.3.3 保存的口令),在客戶端安裝證書的時候須要輸入這個密碼。我仍是輸入 defonds。users 目錄下有 client.p12 文件生成。


3. Nginx 配置

SSL 的目的是爲了保證網絡通訊的安全以及數據完整性。因此,若是 tomcat 前面有了 nginx 做爲反向代理,那就沒有理由再在 nginx 和 tomcat 之間進行加密傳輸,畢竟兩者處於同一內網。
tt
如上圖所示,客戶端經過 SSL 請求過來的訪問被反向代理 nginx 接收,nginx 結束了 SSL 並將請求以純 HTTP 提交 tomcat。nginx 配置 nginx.conf 以下:

worker_processes  1;

error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '[$time_local] $remote_addr - "$request" '
                      '$status "$http_user_agent" '
                      '"$args"';

    access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  120;
    client_max_body_size    120m;
    client_body_buffer_size 128k;
    server_names_hash_bucket_size 128;
    large_client_header_buffers 4 4k;
    open_file_cache max=8192 inactive=20s;
    open_file_cache_min_uses 1;
    open_file_cache_valid 30s;

	upstream tomcat_server {
	# Tomcat is listening on default 8080 port
        server 192.168.1.177:8080 fail_timeout=0;
    }

    server {
        listen       443;
        server_name  localhost;
        ssi on;
        ssi_silent_errors on;
        ssi_types text/shtml;

        ssl                  on;
        ssl_certificate      /usr/local/nginx/ca/server/server.crt;
        ssl_certificate_key  /usr/local/nginx/ca/server/server.key;
        ssl_client_certificate /usr/local/nginx/ca/private/ca.crt;

        ssl_session_timeout  5m;
        ssl_verify_client on;  #開戶客戶端證書驗證

        ssl_protocols  SSLv2 SSLv3 TLSv1;
        ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
        ssl_prefer_server_ciphers   on;
        
        charset utf-8;
		access_log  logs/host.access.log  main;

		#error_page  404              /404.html;

		# redirect server error pages to the static page /50x.html
		#

		error_page   500 502 503 504  /50x.html;
		location = /50x.html {
				root   html;
		}
		location = /favicon.ico {
				log_not_found off;
				access_log off;
				expires      90d;
		}
		location /swifton/ {
				proxy_pass http://tomcat_server;
				include proxy.conf;
		}      

    }
}


其中,tomcat(本例中和 nginx 部署同臺機器) 是 nginx 同一局域網段的,swifton 是測試 tomcat 項目。proxy.conf 內容:

proxy_redirect   off;
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_connect_timeout 60;
proxy_read_timeout 600;
proxy_set_header   X-Forwarded-Proto $scheme;



4. Tomcat 配置

Nginx 反向代理 HTTP 不須要更改 Tomcat 配置。與 HTTP 代理不一樣的是,這裏須要經過更改 tomcat 的配置文件來告訴它前面的 HTTPS 代理。將 %tomcat%/conf/ 如下部分:

<Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" />


修改成

<Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443"
			   scheme="https"
			   proxyName="localhost"
			   proxyPort="443" />



5. 配置驗證

5.1 Tomcat 重啓驗證

重啓 tomcat,後臺日誌沒問題,也能夠看到小貓界面。

5.2 Nginx 重啓驗證

先關閉運行中的 nginx,若是你已經開啓了的話。
$ sudo ./nginx -t
輸出
nginx: [emerg] unknown directive "ssl" in /usr/local/nginx/conf/nginx.conf:50
nginx: configuration file /usr/local/nginx/conf/nginx.conf test failed

ssl 模塊沒有編譯進來。
切換到步驟 1.2.4 裏的 nginx 安裝目錄 nginx-1.7.10,
$ ./configure --with-pcre=../pcre-8.36 --with-zlib=../zlib-1.2.8  --with-http_ssl_module
$ sudo make
$ sudo make install

Nginx 重裝成功。再次
$ sudo ./nginx -t
提示測試成功。
啓動 nginx。

5.3 客戶訪問 ssl 驗證

谷歌瀏覽器使用 https 訪問原有項目 https://192.168.1.177/swifton,177 是 Nginx 所在服務器,提示 400 Bad Request(No required SSL certificate was sent):
400 Bad Request
這是由於 https 雙向驗證須要客戶端安裝證書。windows os 下拿到步驟 2.3.5 生成的證書 client.p12,直接雙擊它,進入 "證書導入嚮導":
歡迎使用證書導入嚮導
點擊 "下一步":
指定要導入的文件
"要導入的文件" 已經爲咱們選好了,點擊 "下一步":
私鑰保護
"私鑰保護" 對話框輸入 2.3.5 步的 Export Password,點擊 "下一步":
證書存儲
"證書存儲" 對話框,咱們使用 Windows 自動存儲,點擊 "下一步":
正在完成證書導入嚮導
直接點擊 "完成" 按鈕完成證書導入。
重啓谷歌瀏覽器,再次訪問 https://192.168.1.177/swifton,瀏覽器要求咱們選擇證書:
選擇證書
選中剛纔安裝好的那個證書(localhost(localhost)),點擊 "肯定",提示 "隱私設置錯誤":
隱私設置錯誤
這是由於咱們服務器用的是本身簽發的證書。選擇繼續訪問,守得雲開見月明,終於看到久違了的項目登陸頁面,成功了:
項目登陸頁面
能夠點擊瀏覽器輸入框左側的小鎖圖標查看咱們導入的客戶端證書相關信息:

證書信息


6. 雙向 SSL 驗證的集羣配置

Nginx 作負載均衡器,多臺 Tomcat 進行集羣,在雙向 SSL 驗證的環境下的配置,和純 HTTP 沒有多少差別。只需注意如下細節便可。

6.1 Nginx 配置

將步驟 3 所述 SSL 配置的如下部分

upstream tomcat_server {
	# Tomcat is listening on default 8080 port
        server 192.168.1.177:8080 fail_timeout=0;
    }


修改成

upstream tomcat_server {
	# Tomcat is listening on default 8080 port
        ip_hash;
        server 192.168.1.176:8081;
        server 192.168.1.177:8080 fail_timeout=0;
    }


便可。具體負載算法以及服務器列表依照實際狀況自行調整。

6.2 Tomcat 配置

同步驟 4 所述配置。


CentOS 下對 Nginx + Tomcat 配置 SSL 實現服務器 / 客戶端雙向認證,至此結束。本文示例所涉及安裝包 openssl-fips-2.0.9.tar.gz、pcre-8.36.tar.gz、zlib-1.2.8.tar.gz、nginx-1.7.10.tar.gz,Nginx 配置文件 nginx.conf、proxy.conf,以及 Tomcat 配置文件 server.xml 都已打包做爲博客附件上傳到 CSDN 資源,有興趣的朋友能夠去下載下來參考,下載地址:http://download.csdn.net/detail/defonds/8512071


參考資料

相關文章
相關標籤/搜索