dehydrated

出自Gea-Suan Lin's Wiki
跳至導覽 跳至搜尋

dehydrated
原作者 Lukas Schauer
開發狀態 運行中
程式語言 Shell Script
許可協議 MIT license
網站 dehydrated.de
原始碼庫 github.com/lukas2511/dehydrated

dehydrated是一套支援ACME協定的軟體套件(目前主要是由Let's Encrypt提供服務)。

特色

相較於官方推廣的Certbot使用Python撰寫,dehydrated僅使用Shell Script與OpenSSLcurl的指令就可以執行,這些指令在大多數系統中都已經提供。

安裝

Ubuntu 17.10之後的版本(包含即將出版的18.04)的APT內有dehydrated[1]可以裝,但因為我自己包了一包只有執行檔的(比較小),可以透過PPA安裝:

sudo add-apt-repository -y ppa:gslin/dehydrated-lite; sudo apt update; sudo apt install -y dehydrated-lite

另外也可以直接去官方網站上下載檔案,僅需下載dehydrated檔案。我建議把這個檔案放到/usr/sbin/下。

基本設定

dehydrated在偵測到/etc/dehydrated/config/usr/local/etc/dehydrated/config時(兩個都有時前者優先),會將/etc/dehydrated或是/usr/local/etc當作設定目錄,所以我們需要產生/etc/dehydrated/config

另外因為從v0.7.0開始預設會使用secp384r1的憑證,這會導致很多舊一點的瀏覽器與爬蟲無法使用,所以指定KEY_ALGO=rsa保持相容性:

sudo mkdir -p /etc/dehydrated /var/www/dehydrated
echo "KEY_ALGO=rsa" | sudo tee /etc/dehydrated/config

進階設定

這邊的設定都是選擇性設定,進階使用者可以修改dehydrated預設值,對安全性與效能的參數進行調整。

config內可以設定開啟憑證內標示一定要開OCSP Stapling:

OCSP_MUST_STAPLE=yes

也可以設定KEYSIZE,預設是4096,可以改成2048:

KEYSIZE=2048

另外也可以指定使用ZeroSSL的CA,其中的EAB資訊xy可以在註冊ZeroSSL後從網頁界面上拿到:

CA=zerossl
EAB_HMAC_KEY=x
EAB_KID=y

域名設定

認證可以透過http-01或是dns-01的協定。無論是那種,都是在domains.txt內設定要申請的網域名稱,裡面一行就是一張憑證,一行如果有多個域名就是將這些域名申請到同一個憑證裡:

一張憑證一個域名

一行放一個域名,將需要申請的網域名稱放到domains.txt內:

cd /etc/dehydrated
echo 'blog.gslin.org' | sudo tee -a domains.txt
echo 'wiki.gslin.org' | sudo tee -a domains.txt

一張憑證多個域名

將想要放在同一張憑證的域名放在同一行,一樣是domains.txt內:

cd /etc/dehydrated
echo 'blog.gslin.org wiki.gslin.org' | sudo tee -a domains.txt

Wildcard

Wildcard的認證一定要有帶有一個主域名(沒有*),要注意Wildcard憑證無法使用http-01的驗證過程取得,只能透過dns-01取得(參考後面怎麼設定dns-01的認證):

cd /etc/dehydrated
echo 'gslin.org *.gslin.org' | sudo tee -a domains.txt

認證設定

Domain-validated certificate(即DV,非Wildcard的)的可以用http-01或是dns-01的方式認證。Wildcard的只能使用dns-01的方式認證。

http-01

dehydrated預設會用/var/www/dehydrated/作為認證目錄,需要將網頁的/.well-known/acme-challenge/指到這邊。以nginx的設定會像是這樣:

server {
    # ...

    # map /var/www/dehydrated/
    location /.well-known/acme-challenge/ {
        alias /var/www/dehydrated/;
    }
}

Apache的會是這樣(放到/etc/apache2/conf-available/dehydrated.conf內,再用a2enconf dehydrated啟用):

Alias /.well-known/acme-challenge /var/www/dehydrated
<Directory /var/www/dehydrated>
    Options None
    AllowOverride None
    Require all granted
</Directory>

dns-01

dns-01會需要使用TXT record認證。這邊會使用lexicon(不適合用pyenv安裝,因為通常使用root權限跑dehydrated,這會使得環境無法取得),這需要另外安裝。

另外dehydrated需要lexicon的examples/dehydrated.default.sh(將dehydrated的hook命令轉給lexicon使用),所以需要下載這個檔案,複製到/usr/sbin/lexicon-dehydrated.default.sh以便後續更新:

cd /tmp
git clone https://github.com/AnalogJ/lexicon.git
sudo cp lexicon/examples/dehydrated.default.sh /usr/sbin/lexicon-dehydrated.default.sh

或是直接用GitHub提供的連結下載:

cd /tmp
curl -LO https://raw.githubusercontent.com/AnalogJ/lexicon/master/examples/dehydrated.default.sh
sudo install -g root -m 0755 -o root dehydrated.default.sh /usr/sbin/lexicon-dehydrated.default.sh

執行

第一次需要同意條款:

sudo dehydrated --register --accept-terms

之後就可以用-c自動更新:

sudo dehydrated -c

如果是使用dns-01(像是Wildcard),可能需要在環境變數裡提供對應的API token(給lexicon使用):

sudo PROVIDER=digitalocean LEXICON_DIGITALOCEAN_TOKEN=x dehydrated -c -k /usr/sbin/lexicon-dehydrated.default.sh --challenge dns-01

另外因為lexicon在設定DNS的值之後,預設會停30秒才會跑下一步,會比較慢,需要等一下才會知道結果。

自動更新

上面提到更新的指令可以放到/etc/cron.weekly內執行,並且透過傳回值可以判斷是否有更新,然後重跑nginx或是Postfix(以及其他有用到的服務)。

像是:

#!/bin/bash
export PATH=/usr/sbin:/usr/bin:/bin:"${PATH}"
sleep $(expr $(printf "%d" "0x$(hostname | md5sum | cut -c 1-8)") % 86400); dehydrated -c && ( service nginx reload; service postfix reload ) > /tmp/dehydrated-lite.log-$(date -u +%Y%m%d-%H%M%S) 2>&1

或是:

#!/bin/bash
export PATH=/usr/sbin:/usr/bin:/bin:"${PATH}"
sleep $(expr $(printf "%d" "0x$(hostname | md5sum | cut -c 1-8)") % 86400); PROVIDER=digitalocean LEXICON_DIGITALOCEAN_TOKEN=x dehydrated -c -k /usr/sbin/lexicon-dehydrated.default.sh --challenge dns-01 && ( service nginx reload; service postfix reload ) > /tmp/dehydrated-lite.log-$(date -u +%Y%m%d-%H%M%S) 2>&1

其中:

  • sleep片段是為了避免一堆機器同一個時間連到Let's Encrypt的伺服器,造成類似DDoS的效果。
  • sleep後面不使用隨機變數而是使用hostnamemd5sum計算是為了隨機打散,但又要避免很湊巧一堆機器同時打Let's Encrypt的伺服器。

清理

dehydrated因為設計的關係,最快是每兩個月才會更新一次(Let's Encrypt發出來的是三個月有效,dehydrated預設只會renew少於一個月有效期的憑證),而金鑰與憑證的檔案大小一組實際佔用也才28K(用最大的4096-bit RSA整套),一台機器跑個一百年也才600組資料,算起來約16.4MB。應該是沒有太多清理的需求。

但如果還是想要清掉舊的資料,dehydrated有提供指令可以清:

sudo dehydrated -gcd

也可以考慮包裝到/etc/cron.yearly

#!/bin/bash
/usr/sbin/dehydrated -gcd

其他

這邊主要是我的個人想法,放在最後避免干擾只是想要學設定方法的讀者。

dehydrated的相依性較少,僅需BashOpenSSLcurl,這三個套件在蠻多Linux作業系統內已經內建,這對於自動化環境帶來的負擔會比較少(指的是Puppet或是Chef這類工具),同時也避免了套件版本互相影響的問題。

目前比較大的問題在於申請Wildcard certificate時,因為需要透過dns-01申請,而這常常會用到lexicon(因為其他使用Shell Script的DNS操作軟體支援度比較低)。但lexicon使用Python撰寫而引用了大量套件,這違背了使用dehydrated的本意(輕量)。

快速安裝

這邊是設定在更新後重啟nginx

sudo add-apt-repository -y ppa:gslin/dehydrated-lite; sudo apt update; sudo apt install -y cron dehydrated-lite; sudo apt clean; sudo mkdir -p /etc/dehydrated /var/www/dehydrated; echo -e "KEY_ALGO=rsa\nKEYSIZE=2048" | sudo tee /etc/dehydrated/config; sudo dehydrated --register --accept-terms; echo -e '#!/bin/bash\nexport PATH=/usr/sbin:/usr/bin:/bin:"${PATH}"\nsleep $(expr $(printf "%d" "0x$(hostname | md5sum | cut -c 1-8)") % 86400); dehydrated -c && ( service nginx reload ) > /tmp/dehydrated-lite.log-$(date -u +%Y%m%d-%H%M%S) 2>&1' | sudo tee /etc/cron.weekly/dehydrated-lite; sudo chmod 755 /etc/cron.weekly/dehydrated-lite

參考資料

外部連結