Certbotでワイルドカード証明書をいただく

Infrastructure

イントラ内の証明書を一括更新したい

我が家の環境内に、いくつかWebサーバがあります。以前はオレオレ証明書を入れたり、HTTPのまま内部開放したりと言うのがやり方としてはあったんですが、悲しいかなこれらの方法だといろいろ都合が悪いところが出てきだしました。一番キッツいのは「HTTP通信だと、コピー&ペーストボタンが無効化される」です。

そこでLet’s Encryptを使って証明書をもらうのですが、私が使用しているAzure DNSとの連携で少し躓きがあったので備忘録として書いていこうかと思います。はい。

certbotを入れる前に

アプリケーションアカウントを作っておきましょう。Azure EntraIDのメニューから「エンタープライズアプリケーション」をクリックして「新しいアプリケーション」をクリックして作ってください。その際の詳細手順はここではもう省いちゃいます。

そのうち、以下の情報が必要になります。

  • アプリケーションID
  • シークレット(シークレットIDじゃなくて、値のほうが必要です)
  • サブスクリプションID
  • リソースグループ名

Certbotを入れる

まずはapt使ってsnapdを入れまする。

$ sudo apt update
$ sudo apt install -y snapd

続いてsnap環境を整備します。

$ sudo snap install core
$ sudo snap refresh core

Certbotをインストールします。

$ sudo snap install --classic certbot

certbotだけでは、Azure DNS用プラグインがありませんので、これを追加インストールします。

$ sudo snap set certbot trust-plugin-with-root=ok
$ sudo snap install certbot-dns-azure

