AWS Application Load BalancerでLet's Encrypt SSLを自動化する
この記事では、AWS Application Load Balancer向けのLet's Encrypt発行オペレーションをすべて自動化し、その管理方法を学ぶことができる。

ほとんどの場合、AWS Certificate Manager(ACM)以外に必要なものはないが、顧客のドメインをALBでホストしていて、顧客からSSL証明書を取得する手段がない場合など、いくつかのケースでは回避策が必要になる。この記事では、AWS Application Load BalancerでLet's Encrypt SSLを発行し、それを自動化する方法を解説する。
Let's EncryptにSSL証明書をリクエストする際、LEにはweb-challenge、route53などの検証方法がある。このシナリオでは、ドメインのDNS管理が自分の手にないため、web-challengeを使用することにした。私はアプリケーションをホストしているだけで、SSLを発行する必要がある。
web-challengeでSSLをリクエストする場合、Let's Encryptは https://domain.com/.well-known/acme-challenge パスをチェックして確認・検証を行う。これはどういう意味か?つまり、Let's Encryptがポート80でドメインにリクエストを送信し、検証を行うということだ。うーん、Load Balancerの設定にいくつか調整が必要で、acme-challengeリクエストを特別にリダイレクトするための別のTarget Groupが必要になる。
Step 1: 新しいEC2を起動し、新しいTarget Groupを作成する
リポジトリをクローンする
簡単な管理と全ドメインで同じ方法で標準を維持するために、bashスクリプトを書いた。GitHubリポジトリをチェックするか、/opt/パス配下のacme-challange-serverにリポジトリをクローンしてほしい。
Tip: # git clone https://github.com/flightlesstux/alble.git
nginx、Let's Encryptをインストールして設定する
/.well-known/acme-challenge/* リクエストを受け取ると、nginxがインストールされたEC2がすべてのacme-challengeリクエストを処理し、SSLを発行する。
nginxをインストールし、/.well-known/acme-challenge/ 用に設定する
amazon-linux-extras install nginx1 コマンドでnginxを簡単にインストールできる。インストール後、nginxのルート設定ファイルに新しいlocationブロックを追加する。ルート設定ファイルは /etc/nginx/nginx.conf にある。
location /.well-known/acme-challenge {
root /opt/alble/certbot-challange;
}server_name の値は全ドメインに対して _; にする必要がある。静的なDNS名は設定できない。
nginxモジュール付きでCertbotをインストールする
まず、epelリポジトリからcertbotをインストールする。最初にepelをインストールする必要がある。epelのインストールには amazon-linux-extras install -y epel コマンドを使い、その後 yum install -y nginx certbot python2-certbot-nginx jq dig コマンドを実行して前提条件をカバーする。
acme-challengeサーバー用のIAMロールポリシー
このacme-challengeサーバーには、Let's Encrypt SSLでACMとALBの操作にアクセスするためのIAMロールがある。IAMポリシーは以下の通り。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AWSLEPolicy1",
"Effect": "Allow",
"Action": [
"acm:DescribeCertificate",
"acm:RemoveTagsFromCertificate",
"acm:GetCertificate",
"acm:AddTagsToCertificate",
"acm:ListCertificates",
"acm:ImportCertificate",
"acm:ListTagsForCertificate"
],
"Resource": "*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "acme-challenge-server-Elastic-IP/32"
}
}
},
{
"Sid": "AWSLEPolicy2",
"Effect": "Allow",
"Action": [
"elasticloadbalancing:RemoveTags",
"elasticloadbalancing:DescribeTags",
"elasticloadbalancing:AddTags",
"elasticloadbalancing:AddListenerCertificates"
],
"Resource": "AWS::ALB::ARN",
"Condition": {
"IpAddress": {
"aws:SourceIp": "acme-challenge-server-Elastic-IP/32"
}
}
},
{
"Sid": "AWSLEPolicy3",
"Effect": "Allow",
"Action": [
"elasticloadbalancing:DescribeSSLPolicies",
"elasticloadbalancing:DescribeListeners",
"elasticloadbalancing:DescribeListenerCertificates"
],
"Resource": "*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "acme-challenge-server-Elastic-IP/32"
}
}
},
{
"Sid": "AWSLEPolicy4",
"Effect": "Allow",
"Action": [
"elasticloadbalancing:RemoveTags",
"elasticloadbalancing:DescribeTags",
"elasticloadbalancing:AddTags"
],
"Resource": "AWS::ALB::ARN",
"Condition": {
"IpAddress": {
"aws:SourceIp": "acme-challenge-server-Elastic-IP/32"
}
}
},
{
"Sid": "AWSLEPolicy5",
"Effect": "Allow",
"Action": [
"elasticloadbalancing:DescribeSSLPolicies",
"elasticloadbalancing:DescribeListeners",
"elasticloadbalancing:AddListenerCertificates",
"elasticloadbalancing:DescribeListenerCertificates"
],
"Resource": "*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "acme-challenge-server-Elastic-IP/32"
}
}
}
]
}Elastic IPを割り当てた後、このポリシーをセキュリティ上の問題や漏洩なく直接acme-challengeサーバーにアタッチできる。ローカル認証情報を使用したい場合も、同じIAMポリシーを使用できる。
新しいTarget Groupを作成する
EC2インスタンスの設定後、acme-challengeという名前のTarget Groupを作成し、acme-challange-serverという名前のnginxがインストールされたEC2にリクエストをリダイレクトし、acme-challenge-serverをターゲットとして登録する。すべてが問題なく進めば、画面は以下のようになる。

Step 2: Application Load Balancerのリスナールールを作成する
/.well-known/acme-challenge/* リクエストを受け入れてacme-challenge Target Groupにリダイレクトするために、新しいリスナールールを編集・作成する必要がある。このステップが完了すると、画面は以下のようになる。

これで、ACMEからLet's Encrypt SSLをリクエストし、問題なく発行してACMにインポートし、AWS ALBに割り当てる準備が整った。この操作には発行のための3つの異なるステップが含まれる。
- Let's EncryptからSSLをリクエストする
- ドメインまたはサブドメインがAWS ALB CNAMEレコードと一致する場合に、リクエストしたSSLをインポートする
- 本番で使用するためにインポートしたSSL証明書をAWS ALBに割り当てる
ACMEからLet's Encrypt SSLを発行・リクエストする
gitリポジトリをクローンしたら、/opt/alble/renewal-hooks フォルダを/etc/letsencrypt/パス配下に移動する必要がある。そうしないと、ACMで証明書を更新できず、自分と顧客のセキュリティが損なわれる。mv /opt/alble/renewal-hooks /etc/letsencrypt/ をコピー&ペーストすればよい。
gitリポジトリのREADME.mdファイルを読み、envファイルに変数を記述するだけだ。その後、AWS Application Load BalancerでLet's Encrypt SSL証明書を簡単に実行・管理・作成できる。SSLを発行するためにacme-challange-serverにコマンドを実行するにはAWS SSMの使用を推奨する。そのためには、IAMロールに ポリシーを追加する必要がある。
AmazonEC2RoleforSSM
テストにはサブドメインを使用することにしたが、問題ではない。ルートドメインも使用できる。テストドメインは awsle-1.ercanermis.com と awsle-2.ercanermis.com だ。
/opt/alble/ パスにいる状態で、./create-new-site.sh awsle-1.ercanermis.com のようにコマンドを実行すると、以下のような出力が表示される。

ALBLeスクリプトは、続行する前にまずドメインおよび/またはサブドメインのCNAMEレコードをチェックして確認する。間違ったドメイン/サブドメインを入力したりタイプミスした場合は、Slackアラートで警告する。アラートは自動化にとって本当に重要だ。envファイルでSlackアラートを設定できる。以下は以前にLet's Encrypt SSLを発行した場合の例:

本番環境
AWS ALBのDNS名は web-application-elb-1302305711.us-east-1.elb.amazonaws.com で、https://web-app.ercanermis.com からアクセスできる。SSLの取得にはAWS Certificate Managerを使用している。
テストドメインは https://awsle-1.ercanermis.com と https://awsle-2.ercanermis.com で、AWS Application Load BalancerでLet's Encryptを使用している。やった!



AWS ALB SSL証明書とACMはどのように見えるか?


この記事が役立つことを願っている。P.S. 更新リクエスト用のcronを設定するのを忘れずに。
ソースコード: https://github.com/flightlesstux/alble/
Ercan の他のサイト
同じ著者、別の領域のサイトが2つ。