📙

EC2でデプロイしたプロジェクトにACMとELBを使用してHTTPSでドメイン接続を設定する

2024/06/25に公開

はじめに

こちらの続きで、EC2でデプロイしたプロジェクトにACMを使用してHTTPSでドメイン接続を設定しています。
https://zenn.dev/nenenemo/articles/36e9742c63c029

今回はELBがHTTPSリクエストを処理し、証明書の管理を行います。これにより、EC2上のNginxなどのWebサーバーでSSL証明書を直接扱う必要はありません。

https://ドメイン/ にアクセスした際にEC2上のNext.jsプロジェクトが表示されるようにしています。
ちなみに、http://ドメイン/ にアクセスした際に自動的に https://ドメイン/ に転送されるようになっています。

ユーザーがブラウザを使用して https://ドメイン/ にアクセス
→Route 53はドメインのリクエストを適切なALBにルーティングします。
→ALBはSSL/TLS証明書(ACMから取得)を使用してHTTPSリクエストを処理
→ALBはリクエストを適切なEC2インスタンスにルーティング
→EC2インスタンスはリクエストに応じたページを生成し、ALBを通じてユーザーに応答を返します。

というのが大まかな流れです。

ドメインを使用したSSL化対応

ドメインを使用したSSL化対応のために、今回はACMを使用してSSL/TLS証明書を作成します。
ACMで証明書を発行する際には必ずドメイン名が必要なので、まずはRoute53でドメインを登録してください。

詳しくは下記を参考にしてください。
https://zenn.dev/nenenemo/articles/a3a4b29af76df2#独自ドメインでcloudfrontにアクセスできるようにする

ACMでSSL証明書発行

リクエストを選択、

次へ

ドメイン名にはRoute53に登録してある対象のドメイン名と*.ドメイン(サブドメイン)を指定して、リクエスト

ステータスが検証保留中から発行済に変わると、SSL証明書の発行が完了しています。

CNAMEがまだない場合は、Route 53 でレコードを作成

レコードを作成でCNAMEを作成してください。

発行済みになったので、使用できます。

ターゲットグループの作成

ターゲットグループは、ELBで使用される概念で、ターゲットグループは、ロードバランサーからのトラフィックを受け取る対象となるリソース(インスタンス、コンテナ、IPアドレスなど)の集合です。

ターゲットグループでELBからの通信をどこに向けるかを定義します。

主にALB(Application Load Balancer)やNLB(Network Load Balancer)で利用されます。
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/load-balancer-target-groups.html

ロードバランシング > ターゲットグループ

ターゲットグループの作成を選択、

ターゲットグループ名(for-nextjs-tg)を入力、

スクロールして次へ

ここでターゲットグループにwebサーバのEC2インスタンスを紐付けます。
インスタンスを選択し、保留中として以下を含めるを押してください。

下にターゲットが表示されるので確認したら、ターゲットグループの作成を押してください。

まだ、ALBにターゲットグループを登録していないので未使用となっています。

ELB(Elastic Load Balancing)

アプリケーションの高可用性、耐障害性、および自動スケーリングをサポートするために、サーバーにかかる負荷を複数のターゲット(EC2など)に分散させるサービスです。このプロセスにより、アプリケーションは多くのユーザーからのリクエストを効率的に処理できるようになります。
https://aws.amazon.com/jp/elasticloadbalancing/

ヘルスチェック機能

ELBのヘルスチェックは、登録されたターゲット(EC2、コンテナなど)へ定期的にリクエストを送信し、正しいレスポンスが返ってくるか評価する機能です。

ヘルスチェックはELBの設定時に定義され、どのポートとパスでリクエストを送信するか、何秒ごとにチェックを行うか、どのような応答を正常とするかなどを設定できます。

また、正常に応答しないターゲットからはトラフィックを自動的に引き離し、障害が発生した場合にもトラフィックの中断を最小限に抑えることができます。また、問題が解決した後は自動的にトラフィックを再開します。

SSL/TLS証明書の付与

アクセスポイントとなるELBにSSL証明書を設定すると、ELBはクライアントからのHTTPS通信を受け取り、その通信を暗号化を復号化します。これにより、ELBはクライアントとの間で安全な通信を確立し、バックエンドのサーバーには暗号化されていない形でリクエストを転送します。

つまり、ELBがSSL通信の終点となり、クライアントとサーバー間のデータを安全にやり取りします。そして、バックエンドのサーバーは通常のHTTPで通信を受け取ることができます。

この仕組みにより、ELBはセキュリティを担保しつつ、バックエンドのサーバーに対する負荷を軽減し、効率的なアプリケーションの運用を支援します。また、証明書の管理を中央集権化することで、更新や再配置が簡単になります。

ELBでは4種類のロードバランサーがあります。

ALB(Application Load Balancer)

レイヤー7(アプリケーション層)のロードバランサーで、HTTPおよびHTTPSトラフィックを扱います。
コンテンツベースのルーティングをサポートしており、URLパスやヘッダーに基づいてトラフィックを異なるバックエンドサービスにルーティングできます。
WebsocketとHTTP/2もサポートされています。
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/introduction.html

NLB(Network Load Balancer)

レイヤー4(トランスポート層)で動作し、TCPトラフィックやUDPトラフィックを処理します。
極めて高いパフォーマンスを実現し、固定IPアドレスを使用することもできます。
ミリ秒単位での超低遅延が特徴です。
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/network/introduction.html

GWLB(Gateway Load Balancer)

https://aws.amazon.com/jp/elasticloadbalancing/gateway-load-balancer/

CLB(Classic Load Balancer)

前世代のロードバランサーです。新しい機能やアップデートをALBやNLBに集中しているため、新規のデプロイメントでCLBを選択することはないかと思います。
https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/environments-cfg-clb.html

ALBの作成

ロードバランシング > ロードバランサー

Application Load Balancer を作成を選択

ロードバランサー名(for-nextjs-alb)を入力、

高可用性と自動スケーリングに対応するために、ロードバランサーには異なるアベイラビリティゾーン(AZ)にまたがる複数のサブネット(2つ以上設定が必須)を選択

セキュリティグループは、新しいセキュリティグループを作成からALB用の新しいセキュリティグループを作成してください。デフォルトのセキュリティーグループが指定されている場合は、削除してください。

ALBとEC2で異なるセキュリティグループを設定することによって、ALBは外部トラフィック(ポート80と443)を許可、EC2はALBからのトラフィックのみを許可することができます。

セキュリティグループ名(for-nextjs-alb-sg)と今回は説明も必須なので入力、
VPCはEC2と同じものを選択、インバウンドルールは、80443でどこからでもアクセス出来るように、0.0.0.0/0::/0を許可したものを4つ追加して、セキュリティグループを作成

ALBの画面に戻り、リスナーとルーティング > リスナーの追加を押して、
下記のようにHTTPとHTTPSの2つ作成してデフォルトアクションでは、先ほど作成したターゲットグループを指定

HTTPSでは、SSL/TLS サーバー証明書 > 証明書の取得先 > ACM から
証明書(ACM から)は、作成した証明書を指定する必要があります。

下にスクロールに内容を確認したら、ロードバランサーの作成を押してください。

ターゲットグループがALBに関連付けたので未使用から初期になっています。

リスナーの設定

リスナー

クライアントからの接続要求を受け付ける部分です。リスナーは、特定のポートで受け取ったトラフィックを指定されたプロトコルに基づいて適切なターゲットグループにルーティングする設定ができます。

リスナーが追加できたら、HTTPからHTTPSにリダイレクトするようにリスナールールを編集してください。
HTTP(80リスナー)を選択、

リスナーの管理 > リスナーの管理 > リスナーの編集

アクションのルーティング > URL にリダイレクト
URL にリダイレクト > URI 部分
プロトコルは、HTTPS、ポートは、443

スクロールして、変更内容の保存

設定したリスナールールによって、HTTP(ポート80)で受信したリクエストをHTTPS(ポート443)にリダイレクトするようになります。これにより、http://ドメイン/ にアクセスした際に自動的に https://ドメイン/ に転送され、通信が暗号化された状態で行われるようになります。

https://qiita.com/seshiruff4214/items/d72b56c5c08ba7a455f8
https://qiita.com/miyuki_samitani/items/1734dc13c6b7af601bd9

ドメインとロードバランサーの紐付け

レコードを作成

エイリアスを選択し、
トラフィックのルーティング先 > Application Load Balancer と Classic Load Balancer へのエイリアス > アジアパシフィック (東京) > 先ほど作成したELBを選択し、レコードを作成を選択すると、値/トラフィックのルーティング先が先ほど作成したALBになっているAレコードが作成されます。

上記を同じ動作をレコード名にwwwを入力して行い、もう一つAレコードを作成してください。

DNA設定のa @ パブリック IPv4 アドレスは削除してください。

セキュリティグループの変更

EC2のセキュリティグループ(ALB用のセキュリティグループではない方)> インバウンドルールの設定を変更して、ALBからのトラフィックのみを許可するようにします。
タイプはHTTP、ソースはセキュリティグループからALB用のセキュリティグループを選択してください。

ポート範囲が22のものは、SSH接続に必要なので残して下記のようになっていることを確認して、ルールを保存

ドメイン(https://ドメイン/ )にアクセスしてプロジェクトの内容が表示されるか、
http://ドメイン/ にアクセスした際に自動的に https://ドメイン/ に転送されるか確認してください。

証明書情報を確認して、Amazonが認証局になっていることが確認してください。

一般名(CN)Amazon RSA 2048 M03」と表示されている場合、それはACMによって発行された証明書です。

この時点でパブリックIPアドレス(http://パブリックIPアドレス/ )にアクセスしても表示されなくなります。

ロードバランサーのリスナーとルールで到達不可能と表示される

ロードバランサー > リスナーとルールのHTTPS:443で到達不可能と表示されていました。

原因は、セキュリティグループがALB用に作成したものを選択していないことでした。

エラー備忘録

ACMを使用せずに、https化しようとした時のものです。

Route53でAレコードを作成します。
値にはパブリックIPアドレスを入力し、レコードを作成を押してください。

ルートに移動し、

cd ~/

Next.jsアプリケーションのポートに転送されるようにNginxの設定を変更します。

sudo nano /etc/nginx/nginx.conf

server > server_nameを下記のように記述してください。変更前はserver_name _;となっていると思います。これは特にサーバー名を指定せずにすべてのリクエストを受け入れるための設定です。

    server_name  example.com www.example.com; # ここを自分のドメインに変更

https://www.linkedin.com/pulse/supercharge-your-nextjs-application-deploying-aws-ec2-kalaiselvam-m2ehc
iles for the default server block.

Job for nginx.service failed because the control process exited with error code.

See "systemctl status nginx.service" and "journalctl -xeu nginx.service" for details.
/etc/nginx/nginx.confの内容を変更して適用しようとした時に

sudo systemctl restart nginx

下記のように表示されました。

Job for nginx.service failed because the control process exited with error code.
See "systemctl status nginx.service" and "journalctl -xeu nginx.service" for details.

これは通常では、設定ファイル(nginx.conf)に記述された内容に問題があるために起こります。

メッセージにもあるように、systemctl status nginx.servicejournalctl -xeu nginx.serviceを使用して、具体的なエラーメッセージや原因を確認してください。

Nginxの構文チェックを行います。

sudo nginx -t

表示されたエラーメッセージから、NginxがSSL証明書ファイルを読み込むことができないという問題が確認されます。具体的には、指定されたパス/etc/pki/nginx/server.crtにファイルが存在しないために発生しています。

nginx: [emerg] cannot load certificate "/etc/pki/nginx/server.crt": BIO_new_file() failed (SSL: error:80000002:system library::No such file or directory:calling fopen(/etc/pki/nginx/server.crt, r) error:10000080:BIO routines::no such file)
nginx: configuration file /etc/nginx/nginx.conf test failed

CertbotとそのNginxプラグインをインストール

sudo yum -y install certbot python3-certbot-nginx

https://certbot.eff.org/

Certbotを実行して SSL 証明書を生成します。

sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Certbotが証明書の有効期限が近づいたときや他の重要な通知を受け取るために必要なメールアドレスを入力するよう求めています。

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel):

Let's Encryptのサービス利用規約に同意するかどうかを確認するものです。Let's EncryptからSSL証明書を取得するためには、この利用規約に同意する必要があります。

Yを入力してEnterを押してください。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.4-April-3-2024.pdf. You must agree in
order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o:

Let's Encryptを提供するプロジェクトの一環として、Electronic Frontier Foundation(EFF)とメールアドレスを共有するかどうかを尋ねています。これに同意すると、EFFからウェブ暗号化に関する情報やキャンペーン、ニュースレターなどが送られてくることになります。

どちらを選んでも、SSL証明書の取得やNginxの設定には影響しないので、今回はNを入力してEnterを押してください。

Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o:

検証の失敗は、1アカウントごと、1ホスト名ごと、1時間毎に、5回までに制限されているようです。
また、レート制限に引っかかった場合、制限を一時的にリセットする方法がなく、レート制限が解消される1週間後まで待つ必要があるようです。

An unexpected error occurred:
Error creating new order :: too many failed authorizations recently: see https://letsencrypt.org/docs/failed-validation-limit/
Ask for help or search for solutions at https://community.letsencrypt.org. 
See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.

https://community.letsencrypt.org/t/error-creating-new-order-too-many-failed-authorizations-recently/198544/6
https://letsencrypt.org/ja/docs/rate-limits/
https://qiita.com/seena417/items/02743071f1c0a43be3e3

参考にさせていただきました

https://qiita.com/seshiruff4214/items/d72b56c5c08ba7a455f8
https://qiita.com/yuuichimizuta/items/d7dabc1b4b21de0e7e60#3リスナーの追加と編集
https://qiita.com/miyuki_samitani/items/1734dc13c6b7af601bd9#comments
https://dev.classmethod.jp/articles/for-begginer-ssl-communication-by-aws-certificate-manager/
https://dev.classmethod.jp/articles/alb-backend-https/
https://zenn.dev/nozomi_iida/articles/20220216_to_https_with_aws

終わりに

何かありましたらお気軽にコメント等いただけると助かります。
ここまでお読みいただきありがとうございます🎉

Discussion