ここで、どうやらsnapでインストールしたプラグインを接続するコマンドが必要っぽいです。snapは今回初めて使うもんで「え、そうなの?」って感じになりましてヾ(*`∀´*)ノヘヘヘッ

$ sudo snap connect certbot:plugin certbot-dns-azure

この状態でプラグイン一覧を出力すると、このようにAzure DNS用のプラグインが表示されます。

aiuser@dproto02:~$ sudo certbot plugins
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* apache
Description: Apache Web Server plugin
Interfaces: Authenticator, Installer, Plugin
Entry point: EntryPoint(name='apache',
value='certbot_apache._internal.entrypoint:ENTRYPOINT', group='certbot.plugins')

* dns-azure
Description: Obtain certificates using a DNS TXT record (if you are using Azure
for DNS).
Interfaces: Authenticator, Plugin
Entry point: EntryPoint(name='dns-azure',
value='certbot_dns_azure._internal.dns_azure:Authenticator',
group='certbot.plugins')

* nginx
Description: Nginx Web Server plugin
Interfaces: Authenticator, Installer, Plugin
Entry point: EntryPoint(name='nginx',
value='certbot_nginx._internal.entrypoint:ENTRYPOINT', group='certbot.plugins')

* standalone
Description: Runs an HTTP server locally which serves the necessary validation
files under the /.well-known/acme-challenge/ request path. Suitable if there is
no HTTP server already running. HTTP challenge only (wildcards not supported).
Interfaces: Authenticator, Plugin
Entry point: EntryPoint(name='standalone',
value='certbot._internal.plugins.standalone:Authenticator',
group='certbot.plugins')

* webroot
Description: Saves the necessary validation files to a
.well-known/acme-challenge/ directory within the nominated webroot path. A
separate HTTP server must be running and serving files from the webroot path.
HTTP challenge only (wildcards not supported).
Interfaces: Authenticator, Plugin
Entry point: EntryPoint(name='webroot',
value='certbot._internal.plugins.webroot:Authenticator',
group='certbot.plugins')

設定ファイルを作る

設定ファイルを作り、これを使用して証明書を作成します。今回、ファイル名は ~/.secrets/certbot/azure.ini としました。Permissionは440に設定しています。

dns_azure_sp_client_id = xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx ※アプリケーションID
dns_azure_sp_client_secret = ******************************** ※アプリケーションシークレット値
dns_azure_tenant_id = yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy ※サブスクリプションID

dns_azure_environment = "AzurePublicCloud"

dns_azure_zone1 = <ドメイン>:/subscriptions/<サブスクリプションID>/<リソースグループ>/<DNSゾーンリソース>

いざ認証

そして証明書を取得に行きます。当初私の場合はmanualモードで証明書を取得してしまったため、実質的に再取得と言う形で実行することになりました。そのため途中の対話内容は少し通常と異なるかもしれません。

aiuser@dproto02:~$ certbot certonly --dns-azure-config ~/.secrets/certbot/azure.ini -d bluecore.net -d '*.bluecore.net'
Saving debug log to /var/log/letsencrypt/letsencrypt.log

How would you like to authenticate with the ACME CA?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Obtain certificates using a DNS TXT record (if you are using Azure for DNS).
(dns-azure)
2: Nginx Web Server plugin (nginx)
3: Runs an HTTP server locally which serves the necessary validation files under
the /.well-known/acme-challenge/ request path. Suitable if there is no HTTP
server already running. HTTP challenge only (wildcards not supported).
(standalone)
4: Saves the necessary validation files to a .well-known/acme-challenge/
directory within the nominated webroot path. A separate HTTP server must be
running and serving files from the webroot path. HTTP challenge only (wildcards
not supported). (webroot)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-4] then [enter] (press 'c' to cancel): 1 <-★1を入力して押下
Certificate not yet due for renewal

You have an existing certificate that has exactly the same domains or certificate name you requested and isn't close to expiry.
(ref: /etc/letsencrypt/renewal/bluecore.net.conf)

What would you like to do?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Keep the existing certificate for now
2: Renew & replace the certificate (may be subject to CA rate limits)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2 ←★2を選択して再取得を試行
Renewing an existing certificate for bluecore.net and *.bluecore.net

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/bluecore.net/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/bluecore.net/privkey.pem
This certificate expires on 2026-10-01.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

ハイライトをしたところは、追加入力をしたところ、そして発行・更新された証明書のありかについて示しています。無事に認証は行えたようで、証明書は私の環境の場合は「更新」と言う扱いになりました。

あとは示されたパスをSSL証明書、SSLキーのパスとしてNginxやApacheに対して指定することで証明書の適用が可能になります。

更新処理をテストする

更新処理を試すには以下のコマンドを実行するようです。

sudo certbot renew --dry-run

その際、以下のエラーが出たことを確認しています。

Processing /etc/letsencrypt/renewal/bluecore.net.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Simulating renewal of an existing certificate for bluecore.net and *.bluecore.net
Encountered exception during recovery: ValueError: No value for given attribute
Failed to renew certificate bluecore.net with error: No value for given attribute

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
All simulated renewals failed. The following certificates could not be renewed:
  /etc/letsencrypt/live/bluecore.net/fullchain.pem (failure)

エラーが出ました。どうやら原因は、過去にmanualモードで証明書を作ったことが原因のようです。

その場合一度 /etc/letsencrypt/renewal/bluecore.net.conf を削除しないとエラー終了してしまうようで、削除したあとであれば、confファイルはrenew処理に伴いconfファイルが自動生成されて正常な状態で動作するようです。

では再実行。

root@dproto02:~# certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
No simulated renewals were attempted.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

無事完遂できたようなので、これで設定は完了・・・ですかね?(自信はない)

自動更新について

自動更新を行うのは、certbotの基盤として動作するsnapdの役目になります。タイマーのリストを出力させると以下のものが登録されていました。なので、どうやら昔やってたように一々頑張って更新スクリプトを実行する必要はなさそうです。

root@dproto02:~# systemctl list-timers | grep certbot
Fri 2026-07-03 22:14:00 JST        9h -                                      - snap.certbot.renew.timer       snap.certbot.renew.service

この実態ファイルは /etc/systemd/system 配下に保存されていて、内容は以下の通りでした。

[Unit]
# Auto-generated, DO NOT EDIT
Description=Service for snap application certbot.renew
Requires=snap-certbot-5603.mount
Wants=network.target
After=snap-certbot-5603.mount network.target snapd.apparmor.service
X-Snappy=yes

[Service]
EnvironmentFile=-/etc/environment
ExecStart=/usr/bin/snap run --timer="00:00~24:00/2" certbot.renew
SyslogIdentifier=certbot.renew
Restart=no
WorkingDirectory=/var/snap/certbot/5603
TimeoutStopSec=30s
Type=oneshot

snap越しにどうやら1日2回、certbot.renewというユニットを実行しますよと言うことを示しているようです。
1日2回と判断したのは、timer一覧を表示させた際に次回実行時が「Fri 2026-07-03 22:14:00 JST」と指定していることから、およそ10-12時間ごとに実行をするようスケジューリングされているのかな?と判断しました。

なんとも・・・・いい時代になりましたねー。

コメント

タイトルとURLをコピーしました