網站要使用 HTTPS,需要從具公信力的憑證授權單位(Certificate Authority, 簡稱 CA)取得憑證,大部分的 CA 為商業運作,需要付費購買憑證,對於個人或者是小單位,是一筆額外負擔。

Let's Encrypt 計畫基於普及 HTTPS 的使用,透過基金會贊助的方式,設立名為 Let's Encrypt 的 CA,提供免費的憑證發放服務。


使用 Certbot ACME client 自動化流程

Let's Encrypt 建議使用 EFF 的 Certbot ACME client 進行自動化流程,
Certbot 網頁 (https://certbot.eff.org) 提供各種不同網頁伺服器與作業系統的安裝說明。

CentOS/RHEL 7

Certbot 已經成為 EPEL 的套件之一,安裝 EPEL 套件庫後即可安裝。

$ sudo yum install epel-release

使用 Nginx 伺服器

直接安裝 certbot

  $ sudo yum install certbot python2-certbot-nginx

安裝 DNS plugins

DNS plugins 可用來自動獲得通用字元網域名稱憑證。要使用此功能,必須有 Certbot plugin 支援的 DNS 業者才行,詳細清單在此。安裝 plugins 時將上面的 certbot python2-certbot-nginx 改成 python2-certbot-dns-PLUGIN,PLUGIN 即為清單上有對應的 DNS 服務。

Certbot 具有 Nginx plugin,可自動獲得憑證並修改 Nginx 設定檔對應:

  $ certbot --nginx

如果不想讓 Certbot 修改 Nginx 設定檔,可使用 certonly 參數

$ certbot --nginx certonly

如果要使用 Certbot's DNS plugins 取得通用字元網域名稱對應的憑證:

$ sudo certbot -a dns-plugin -i nginx -d "*.example.com" -d example.com --server https://acme-v02.api.letsencrypt.org/directory

使用 Apache 伺服器

安裝 python-certbot-apache

  $ yum install certbot python-certbot-apache

使用 Apache Plugin 進行自動設定

  $ certbot --apache

或僅要取得憑證

certbot --apache certonly

使用 DNS plugins 方式同上。

自動更新

Let's Encrypt 憑證有效期僅為 90 天,建議設定自動更新

  $ certbot renew --dry-run
  測試成功後,可利用 cron 或 systemd 排定定期工作(官網建議一天檢查兩次)
  $ certbot renew --quiet

cron job 範例如下:

0 0,12 * * * python -c 'import random; import time; time.sleep(random.random() * 3600)' && /path/to/certbot-auto renew

Debian 8 (jessie)

因 Certbot 程式碼架構更新,原 jessie 套件庫中的 certbot 套件過於老舊,不再適用,安裝前先確認移除舊套件:

sudo apt-get remove certbot

安裝 certbot-auto script

wget https://dl.eff.org/certbot-auto
chmod a+x certbot-auto

安裝 DNS plugins

DNS plugins 可用來自動獲得通用字元網域名稱憑證。但截至 2019/03,jessie 平台尚未提供 Certbot's DNS plugins。

Nginx 伺服器

sudo /path/to/certbot-auto --nginx

執行上述 script 可取得憑證,同時自動修改 Nginx 設定檔,如果不想讓程序修改設定檔,可加入 certonly 參數:

sudo /path/to/certbot-auto --nginx certonly

自動更新

Let's Encrypt 憑證有效期僅為 90 天,建議設定自動更新

  $ ./path/to/certbot-auto renew --dry-run
  測試成功後,可利用 cron 或 systemd 排定定期工作(官網建議一天檢查兩次)
  $ ./path/to/certbot-auto renew --quiet

cron job 範例如下:

0 0,12 * * * python -c 'import random; import time; time.sleep(random.random() * 3600)' && /path/to/certbot-auto renew

運作原理

在網站伺服器上執行一個憑證管理代理程式,使用 ACME protocol 來向 Let's Encrypt CA 自動取得瀏覽器信任憑證。

分為兩個階段:

  1. 代理程式向 CA 證明網頁伺服器具有 domain 控制權。
  2. 代理程式可請求、更新、撤銷管理 domain 的憑證。

階段 1 : 網域驗證

假設網站域名為 example.com
當代理程式第一次聯繫 Let's Encrypt CA 時,會產生一組新的金鑰對供後續使用。
流程開始,代理程式詢問 CA,需要做些什麼來證明網站對 example.com 網域有控制權。
CA 將會尋找域名並要求一或數個質問挑戰,可能為:

  • 提供 example.com 下的 DNS record
  • 提供 Well-known URI https://example.com/ 下的 HTTP resource

伴隨著質問挑戰,CA 也會提供一次性隨機數(nonce)要求代理程式以私鑰簽署,以證明代理程式對金鑰對有控制權。

代理程式會回應挑戰,並在 https://example.com 網站特定路徑下建立一個檔案,同時對 CA 提供的一次性隨機數(nonce)以私鑰簽署。完成這些步驟後,便通知 CA 已準備好檢驗。

接下來便是 CA 的工作,CA 會檢驗一次性隨機數(nonce)的簽署,並嘗試從網站下載代理程式準備的檔案,確定內容正確。
一切檢查成功後,此 key pair 便會做為 example.com已驗證金鑰對

階段 2 : 發證與撤銷

有了 已驗證金鑰對 後,接下來的請求、更新、撤銷憑證動作就簡單了,只要送出使用金鑰對簽署的憑證管理請求即可。

請求憑證時,代理程式會建構一個 PKCS#10CSR(Certificate Signing Request),請求 CA 以對應公鑰發出 example.com 的憑證。

CSR 中包含以私鑰對 CSR 中公鑰的簽署,同時代理程式也會用 example.com 的驗證金鑰對整個 CSR 進行簽署。

當 Let's Encrypt CA 收到請求後,會檢查兩者,如果一切正常,將以 Public key 發出 example.com 的憑證回傳給代理程式。

撤銷憑證時,agent 以 example.com 驗證金鑰簽發撤銷請求。如果 CA 檢查正確,會將撤銷資訊發布至 撤銷 Channel 中 (CRLs, OCSP),各家的瀏覽器得以更新採用。


2019/03 更新

Docker 時代自有新的方法,可使用 Certbot docker image 取得憑證,但僅限於取得憑證本體,無法自動修改 Webserver 的設定組態。搭配 DNS TXT 記錄驗證方式,可以不用在 Webserver 執行主機上申請憑證,只要在任何一部可執行 Docker 的機器上便可申請。若要申請 Wildcard(通用字元)網域憑證,記得使用 ACMEv2 server。

底下使用 Certbot docker image 來取得 Wildcard(通用字元)對應網域憑證,使用的驗證方式為 DNS TXT 記錄,過程中會提示需要建立的 DNS TXT 記錄內容,前往 DNS 代管業者的服務設定頁面設定完成後,再會來繼續完成操作:

docker run -it --rm --name letsencrypt \
    -v "/etc/letsencrypt:/etc/letsencrypt" \
    -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
    certbot/certbot \
        certonly \
        -d example.com \
        -d *.example.com \
        --manual \
        --preferred-challenges dns \
        --server https://acme-v02.api.letsencrypt.org/directory