fbpx

HAProxy 整合 SSL/TLS Client Certificate 教學

利用 SSL Client Certificate 驗證身份ssl-https

一般網站使用 HTTPS 進行連線時,大多數的情況都是為了實現資料傳輸加密,理論上透過 2048 長度的密鑰進行 SSL 通道加密是安全的。但其實 SSL 還提供另一個功能,就是用來確認身份。我們可以透過 OpenSSL 由我們的憑證簽發一組 SSL 用戶連線憑證,可以用來確認與驗證連線來源,可以想像成是一種安全且不需要輸入密碼的身份確認機制。

我們先來介紹一下如何透過 OpenSSL 產生可以用來驗證 Client 身份的憑證,首先我們先產生一組測試用的 CA 根憑證,如果用在開放的網路環境中,這個根憑證實際上需要花錢購買,請有公證信的第三方單位來核發。

產生測試根憑證 (Root CA)

Linux 憑證習慣放在 /etc/pki 目錄中,建立 CA 根憑證命令如下:

mkdir -p /etc/pki/CA
cd /etc/pki/CA
mkdir certs crl newcerts private
chmod 700 private
touch index.txt
echo 1000 > serial
echo 1000 > crlnumber
openssl genrsa -out ./private/ca.key 4096
openssl req -new -x509 -days 365 -key ./private/ca.key -out ./certs/ca.crt

上述命令我們產生一組長度為 4096 的金鑰,基本上目前金鑰長度最少要 2048 以上才會比較安全,不容易被破解。執行過程如下:

openssl-root-ca

產生 SSL 連線中繼憑證 (Intermediate Certificate)

接著我們利用前面產生的測試根憑證,簽發一組金鑰長度為 2048 並且可以用來建立 SSL 連線的中繼憑證,命令如下:

openssl genrsa -out ./private/server.key 2048
openssl req -new -key ./private/server.key -out ./certs/server.csr
openssl x509 -req -days 365 -in ./certs/server.csr -CA ./certs/ca.crt -CAkey ./private/ca.key -set_serial 01 -out ./certs/server.crt

執行過程如下:

openssl-intermediate-certificate

建立 Web Sever 需要的 PEM 檔 (合併金鑰與證書)

由於最後要用在 HAProxy 的設定中,所以我們先產生 PEM 檔,如下:

cat ./certs/server.crt > ./certs/server.pem
cat ./private/server.key >> ./certs/server.pem

設定 HAProxy 強制檢驗 Client Certificate

接著我們來設定 HAProxy SSL 連線設定 (HAProxy 安裝教學可以參考「富人用 L4 Switch,窮人用 Linux HAProxy!」這一篇文章)。請注意,HAProxy 必須 1.5.x 之後的版本才有預設編譯 SSL Module,記得先確認版本有沒有支援 SSL。然後先編輯 /etc/haproxy/haproxy.cfg,範例如下:

global
    log /dev/log local0
    log /dev/log local1 notice
    maxconn 1024
    user haproxy
    group haproxy
    daemon
    nbproc 1
    pidfile /var/run/haproxy.pid
    tune.ssl.default-dh-param 2048

defaults
    log global
    mode http
    option httplog
    option dontlognull
    timeout server 120s
    timeout connect 120s
    timeout client 120s
    retries 2

frontend ssl_switch
    mode http
    bind :443 ssl crt /etc/pki/CA/certs/server.pem ca-file /etc/pki/CA/certs/ca.crt verify required
    default_backend service_cluster if { ssl_fc_has_crt }

backend service_cluster
    mode http
    server srv1 192.168.0.1:80 check
    server srv2 192.168.0.2:80 check

haproxy.cfg 存檔後記得 restart haproxy 命令如下:

service haproxy restart

上述的設定我們限制 SSL 連線一定要使用 Server 所簽發的憑證,也就是「verify required」這一個設定,因此在沒有憑證的狀態下連線會出現以下錯誤畫面 (Chrome 為例):

chrome-ssl-error

也可以直接透過 openssl 命令來測試 SSL 連線,輸入以下命令後由於沒有提供 Client 憑證進行連線,所以會直接被踢掉。

openssl s_client -connect 127.0.0.1:443

接著我們介紹如何簽發 SSL Client 連線憑證。

簽發 Client SSL 連線用憑證

接著我們開始簽發 Client SSL 連線憑證,這張憑證可以提供給使用者建立 SSL/TLS 連線,並且在 Server 上驗證憑證合法性。命令步驟如下:

openssl genrsa -out ./private/client.key 2048
openssl req -new -key ./private/client.key -out ./certs/client.csr
openssl x509 -req -days 365 -in ./certs/client.csr -CA ./certs/ca.crt -CAkey ./private/ca.key -set_serial 02 -out ./certs/client.crt

openssl-client-certificate

上述的過程我們會產生一張可以用來建立 SSL 連線的憑證 client.crt 與密鑰 client.key,一樣可以透過以下 openssl 命令測試 SSL 連線,執行命令如下:

openssl s_client -connect 127.0.0.1:443 -cert ./certs/client.crt -key ./private/client.key

當有給憑證進行連線就可以正確建立 SSL 通道了,不像之前會直接被踢掉。

建立傳說中的 .p12 檔

由於一般正常的使用者都是透過瀏覽器進入網站或服務 (應該沒有人用 openssl 或 open socket 這種低階方式),所以我們必須建立可以直接匯入瀏覽器的 PKCS12 格式檔案,就是傳說中的 p12 檔。一樣是透過 openssl 工具,產生的方式如下:

openssl pkcs12 -export -in ./certs/client.crt -out ./certs/client.p12 -name "Client Name" -inkey ./private/client.key

建立時會要求輸入檔案的密碼,避免檔案外流後還有一道保障。

瀏覽器設定憑證進行連線

由於我們的 Server 目前已經設定為強制驗證 SSL Client Certificate,因此我們要將上述產生的 p12 檔匯入瀏覽器才能進行連線。以 Chrome 為例,點選「設定」在下方展開「顯示進階設定...」,進入「管理憑證...」功能,如下:

chrome-ssl-ca-1

點選「匯入」,選取我們剛剛產生好的 p12 檔,匯入時要輸入密碼。

chrome-ssl-ca-2

然後 Chrome Refresh 就可以看到瀏覽器抓到適合的憑證,並且出現確認畫面:

chrome-ssl-ca-3

按下「確定」後就可以進入網站囉,如下:

chrome-ssl-ca-4

出現上述的警告畫面是正常的,因為我們 Server 使用的憑證並非第三方公證單位所簽發,所以這樣就完成囉,如果要簽發可以通過驗證的憑證,就得花錢購買(但預計 2015 年會有免費的 SSL 憑證可以使用)。關於其他的 Web Server,像是 Apache, Nginx, Tomcat 等等,設定方法也都差不多,最多差在有的 Web Server 設定 Key 與 Certificate 時,不需要合併為 PEM 檔。下期我們再分享更進階的憑證玩法,下次再見...

發佈留言