固定IPアドレスでフルマネージドなリダイレクト環境をAWSで構成する

ALBのリダイレクト機能とGlobal Acceleratorを組み合わせることで、AWSで固定IPアドレスなフルマネージドリダイレクト環境が構成できます。事情により名前解決をAレコードで行う必要がある場合にベストなリダイレクト環境かと思います。
2021.07.20

はじめに

清水です。固定IPアドレスでアクセスできるリダイレクト環境が必要になり、AWSでの構成を考えてみました。S3+CloudFrontのリダイレクト環境だとIPアドレスが可変であるため要件にマッチしません。それならEC2上でHTTPサーバを稼働させる必要があるかな、と考えていたのですが、ALBのリダイレクト機能とGlobal Acceleratorの固定IPアドレスを利用することで実現が可能だということに気が付きました。AWSのフルマネージドなサービスのみで実現できるため、管理運用の手間もありません。ACM証明書も利用可能です。そもそもどうしてこのような環境が必要になったのかの経緯とあわせてまとめてみました。

どうして固定IPアドレスなリダイレクト環境が必要なのか?

まずは背景として、どうして固定IPアドレスなリダイレクト環境が必要になるのかをまとめてみます。

AWSではCloudFrontやELB利用時にエンドポイントとしてドメイン名が払い出され、それをCNAMEとしてレコード登録して利用することが多いかと思います。この際、Zone Apex(Naked Domain)の利用が問題となることがあります。www.example.comではなくexample.comを利用したい、というケースですね。このZone Apexであるexample.comについてはCNAMEレコードが利用できない制約が発生するケースがほとんどかと思います。(厳密にはRFC 1912に記載のあるCNAMEレコードが他のレコードと同居できないという制約によります。参考: CDN とCNAME Apexドメインの制限 | REDBOX Labo

もしDNSにRoute 53を利用しているのであれば、ALIASレコードを利用することで制約の回避が可能です。(参考: Amazon Route 53のALIASレコード利用のススメ | DevelopersIO なおALIASレコードが利用できるのであれば、CNAMEレコードではなくALIASレコードの利用が推奨されます。)またCloudflareのCNAME Flatteningのように、Route 53以外でもこの問題を解決する手段が各DNSサービスベンダより提供されている場合もあります。

しかし事情によりそれらDNSサービスが利用できず、Zone ApexにはCNAMEでなくAレコード(つまり固定IPアドレス)で登録する必要がある、という状況もあるかと思います。この場合、CNAMEが利用できるZone Apexではないドメイン名(例えばwww.example.com)に実際の環境を準備、Zone Apex(example.com)へのアクセスは301 Moved Permanentlyでリダイレクトする、ということが検討できるかと思います。(ブラウザにはwww.example.comと表示されますが、これにはいったん目をつむりましょう。最近のGoogle Chromeブラウザではいい感じにwww表記を省略してくれたりもしますしね。)構成を示すと以下のようになります。

さてこの「Zone Apexをwww付きにリダイレクトさせる」構成を考えたとき、301 Moved Permanentlyを返すリダイレクト環境を別途準備する必要があります。AWSでリダイレクト環境をつくる一番手っ取り早い方法はS3のリダイレクト機能を使用する構成かと思います。HTTPS対応としてCloudFrontも準備、S3+CloudFrontでのリダイレクト環境ですね。費用としても大きく発生するのはCloudFrontの転送量、リクエスト量によるものなので非常にリーズナブルに運用が可能です。(参考: CloudFront – S3 オリジンの構成でリダイレクトさせる方法を教えてください | DevelopersIO

ですが今回の「Zone Apexをwww付きにリダイレクトさせる」という構成では、このS3+CloudFrontのリダイレクト環境が利用できません。理由はエンドポイントとなるCloudFrontのドメイン名の登録がZone Apexでは難しいからです。話の発端であるリダイレクト環境をつくる理由と同じ理由ですね。今回のケースでは「Zone Apexをwww付きにリダイレクトさせる」環境は、エンドポイントとして固定IPアドレスである必要があります。

この「固定IPアドレスでアクセスできるリダイレクト環境」について、私は当初、EC2上でApache HTTP ServerないしnginxなどHTTPサーバを稼働させ、リダイレクト環境を準備する必要があるかな、と考えていました。IPアドレスについてはElastic IPを利用すれば固定化することができます。EC2についてもAuto HealingやAuto Recoveryなどを使えばある程度、可用性も確保できるかと思います。しかしそれでもEC2上のOS管理、HTTPサーバのミドルウェア管理が発生します。HTTPS対応の場合はSSL/TLS証明書の発行や管理も必要です。できればやりたくないですよね。そんなことを考えていたいところ、ALBのリダイレクト機能を思い出しました。(参考: [新機能]Webサーバでの実装不要!ALBだけでリダイレクト出来るようになりました! | DevelopersIO)この機能を使えば、EC2を使わず301 Moved Permanentlyをレスポンスとして返すことが可能です。さらにGlobal Acceleratorを使用すればALBの固定IPアドレス化もできます。(参考: Global Acceleratorを使ってALBを固定IP化する #reinvent | DevelopersIO)AWSのフルマネージドなサービスだけで、「固定IPアドレスでアクセスできるリダイレクト環境」が構築できます。構成としては以下のぐあいです。

S3+CloudFrontのリダイレクト環境と比べて、ALBならびにGlobal Acceleratorの利用費が発生するため、料金コストとしては割高になることは否めません。しかしAWSのフルマネージドなサービスのみでリダイレクト環境を構築でき、またACM証明書も利用可能です。「固定IPアドレスでアクセスできるリダイレクト環境」という場合のベストな構成パターンかと思います。以下では実際にこの構成を構築し、動作を確認していみたいと思います。

(なお、本節冒頭でドメイン名の利用をCloudFrontやELBとしていますが、ALBの利用であればZope Apexなリダイレクト環境を準備しなくても、Global AcceleratorでALBの固定IPアドレス化を行いAレコード登録してコンテンツをホスト、という構成が取れるかと思います。またNLBについてはGlobal Acceleratorなしで固定IPアドレスが使用できます。よってこの構成の使用用途としては、コンテンツ本体をCloudFrontでホストしている環境となるかと思います。)

www付きドメインをホストするCloudFront環境

まずはコンテンツ本体をホストするCloudFront環境を準備しておきます。こちらはCloudFrontのAlternate domain name (CNAME)でwww.example.comを設定、また証明書も設定しHTTPSアクセス可能となるように設定します。

まずはオリジンの準備です、今回はALB+EC2環境に、ドメインorigin.example.infoでアクセスできるよう準備しておきました。

CloudFront環境はこのドメインをオリジンに指定します。Behaviorの設定はDefaultのみ使用、Cache PolicyでManagedのCachingDisabled、Origin request PolicyもManagedのAllViewerを設定します。

Alternate domain name (CNAME)でwww.example.comを指定、また証明書も設定しHTTPSアクセス可能としておきます。

CloudFrontディストリビューションの準備ができたら、DNSサービスの設定を行います。今回はexample.comのDNSにお名前.comを利用しています。(実際は.comではなくて.netなドメインですが、適宜読み替えてください。)Route 53のALIASレコードのような設定はできません。(CNAMEレコードを設定する場合、ホスト名空欄での設定はおこなえない旨、記載がありますね。)www.example.comのCNAMEレコードの値として作成したCloudFrontディストリビューションのドメイン名(dXXXX.cloudfront.net)を設定します。(TTLは動作確認目的のため60としていますが、実際の環境に適した値としましょう。)

設定後、digコマンドで名前解決結果を確認しておきます。

% dig www.example.net

; <<>> DiG 9.10.6 <<>> www.example.net
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1987
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;www.example.net.               IN      A

;; ANSWER SECTION:
www.example.net.        60      IN      CNAME   dgaxxxxxxxxxx.cloudfront.net.
dgaxxxxxxxxxx.cloudfront.net. 60 IN     A       13.XXX.XXX.61
dgaxxxxxxxxxx.cloudfront.net. 60 IN     A       13.XXX.XXX.24
dgaxxxxxxxxxx.cloudfront.net. 60 IN     A       13.XXX.XXX.81
dgaxxxxxxxxxx.cloudfront.net. 60 IN     A       13.XXX.XXX.72

;; Query time: 9 msec
;; SERVER: X.X.X.X#53(X.X.X.X)
;; WHEN: Tue Jul 20 12:54:24 JST 2021
;; MSG SIZE  rcvd: 147

続いて、ブラウザでwww.example.comにアクセスし、コンテンツが表示できることを確認しておきます。なお、Chromeブラウザの場合、標準でアドレスバーのwwwは省略されます。「表示」メニューの「URL全体を常に表示」を有効にする、もしくはアドレスバーをクリックしてみることで、アドレス全体www.example.comが表示されます。

Zone Apexをホストする固定IPアドレスでリダイレクトするALB

実際のコンテンツをホスティングしている環境(www.example.com)が準備できました。続いて本エントリの本題となる、固定IPアドレスでアクセスできるリダイレクト環境のALBを作成していきます。

ALBとGlobal Acceleratorの作成

まずはALBリソース本体とGlobal Acceleratorリソースを作成します。マネジメントコンソールのALBの作成ウィザードから進めます。

ロードバランサの名称は適切に入力します。リスナーはHTTP (80)とHTTPS (443)を設定しました。リダイレクト専用のALBで配下にEC2は配置しない想定ですが、ALB自体の配置用サブネットの指定が必要です。またGlobal AcceleratorについてはこのALB作成ウィザード中に作成が可能です。Global Acceleratorの作成チェックボックスをONにし、Accelerator名を入力します。

証明書についてはあらかじめ作成しておいたexample.com用のACM証明書を選択します。またセキュリティグループの設定では、今回は外部公開用と想定して、InboundルールでHTTP (80)、HTTPS (443)をソース0.0.0.0/0で許可したルールを選択しました。必要に応じてセキュリティグループは調整を行いましょう。(AWS Global Acceleratorのネットワーク・セキュリティ設計のために考えるべきこと | DevelopersIO

ルーティングの設定です。今回は最終的にターゲットグループは不要になりますが、ALB作成ウィザードではターゲットグループを指定しないで進めることはできないようです。今回はダミーのターゲットグループをいったんここで作成して進めます。なおターゲットとなるEC2は登録しません。

以上でALBの作成を行います。

ALBでリダイレクトの設定

ALBの作成ができたら、リスナーの項目からリダイレクト設定を行います。

まずはHTTPS:443を確認します。ALB作成直後は以下のように、ウィザードでダミーとして指定したターゲットグループに転送するよう設定されています。

これを以下のように、リダイレクトするように設定しました。リダイレクト先はドメイン(今回であればwww.example.com)を直接指定するほか、元の値#{host}をうまく活用してwww.#{host}とすることも可能なようです。(想定するexample.com以外のドメインでアクセスした場合の挙動が不安定になりますが。)

HTTP:80についてもリダイレクト先を設定しておきます。HTTPS:443で自ALB(example.com)にリダイレクトする、HTTP:80でwww.example.comにリダイレクトする、などいくつかバリエーションは考えられますが、今回はHTTPS:443でwww.example.comにリダイレクトさせる、としました。こちらはホスト部分をwww.#{host}として指定してみます。

リスナーの設定が完了したら、ターゲットグループは不要ですので削除してしまいます。

固定IPアドレスの確認とAレコード登録

ALBの作成ならびにリダイレクトの設定ができました。続いて、このALBのエンドポイントとなる固定IPアドレスを確認し、Aレコードとして登録します。固定IPアドレスを提供するGlobal Acceleratorについては、ALB作成ウィザード中での指定によりリソース作成などが完了しています。ALBの統合サービスの項目で確認してみましょう。静的IPアドレスセットの項目があります、こちらが固定のIPアドレスですね。

Global AcceleratorのマネジメントコンソールでもStatic IP address setが確認できます。

このGlobal AcceleratorのStatic IP address2つを、example.comのAレコードの値として登録します。先ほどのwww.example.comのレコード登録と同様、お名前.comに設定を行いました。

設定後、digコマンドで名前解決結果を確認しておきます。

% dig example.net

; <<>> DiG 9.10.6 <<>> example.net
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33361
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;example.net.                   IN      A

;; ANSWER SECTION:
example.net.            60      IN      A       35.XXX.XXX.215
example.net.            60      IN      A       52.XXX.XXX.164

;; Query time: 9 msec
;; SERVER: X.X.X.X#53(X.X.X.X)
;; WHEN: Tue Jul 20 12:54:27 JST 2021
;; MSG SIZE  rcvd: 72

リダイレクトされる挙動を確認してみる

設定ができたので、実際にリダイレクトされる挙動を確認してみます。まずはChromeブラウザでexample.comにアクセスしてみます。この際にデベロッパーツールでNetworkの項目をチェックします、 Preserve log にチェクを入れてリダイレクトされる場合の挙動も確認できるようにしました。

以下のように、example.comへのアクセスのステータスは301が返り、続いてwww.example.comにアクセスしていることがわかりますね。

Chromeのアドレスバーはパッと見example.comのままですが、実際に確認してみると(URL全体を常に表示を有効にする、もしくはアドレスバーをクリックしてみる)、www.example.comを表示している状態であることがわかります。

curlコマンドでも確認してみます。ステータスとして301が返り、Locationヘッダでwww.example.comがHTTPSで指定されていることがわかりますね。

% curl -i https://example.net/
HTTP/2 301
server: awselb/2.0
date: Mon, 19 Jul 2021 09:49:58 GMT
content-type: text/html
content-length: 134
location: https://www.example.net:443/

<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
</body>
</html>

HTTPでアクセスした場合も確認してみます。(以降、レスポンスボディは同じ内容なので省略します。)

% curl -I http://example.net/
HTTP/1.1 301 Moved Permanently
Server: awselb/2.0
Date: Mon, 19 Jul 2021 09:51:12 GMT
Content-Type: text/html
Content-Length: 134
Connection: keep-alive
Location: https://www.example.net:443/

ALBでリダイレクト設定を行なった際、HTTPについてはwww.#{host}にリダイレクトするように設定していました。(#{host}はもともとのHostヘッダの値。)こちらの挙動も抑えておきましょう。Global AcceleratorのDNS名a16dxxxxxxxxxxxxx.awsglobalaccelerator.comにアクセスしてみます。リダイレクトとなるのLocationヘッダ値、ドメイン名はwww.a16dxxxxxxxxxxxxx.awsglobalaccelerator.comとなりました。(実在しないのでアクセス不可となるはずです。)ALBのDNS名でも同様の事象となります。

% curl -I http://a16dxxxxxxxxxxxxx.awsglobalaccelerator.com/
HTTP/1.1 301 Moved Permanently
Server: awselb/2.0
Date: Mon, 19 Jul 2021 09:54:00 GMT
Content-Type: text/html
Content-Length: 134
Connection: keep-alive
Location: https://www.a16dxxxxxxxxxxxxx.awsglobalaccelerator.com:443/

HTTPSについてはリダイレクト先をwww.example.comと指定しているので、このような状況にはなりません。そもそもGlobal AcceleratorのDNS名(ALBのDNS名もですが)にHTTPSでアクセスしようとすると証明書に関する警告が表示されます。これを-kオプションで無視してレスポンスを確認してみましょう。Locationヘッダのドメイン名がwww.example.comとなっていますね。

% curl -I https://a16dxxxxxxxxxxxxx.awsglobalaccelerator.com/
curl: (60) SSL: no alternative certificate subject name matches target host name 'a16dxxxxxxxxxxxxx.awsglobalaccelerator.com'
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

% curl -k -I https://a16dxxxxxxxxxxxxx.awsglobalaccelerator.com/
HTTP/2 301
server: awselb/2.0
date: Mon, 19 Jul 2021 09:54:10 GMT
content-type: text/html
content-length: 134
location: https://www.example.net:443/

まとめ

ALBのリダイレクト機能とGlobal Acceleratorの固定IPアドレスを使って、AWSでフルマネージドで固定IPアドレスなリダイレクト環境を構成していみました。エントリ本文でも述べましたが、AWSでリダイレクト環境を構成する場合、一番の手段としてはS3+CloudFrontを考えましょう。今回のように事情によりその構成が取れない場合でも、いきなりEC2内でHTTPサーバを構築するなどと考えず、まずはAWSのマネージドサービスで解決できないか試行するの良いかと思います。(今回の私の思考がまさにこの例でしたね。)またこの「ALBを固定IPアドレス化してリダイレクトレスポンスを返す」構成については、それぞれ(Global AcceleratorならびにALBのリダイレクト機能)のアップデートなしには実現できなかったものです。改めてAWSの機能改善はすごいですね。(個人的には昔はこのような構成が取れなくてEC2でやるしかないかな、と考えたことがあり、それを引きずっていた感も否めません。)昔の「できない」情報に捉われず、改めてAWSの機能を確認することも重要だと思いました。