基於OpenSSL自建CA和頒發SSL證書
openssl是一個開源程式的套件、這個套件有三個部分組成:一是libcryto
,這是一個具有通用功能的加密庫,裡面實現了眾多的加密庫;二是libssl
,這個是實現ssl機制的,它是用於實現TLS/SSL的功能;三是openssl,是個多功能命令列工具,它可以實現加密解密,甚至還可以當CA來用,可以讓你建立證書、吊銷證書。
預設情況ubuntu和CentOS上都已安裝好openssl。CentOS 6.x 上有關ssl證書的目錄結構:
1 2 3 4 5 6 7 8 9 10 11 | /etc/pki/CA/ newcerts 存放CA簽署(頒發)過的數字證書(證書備份目錄) private 用於存放CA的私鑰 |
1. 頒發證書
1.1 修改CA的一些配置檔案
CA要給別人頒發證書,首先自己得有一個作為根證書,我們得在一切工作之前修改好CA的配置檔案、序列號、索引等等。
vi /etc/pki/tls/openssl.cnf
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | ... [ CA_default ] dir = /etc/pki/CA # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept |
一定要注意[ policy_match ]
中的設定的匹配規則,是有可能因為證書使用的工具不一樣,導致即使設定了csr中看起來有相同的countryName,stateOrProvinceName等,但在最終生成證書時依然報錯:
1 2 3 4 5 | Using configuration from /usr/lib/ssl/openssl.cnf Check that the request matches the signature Signature ok The stateOrProvinceName field needed to be the same in the CA certificate (GuangDong) and the request (GuangDong) |
touch index.txt serial
:
在CA目錄下建立兩個初始檔案:
1 2 | # touch index.txt serial # echo 01 > serial |
1.2 生成根金鑰
1 2 | # cd /etc/pki/CA/ # openssl genrsa -out private/cakey.pem 2048 |
為了安全起見,修改cakey.pem私鑰檔案許可權為600或400,也可以使用子shell生成( umask 077; openssl genrsa -out private/cakey.pem 2048 )
,下面不再重複。
1.3 生成根證書
使用req命令生成自簽證書:
1
| # openssl req -new -x509 -key private/cakey.pem -out cacert.pem
|
會提示輸入一些內容,因為是私有的,所以可以隨便輸入(之前修改的openssl.cnf會在這裡呈現),最好記住能與後面保持一致。上面的自簽證書cacert.pem
應該生成在/etc/pki/CA
下。
1.4 為我們的nginx web伺服器生成ssl金鑰
以上都是在CA伺服器上做的操作,而且只需進行一次,現在轉到nginx伺服器上執行:
1 2 | # cd /etc/nginx/ssl # openssl genrsa -out nginx.key 2048 |
這裡測試的時候CA中心與要申請證書的伺服器是同一個。
1.5 為nginx生成證書籤署請求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # openssl req -new -key nginx.key -out nginx.csr ... Country Name (2 letter code) [AU]:CN State or Province Name (full name) [Some-State]:GD Locality Name (eg, city) []:SZ Organization Name (eg, company) [Internet Widgits Pty Ltd]:COMPANY Organizational Unit Name (eg, section) []:IT_SECTION Common Name (e.g. server FQDN or YOUR name) []:your.domain.com Email Address []: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []: ... |
同樣會提示輸入一些內容,其它隨便,除了Commone Name
一定要是你要授予證書的伺服器域名或主機名,challenge password不填。
1.6 私有CA根據請求來簽署證書
接下來要把上一步生成的證書請求csr檔案,發到CA伺服器上,在CA上執行:
1 2 3 4 | # openssl ca -in nginx.csr -out nginx.crt 另外在極少數情況下,上面的命令生成的證書不能識別,試試下面的命令: # openssl x509 -req -in server.csr -CA /etc/pki/CA/cacert.pem -CAkey /etc/pki/CA/private/cakey.pem -CAcreateserial -out server.crt |
上面簽發過程其實預設使用了-cert cacert.pem -keyfile cakey.pem
,這兩個檔案就是前兩步生成的位於/etc/pki/CA
下的根金鑰和根證書。將生成的crt證書發回nginx伺服器使用。
到此我們已經擁有了建立ssl安全連線所需要的所有檔案,並且伺服器的crt和key都位於配置的目錄下,剩下的是如何使用證書的問題。
2. 使用ssl證書
2.1 一般瀏覽器
瀏覽器作為客戶端去訪問https加密的伺服器,一般不用去手動做其他設定,如https://www.google.com.hk
,這是因為Chrome、FireFox、Safari、IE等瀏覽器已經內建了大部分常用的CA的根證書,但自建CA的根證書就不再瀏覽器的信任列表中,訪問時會提示如下:
IE瀏覽器
安裝網站證書後(同時也有信任的根證書),位址列一般會顯示綠色小鎖
2.2 為linux系統新增根證書
這一步不是必須的,一般出現在開發測試環境中,而且具體的應用程式應該提供新增證書的方法。
curl
工具可以在linux上模擬傳送請求,但當它去訪問https加密網站時就會提示如下資訊:
1 2 3 4 5 6 7 8 9 10 11 12 13 | # curl https://sean:[email protected]:8000/ curl: (60) Peer certificate cannot be authenticated with known CA certificates More details here: http://curl.haxx.se/docs/sslcerts.html curl performs SSL certificate verification by default, using a "bundle" of Certificate Authority (CA) public keys (CA certs). If the default bundle file isn't adequate, you can specify an alternate file using the --cacert option. If this HTTPS server uses a certificate signed by a CA represented in the bundle, the certificate verification probably failed due to a problem with the certificate (it might be expired, or the name might not match the domain name in the URL). If you'd like to turn off curl's verification of the certificate, use the -k (or --insecure) option. |
提示上面的資訊說明curl在linux的證書信任集裡沒有找到根證書,你可以使用curl --insecure
來不驗證證書的可靠性,這隻能保證資料是加密傳輸的但無法保證對方是我們要訪問的服務。使用curl --cacert cacert.pem
可以手動指定根證書路徑。我們也可以把根證書新增到系統(CentOS 5,6)預設的bundle:
1 2 3 4 5 | # cp /etc/pki/tls/certs/ca-bundle.crt{,.bak} 備份以防出錯 # cat /etc/pki/CA/cacert.pem >> /etc/pki/tls/certs/ca-bundle.crt # curl https://sean:[email protected]:8000 "docker-registry server (dev) (v0.8.1)" |
2.3 nginx
在nginx配置檔案(可能是/etc/nginx/sites-available/default
)的server指令下新增:
1 2 3 | ssl on; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; |
同時注意 server_name 與證書申請時的 Common Name 要相同,開啟443埠。當然關於web伺服器加密還有其他配置內容,如只對部分URL加密,對URL重定向實現強制https訪問,請參考其他資料。
3 關於證書申請
注意,如果對於一般的應用,管理員只需生成“證書請求”(字尾大多為.csr),它包含你的名字和公鑰,然後把這份請求交給諸如verisign等有CA服務公司(當然,連同幾百美金),你的證書請求經驗證後,CA用它的私鑰簽名,形成正式的證書發還給你。管理員再在web server上匯入這個證書就行了。如果你不想花那筆錢,或者想了解一下原理,可以自己做CA。從ca的角度講,你需要CA的私鑰和公鑰。從想要證書的伺服器角度將,需要把伺服器的證書請求交給CA。
如果你要自己做CA,別忘了客戶端需要匯入CA的證書(CA的證書是自簽名的,匯入它意味著你“信任”這個CA簽署的證書)。而商業CA的一般不用,因為它們已經內建在你的瀏覽器中了。