- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 1. TLS/SSL証明書の基本概念
- 2. Let's Encryptとは
- 3. ACMEプロトコルの動作原理
- 4. Certbotのインストール
- 5. 証明書の発行方法
- 6. 発行されたファイル構造
- 7. 自動更新の設定
- 8. Rate Limitsの注意事項
- 9. 代替ツール
- 10. トラブルシューティング
- 11. セキュリティのベストプラクティス
- 12. まとめ
1. TLS/SSL証明書の基本概念
1.1 なぜTLS証明書が必要か
TLS(Transport Layer Security)証明書はウェブ通信の3つの核心的なセキュリティ要素を提供します。
- 暗号化(Encryption):クライアントとサーバー間のデータを暗号化し盗聴を防止
- 認証(Authentication):サーバーが本当にそのドメインの所有者であることを証明
- 完全性(Integrity):データが伝送中に改ざんされていないことを保証
1.2 証明書チェーン構造
┌───────────────────────┐
│ Root CA Certificate │ <- ブラウザ/OSに内蔵された信頼アンカー
│ (Self-Signed) │
└───────────┬───────────┘
│ 署名
┌───────────▼───────────┐
│ Intermediate CA Cert │ <- 中間CA証明書
│ (Signed by Root CA) │
└───────────┬───────────┘
│ 署名
┌───────────▼───────────┐
│ Server Certificate │ <- ドメイン証明書(Leaf)
│ (Signed by Inter. CA) │
└───────────────────────┘
1.3 公開鍵/秘密鍵ペア
- 秘密鍵(Private Key):サーバーのみが保有、絶対に外部漏洩禁止
- CSR(Certificate Signing Request):公開鍵 + ドメイン情報、CAに提出
- 証明書(Certificate):CAが署名した公開鍵 + ドメイン情報
2. Let's Encryptとは
2.1 概要
Let's EncryptはISRG(Internet Security Research Group) が運営する無料・自動化・オープンな認証機関(CA)です。
主要な特徴:
- 無料:ドメイン検証(DV)証明書を無料で発行
- 自動化:ACMEプロトコルで証明書の発行/更新を完全自動化
- オープン:オープンソースプロトコルとツールを使用
- 有効期間:90日(短いサイクルでセキュリティ強化)
- 信頼性:すべての主要ブラウザとOSで信頼
2.2 証明書タイプの比較
| タイプ | 検証レベル | 発行時間 | 費用 | Let's Encrypt |
|---|---|---|---|---|
| DV(Domain Validation) | ドメイン所有確認 | 数分 | 無料〜安価 | 対応 |
| OV(Organization Validation) | 組織確認 | 数日 | 有料 | 非対応 |
| EV(Extended Validation) | 拡張検証 | 数週間 | 高額 | 非対応 |
3. ACMEプロトコルの動作原理
ACME(Automatic Certificate Management Environment)は証明書発行を自動化するプロトコルです。
3.1 全体フロー
┌────────┐ ┌──────────────┐
│ Certbot│ │ Let's Encrypt│
│(Client)│ │ (CA/ACME) │
└───┬────┘ └──────┬───────┘
│ 1. Account Registration │
│──────────────────────────────────────>│
│ 2. Account Created │
│<──────────────────────────────────────│
│ │
│ 3. Order (domain list) │
│──────────────────────────────────────>│
│ 4. Authorizations + Challenges │
│<──────────────────────────────────────│
│ │
│ 5. Respond to Challenge │
│ (HTTP-01 / DNS-01 / TLS-ALPN-01) │
│──────────────────────────────────────>│
│ │
│ 6. Challenge Validated │
│<──────────────────────────────────────│
│ │
│ 7. Finalize (send CSR) │
│──────────────────────────────────────>│
│ 8. Certificate issued │
│<──────────────────────────────────────│
3.2 HTTP-01チャレンジ
最も一般的なチャレンジ方式です。ポート80で特定のファイルにアクセスできるかを検証します。
Let's Encrypt -> http://yourdomain.com/.well-known/acme-challenge/TOKEN_VALUE
検証プロセス:
1. Certbotがトークンファイルをウェブサーバーに配置
2. Let's EncryptがHTTPでそのファイルにアクセス
3. ファイル内容が期待値と一致すればドメイン所有を確認
利点:
- 最もシンプルで一般的
- 追加のDNS設定が不要
- ほとんどのウェブサーバーで簡単に設定
制限:
- ポート80が外部からアクセス可能でなければならない
- ワイルドカード証明書の発行不可
3.3 DNS-01チャレンジ
DNS TXTレコードを作成してドメイン所有を証明します。ワイルドカード証明書の発行に必須です。
Let's Encrypt -> DNS照会: _acme-challenge.yourdomain.com TXT
検証プロセス:
1. Certbotがトークンを計算
2. _acme-challenge.yourdomain.com TXTレコードにトークン値を設定
3. Let's EncryptがDNSを照会して値を確認
4. 一致すればドメイン所有を確認
利点:
- ワイルドカード証明書の発行が可能
- ウェブサーバーがなくても可能
- ポート80が開いていなくても良い
3.4 チャレンジ比較表
| 機能 | HTTP-01 | DNS-01 | TLS-ALPN-01 |
|---|---|---|---|
| ポート | 80 | なし(DNS) | 443 |
| ワイルドカード | X | O | X |
| ウェブサーバー必要 | O | X | O |
| 自動化難易度 | 低い | 中程度(DNS API必要) | 高い |
| 主な用途 | 一般ウェブサーバー | ワイルドカード、内部サーバー | 特殊環境 |
4. Certbotのインストール
4.1 Ubuntu / Debian
# snapでインストール(推奨)
sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
4.2 CentOS / RHEL / Rocky Linux
sudo dnf install epel-release
sudo dnf install certbot
sudo dnf install python3-certbot-nginx
4.3 macOS
brew install certbot
4.4 Docker
docker run -it --rm \
-v /etc/letsencrypt:/etc/letsencrypt \
-v /var/lib/letsencrypt:/var/lib/letsencrypt \
certbot/certbot certonly --help
5. 証明書の発行方法
5.1 Standaloneモード
Certbotが自前のウェブサーバーを起動してHTTP-01チャレンジを処理します。
sudo systemctl stop nginx
sudo certbot certonly --standalone \
-d example.com \
-d www.example.com \
--agree-tos \
--email admin@example.com \
--non-interactive
sudo systemctl start nginx
5.2 Webrootモード
既存のウェブサーバーを停止せずに証明書を発行します。
Nginx設定追加:
server {
listen 80;
server_name example.com www.example.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
sudo mkdir -p /var/www/certbot
sudo certbot certonly --webroot \
-w /var/www/certbot \
-d example.com \
-d www.example.com \
--agree-tos \
--email admin@example.com
5.3 Nginxプラグイン
sudo certbot --nginx \
-d example.com \
-d www.example.com \
--agree-tos \
--email admin@example.com
5.4 DNSプラグイン(ワイルドカード証明書)
Cloudflare DNSプラグイン:
sudo snap install certbot-dns-cloudflare
cat > /etc/letsencrypt/cloudflare.ini << 'CFEOF'
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
CFEOF
sudo chmod 600 /etc/letsencrypt/cloudflare.ini
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d "example.com" \
-d "*.example.com" \
--agree-tos \
--email admin@example.com
AWS Route 53 DNSプラグイン:
sudo snap install certbot-dns-route53
sudo certbot certonly \
--dns-route53 \
-d "example.com" \
-d "*.example.com" \
--agree-tos \
--email admin@example.com
6. 発行されたファイル構造
/etc/letsencrypt/live/example.com/
cert.pem # サーバー証明書のみ
chain.pem # 中間CA証明書チェーン
fullchain.pem # cert.pem + chain.pem(サーバーで使用)
privkey.pem # 秘密鍵
| ファイル | 内容 | 用途 |
|---|---|---|
| cert.pem | サーバー証明書 | 単独使用(めったに使わない) |
| chain.pem | 中間CA証明書 | OCSP Stapling用 |
| fullchain.pem | サーバー証明書 + 中間CA | Nginx ssl_certificateに使用 |
| privkey.pem | 秘密鍵 | Nginx ssl_certificate_keyに使用 |
Nginxに適用:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
}
7. 自動更新の設定
7.1 更新テスト
sudo certbot renew --dry-run
7.2 systemd Timer(推奨)
# /etc/systemd/system/certbot-renew.timer
[Unit]
Description=Certbot renewal timer
[Timer]
OnCalendar=*-*-* 00,12:00:00
RandomizedDelaySec=3600
Persistent=true
[Install]
WantedBy=timers.target
# /etc/systemd/system/certbot-renew.service
[Unit]
Description=Certbot renewal service
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx"
sudo systemctl daemon-reload
sudo systemctl enable --now certbot-renew.timer
7.3 Crontab
# crontab -e
0 2,14 * * * certbot renew --quiet --deploy-hook "systemctl reload nginx"
7.4 更新フック
# デプロイフック(更新成功時のみ実行)
sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
cat > /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh << 'HOOKEOF'
#!/bin/bash
systemctl reload nginx
echo "Certificate renewed and nginx reloaded at $(date)" >> /var/log/certbot-deploy.log
HOOKEOF
chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
8. Rate Limitsの注意事項
| 制限 | 値 | 説明 |
|---|---|---|
| Certificates per Registered Domain | 50/週 | 同一ドメインに対して週50個 |
| Duplicate Certificate | 5/週 | 同一ドメインセットに対して5個 |
| Failed Validations | 5/時間/アカウント/ホスト名 | 検証失敗制限 |
| New Orders | 300/3時間 | 新規注文制限 |
Staging環境の活用:
sudo certbot certonly --standalone \
--staging \
-d example.com \
--agree-tos \
--email admin@example.com
9. 代替ツール
9.1 acme.sh
純粋なシェルスクリプトで書かれたACMEクライアントです。
curl https://get.acme.sh | sh
acme.sh --issue -d example.com -w /var/www/html
# ワイルドカード(DNS API使用)
acme.sh --issue \
-d example.com \
-d "*.example.com" \
--dns dns_cf \
--dnssleep 120
# Nginxにインストール
acme.sh --install-cert -d example.com \
--key-file /etc/nginx/ssl/example.com.key \
--fullchain-file /etc/nginx/ssl/example.com.fullchain.pem \
--reloadcmd "systemctl reload nginx"
9.2 Caddy(自動HTTPS)
CaddyはウェブサーバーGTRで自動的にHTTPSを処理します。
# Caddyfile
example.com {
root * /var/www/html
file_server
}
# これだけでLet's Encrypt証明書の自動発行と更新!
9.3 cert-manager(Kubernetes)
Kubernetes環境で証明書を自動管理します。
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
ingress:
class: nginx
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- app.example.com
secretName: app-tls-secret
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80
10. トラブルシューティング
10.1 一般的なエラーと解決法
チャレンジ失敗:
# HTTP-01チャレンジファイルのアクセス確認
curl -v http://yourdomain.com/.well-known/acme-challenge/test
# ファイアウォール確認(ポート80)
sudo ufw status
sudo iptables -L -n | grep 80
# DNS確認
dig +short yourdomain.com
証明書更新失敗:
sudo certbot certificates
sudo certbot renew --dry-run -v
sudo cat /var/log/letsencrypt/letsencrypt.log
証明書情報確認:
# 証明書内容確認
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -text -noout
# 有効期限確認
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -enddate -noout
# リモートサーバー証明書確認
openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null | \
openssl x509 -text -noout
11. セキュリティのベストプラクティス
- 秘密鍵の保護:privkey.pemの権限を600に設定、rootのみ読み取り可能
- 自動更新の監視:更新失敗時のアラート設定
- まずStaging:新しい設定は常にStaging環境でテスト
- HSTS適用:証明書発行後にHSTSヘッダーを設定
- 証明書透明性の監視:crt.shでドメイン証明書発行履歴を監視
- バックアップ:/etc/letsencryptディレクトリの定期バックアップ
12. まとめ
Let's EncryptとCertbotは無料TLS証明書の標準となりました。要点整理:
- HTTP-01チャレンジは最もシンプルだがワイルドカードはDNS-01が必須
- CertbotのWebrootまたはNginxプラグインが最も実用的
- 自動更新はsystemd timerまたはcrontabで設定
- Kubernetes環境ではcert-managerが標準
- Rate Limitsを理解しテスト時はStagingサーバーを活用
- 証明書発行後はNginx TLSセキュリティ設定を必ず最適化すべき