letsencrypt-nosudoで証明書を発行する

Certbotがリリースされて早1年近く経つが、rootで実行が必要かついくつかのパッケージが自動でインストールされてしまうことを考え手が出せていなかった。
調べてみたらroot権限なしでできるツールletsencrypt-nosudoがあったので試したところ、案外うまくいった。

しかし実際は、結局root権限(tcp/80にbindする権限)が必要だったので、完全にroot不要かというとそうでもなかった。
それでもパッケージが勝手にインストールされたり、root権限でいろいろなところにファイルを作ったりという事はなかったので便利だと思った。

必要なもの

  • letsencrypt-nosudo
    • git cloneする
  • ドメイン (*1
    • 発行したいFQDNのAレコードを持っている/作れること
  • *1の80/tcpが指す先のサーバでtcp/80をListenできる権限
  • ターミナル
    • 3つ(作業用、署名用、Listen用)

手順

Terminal#1

git clone https://github.com/diafygi/letsencrypt-nosudo.git
cd letsencrypt-nosudo/

# LetsEncriptを使うために必要な非対称暗号鍵を生成する
# ここで作成した鍵はサーバにはインストールしない
openssl genrsa 4096 > user.key
openssl rsa -in user.key -pubout > user.pub

# サーバ証明書に必要な非対称暗号鍵を生成する
# ここで作成する秘密鍵はサーバにインストールする
_fqdn=www.example.com

openssl genrsa 4096 > domain.key
openssl req -new -sha256 -key domain.key -subj "/CN=${_fqdn}" > domain.csr

# 認証
# ドメイン所有者であり、かつインストールしようとしているサーバに権限があることを確認する
python sign_csr.py --public-key user.pub domain.csr > signed.crt


# スクリプトsign_csr.pyは対話的に進んでゆく

STEP 1: What is your contact email? (webmaster@${YOUR_FQDN})

更新通知を受け取るメールアドレスを入力する。

STEP 2: You need to sign some files (replace 'user.key' with your user private key).

openssl dgst -sha256 -sign user.key -out register_xxxxxx.sig register_YYYYYY.json
openssl dgst -sha256 -sign user.key -out domain_zzzzzz.sig domain_WWWWWW.json
openssl dgst -sha256 -sign user.key -out challenge_vvvvvv.sig challenge_uuuuuu.json
openssl dgst -sha256 -sign user.key -out cert_tttttt cert_ssssss.json

Press Enter when you've run the above commands in a new terminal window...

Terminal#1でEnterを押さずに、Terminal#2を開き、指示されたコマンドをそのまま実行する。

Terminal#2

# 実際にはファイルのxxxxxxやYYYYYYなどは都度異なるので、毎回指示された通りに実行すること

cd letsencrypt-nosudo/

openssl dgst -sha256 -sign user.key -out register_xxxxxx.sig register_YYYYYY.json
openssl dgst -sha256 -sign user.key -out domain_zzzzzz.sig domain_WWWWWW.json
openssl dgst -sha256 -sign user.key -out challenge_vvvvvv.sig challenge_uuuuuu.json
openssl dgst -sha256 -sign user.key -out cert_tttttt cert_ssssss.json

終わったらTerminal#1でEnterを押して進める。

Terminal#1

STEP 3: You need to sign some more files (replace 'user.key' with your user private key).

openssl dgst -sha256 -sign user.key -out response_rrrrrr.sig response_qqqqqq.json

Press Enter when you've run the above commands in a new terminal window...

こちらもSTEP 2を実行したターミナルへ、都度コマンドをC&Pして実行する。

Terminal#2

openssl dgst -sha256 -sign user.key -out response_rrrrrr.sig response_qqqqqq.json

終わったら再度Terminal#1でEnterを押して進める。

Terminal#1

STEP 4: You need to run this command on letsencrypt.daylightpirates.org (don't stop the python command until the next step).

sudo python -c "import BaseHTTPServer; \
h = BaseHTTPServer.BaseHTTPRequestHandler; \
h.do_GET = lambda r: r.send_response(200) or r.end_headers() or r.wfile.write('{\"header\": {\"alg\": \"RS256\"}, \"protected\": \"wvuTSrQpOnmlkJjHgFEDcbA\", \"payload\": \"xxxxxxxxxxxx...xxxxxxxxxxxx\", \"signature\": \"yyyyyyyyyyyy...yyy\"}'); \
s = BaseHTTPServer.HTTPServer(('0.0.0.0', 80), h); \
s.serve_forever()"

Press Enter when you've got the python command running on your server...

簡易的なHTTPサーバを立て、応答に特定の文字列を返すPythonのコマンドが提示される。
こちらも、別Terminalを起動し、実行する。

Terminal#3

# rootユーザであればsudoは必要ない

sudo python -c "import BaseHTTPServer; \
    h = BaseHTTPServer.BaseHTTPRequestHandler; \
    h.do_GET = lambda r: r.send_response(200) or r.end_headers() or r.wfile.write('{\"header\": {\"alg\": \"RS256\"}, \"protected\": \"wvuTSrQpOnmlkJjHgFEDcbA\", \"payload\": \"xxxxxxxxxxxx...xxxxxxxxxxxx\", \"signature\": \"yyyyyyyyyyyy...yyy\"}'); \
    s = BaseHTTPServer.HTTPServer(('0.0.0.0', 80), h); \
    s.serve_forever()"

プロセスを起動したらそのまま応答を待っている状態で、Terminal#1に戻り、Enterを押す。
Let'sEncryptのサーバからリクエストが来て、処理が進むはずである。
Terminal#1は正常終了し、Terminal#3はHTTPサーバが起動したままなのでCtl+Cで停止させる。


以上で作業は終了で、成功していればカレントディレクトリにdomain.csrという名前で証明書が作成されている。

中間CA証明書

これは配布されているのでwget等で取得する。

wget https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem