はじめに
OpenBSD の acme-client
acme-client
は OpenBSD で標準の自動証明書管理環境 (Automatic Certificate Management Environment, ACME) のためのクライアントです。このソフトウェアは OS インストール時にインストールされます。
acme-client.conf で設定しますが、これは難しくありません。そしてそれによって Let's Encrypt や他の認証局から証明書を取得できるようになります。
基本的な使い方はこのような感じです:
# # 設定
# nvim /etc/acme-client.conf
# # 証明書の取得または (リニューアルのための) 更新
# acme-client <domain>
# # 証明書の無効化 (失効させる)
# acme-client -r <domain>
CertBot について
余談ですが、有名な他の選択肢がありますね。そうです、CertBot です。電子フロンティア財団 (Electronic Frontier Foundation, EFF) から提供されている、非常によく使われているクライアントです。pkg_add certbot
の実行でインストールすることは可能です。しかしながら、このソフトウェアを OpenBSD 環境下で使うと、証明書リニューアルの時に パーミッションの問題が発生することがあります (英語) 。
環境
使い方
acme-client.conf
の設定
OpenBSD から公式に提供されている設定ファイルがあります。それを見てみましょう。
$ cat /etc/examples/acme-client.conf
わかりやすい例が書かれています:
#
# $OpenBSD: acme-client.conf,v 1.4 2020/09/17 09:13:06 florian Exp $
#
authority letsencrypt {
api url "https://acme-v02.api.letsencrypt.org/directory"
account key "/etc/acme/letsencrypt-privkey.pem"
}
authority letsencrypt-staging {
api url "https://acme-staging-v02.api.letsencrypt.org/directory"
account key "/etc/acme/letsencrypt-staging-privkey.pem"
}
authority buypass {
api url "https://api.buypass.com/acme/directory"
account key "/etc/acme/buypass-privkey.pem"
contact "mailto:me@example.com"
}
authority buypass-test {
api url "https://api.test4.buypass.no/acme/directory"
account key "/etc/acme/buypass-test-privkey.pem"
contact "mailto:me@example.com"
}
domain example.com {
alternative names { secure.example.com }
domain key "/etc/ssl/private/example.com.key"
domain full chain certificate "/etc/ssl/example.com.fullchain.pem"
sign with letsencrypt
}
コピーして使いましょう:
$ # 初期状態では以下を実行しても何も出ない (余談)
$ ls /etc/acme-client*
$ doas cp -p /etc/examples/acme-client.conf /etc/
設定ファイルを編集しましょう:
$ doas nvim /etc/acme-client.conf
例えば以下のような内容です:
- domain example.com {
- alternative names { secure.example.com }
- domain key "/etc/ssl/private/example.com.key"
- domain full chain certificate "/etc/ssl/example.com.fullchain.pem"
- sign with letsencrypt
- }
+ domain your.domain {
+ #alternative names { secure.example.com }
+ domain key "/etc/ssl/private/your.domain.key"
+ domain full chain certificate "/etc/ssl/your.domain.fullchain.pem"
+ sign with letsencrypt
+ }
さあこれで your.domain
について "sign with letsencrypt (Let's Encrypt でサインする)" 準備が整いました。
OpenBSD httpd (Web サーバー) を起動する
httpd
が egress をリッスンしていることが必要です:
server "your.domain" {
listen on egress port 80
# ...
}
ちなみに httpd.conf
のサンプルファイルも /etc/examples/
で見付けられます。
もちろんこのデーモンを起動させておく必要があります:
$ # httpd が有効化されていない場合:
$ doas rcctl start -f httpd
$ # 有効化されている場合:
$ doas rcctl restart httpd
証明書をリクエストする
以下の一行のコマンドを実行するだけです。そうすればうれしいことに証明書を取得できます:
$ doas acme-client -v your.domain
ここで -v
は verbose 出力のためのもので、省略可能です。
他の使い方もあります。更新は次のように行います:
$ # 上と同じコマンド
$ doas acme-client your.domain
さらに証明書を失効させることもできます:
$ doas acme-client -r your.domain
補足
定期的な更新が必要
Let's Encrypt 証明書の有効期間は 90 日間しか無いことを憶えておきましょう。定期的に更新する必要があります。
対応策の一つに cron
の使用が考えられます。
Let's Encrypt には制限 (Rate Limits) が存在する
Let's Encrypt にはいくつかのレート制限があることに注意してください。
一例ですが、
- "Certificates per Registered Domain" (登録ドメインごとの証明書)。1 週間あたり 50 件までです。
また他の例ですが、
- "Duplicate Certificate" (証明書の重複)。同じ証明書を更新できるのは 1 週間に最大 4 回 (合計で 5 回) までです。
これらに関わる公式ドキュメントは こちら (英語) です。
サイド・ストーリー: 歴史と経緯
acme-client は初めて登場したのは 6.1 のリリースでした。
6.5 あるいはそれ以前 (ただし 6.1 以降) では、証明書取得のために指定しなければならないコマンドオプションの数が、現在よりも多かったです:
$ doas acme-client -ADv your.domain
しかし 6.6 で acme-client が v02 Let's Encrypt API とやり取りできるようになりました。それによって -A
および -D
オプションは不要になったのです。ありがたい改善です。
トラブルシューティング: チャレンジが失敗した場合
以下のようなエラーが出て、失敗に終わり悲しい思いをすることがあるかもしれません:
acme-client: /etc/ssl/private/your.domain: generated RSA domain key
acme-client: https://acme-v02.api.letsencrypt.org/directory: directories
acme-client: acme-v02.api.letsencrypt.org: DNS: xxx.xxx.xxx.xxx
acme-client: dochngreq: https://acme-v02.api.letsencrypt.org/acme/authz-v3/84303399960
acme-client: challenge, token: (...), uri: https://acme-v02.api.letsencrypt.org/acme/chall-v3/84303399960/MQGXJQ, status: 0
acme-client: /var/www/acme/(...): created
acme-client: https://acme-v02.api.letsencrypt.org/acme/chall-v3/84303399960/MQGXJQ: challenge
acme-client: order.status 0
acme-client: dochngreq: https://acme-v02.api.letsencrypt.org/acme/authz-v3/84303399960
acme-client: challenge, token: (...), uri: https://acme-v02.api.letsencrypt.org/acme/chall-v3/84303399960/MQGXJQ, status: -1
acme-client: order.status -1
acme-client: dochngreq: https://acme-v02.api.letsencrypt.org/acme/authz-v3/84303399960
acme-client: Invalid response from http://your.domain/.well-known/acme-challenge/(...) [2606:4700:3031::6815:3ae6]: \\"\\u003c!DOCTYPE html\\u003e\\\\n\\u003chtml\\u003e\\\\n\\u003chead\\u003e\\\\n\\u003cmeta charset=\\\\\\"utf-8\\\\\\"\\u003e\\\\n\\u003ctitle\\u003e404 Not Found\\u003c/title\\u003e\\\\n\\u003cstyle type=\\\\\\"text/css\\\\\\"\\u003e\\u003c!--\\\\nbody { background-\\"
acme-client: bad exit: netproc(87417): 1
これは 404 つまり ページが見付かりません エラーです。別のケースもあります。403 つまり アクセスが拒否されました エラーです。
これらはあなたの Web サーバーが "不正なレスポンス (bad response)" を返したことによるものです。チャレンジに対するレスポンスを正しくマッピングしてあげましょう:
server "your.domain" {
listen on egress port 80
+ # acme-client
+ location "/.well-known/acme-challenge/*" {
+ root "/acme"
+ request strip 2
+ }
# ...
}
その後に httpd を再起動します:
$ # デーモンを有効化していない場合:
$ doas rcctl -f restart httpd
$ # 有効化している場合:
$ doas rcctl restart httpd
これで直るかもしれません。
# acme-client -v your.domain
以下のようなメッセージに変われば成功です:
acme-client: https://acme-v02.api.letsencrypt.org/directory: directories
acme-client: acme-v02.api.letsencrypt.org: DNS: xxx.xxx.xxx.xxx
acme-client: dochngreq: https://acme-v02.api.letsencrypt.org/acme/authz-v3/84304202350
acme-client: challenge, token: (...), uri: https://acme-v02.api.letsencrypt.org/acme/chall-v3/84304202350/NVmlRA, status: 0
acme-client: /var/www/acme/(...): created
acme-client: https://acme-v02.api.letsencrypt.org/acme/chall-v3/84304202350/NVmlRA: challenge
acme-client: order.status 0
acme-client: dochngreq: https://acme-v02.api.letsencrypt.org/acme/authz-v3/84304202350
acme-client: challenge, token: (...), uri: https://acme-v02.api.letsencrypt.org/acme/chall-v3/84304202350/NVmlRA, status: 2
acme-client: order.status 1
acme-client: https://acme-v02.api.letsencrypt.org/acme/finalize/58118741/68735636600: certificate
acme-client: order.status 3
acme-client: https://acme-v02.api.letsencrypt.org/acme/cert/(...): certificate
acme-client: /etc/ssl/your.domain: created
おわりに
Let's Encrypt の証明書を取得できました ! あとはそれを httpd.conf
で設定するだけです。
server "your.domain" {
listen on * port 80
# acme-client
location "/.well-known/acme-challenge/*" {
root "/acme"
request strip 2
}
+ block return 301 "https://$SERVER_NAME$REQUEST_URI"
}
+ server "your.domain" {
+ listen on * tls port 443
+ tls {
+ certificate "/etc/ssl/your.domain.fullchain.pem"
+ key "/etc/ssl/private/your.domain.key"
+ }
+ # acme-client
+ location "/.well-known/acme-challenge/*" {
+ root "/acme"
+ request strip 2
+ }
+ # ...
+ }
ここで、私は egress
を *
に変更しました。これは lo
にも適用したかったからです。必須の変更ではありません。
暗号化による TLS 接続すなわち HTTPS 通信の基盤が完成しました。
Happy connecting securely🕊