2020年9月13日日曜日

ipv6対応のCloudFront+S3をCloudFormationで作る

 
ipv6対応のCloudFront+S3をCloudFormationで作ってみました。
検証環境の構成イメージは下図のとおり。


[MEMO]

  • CloudFrontは、下記の独自ドメインでアクセスできるようにします。
    • https://blue21.tk・・・ipv4/ipv6対応
    • https://www.blue21.tk・・・ipv4のみ
  • CloudFrontは、特定のIPアドレスのみリクエストを許可するようにします。(WAFでアクセス制限)
  • S3には、静的コンテンツを格納し、CloudFrontからのリクエストのみ許可します。(OAIでアクセス制限)
  • ACMとWAFは、CloudFront用なので us-east-1 に作成します。(AWSの制約)
  • ACMで証明書を作成し、Route53でDNS検証します。なお、証明書はCloudFrontに登録します。
  • Route53のNameServerをドメイン・プロバイダに登録します。


環境構築


## 作業環境(ローカル環境)

構築作業は、WSL2(ubuntu20.04)で実施します。
なお、AWSのリージョンは us-east-1を使用します。
  • Windows10
  • WSL2(ubuntu20.04)
  • docker 19.03.12
  • make 4.2.1
  • aws-cli 1.17.14

1. aws-cli の設定


aws-cli実行時はプロファイルを指定します。プロファイルの設定は下記のとおり。
  • blue21 という名称でプロファイルを作成
  • リージョンは us-east-1 を使用し, Output形式は json
  • 管理者権限のアクセスキーを使用

2. ソース一式のdownload


環境構築に必要なCloudFormationテンプレートなどは、Bitbucketに登録しています。
Bitbucketの下記URLからダウンロードできます。

レポジトリの内容は以下のとおり。
.
├── README.md
├── bin
│   ├── Makefile
│   ├── README.md
│   ├── cfn_validate.sh
│   └── cfn_wait.sh
├── cfn
│   ├── Makefile
│   ├── README.md
│   ├── cfn_cf.yml
│   └── cfn_r53.yml
├── htdocs
│   ├── index.html
│   └── sorry.html
└── img
    ├── image01.drawio
    └── image01.png

3.独自ドメインの取得


検証用に無料の独自ドメイン(blue21.tk)を取得して、Route53 にパブリックのホストゾーンを作成しました。(参考にした手順は、下記URLを参照)
Route53のホストゾーンは、aws-cliとCloudFormationで作成しました。
aws-cli コマンドをMakefileに記述しているので、cfnディレクトリで下記コマンドを実行するとCloudFormationのスタックを作成します。
make に指定する変数は以下のとおり
  • DOMAIN_NAME・・・独自ドメイン名
$ make cfnr53 DOMAIN_NAME=blue21.tk

コマンドが終了すると、
Route53に下図のようなホストゾーンが作成されます。


Route53のネームサーバをドメイン・プロバイダに登録後、下記コマンドで変更が反映されたことを確認します。
ネームサーバが表示されたらOKです。
$ dig blue21.tk @8.8.8.8 NS

; <<>> DiG 9.16.1-Ubuntu <<>> blue21.tk @8.8.8.8 NS
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2465
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;blue21.tk.                     IN      NS

;; ANSWER SECTION:
blue21.tk.              21588   IN      NS      ns-1424.awsdns-50.org.
blue21.tk.              21588   IN      NS      ns-1611.awsdns-09.co.uk.
blue21.tk.              21588   IN      NS      ns-499.awsdns-62.com.
blue21.tk.              21588   IN      NS      ns-751.awsdns-29.net.

;; Query time: 20 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Thu Sep 10 09:58:04 JST 2020
;; MSG SIZE  rcvd: 178

4. IPアドレスの確認


CloudFrontにアクセスするクライアント(私の場合は自宅)のIPアドレスを確認します。
下記URLで、ipv4 と ipv6 のIPアドレスを確認できます。
下図は表示例です。
確認したIPアドレスは、後続の手順で使用します。


4.CloudFront+S3+WAF+ACM構築


構築は、aws-cliとCloudFormationで行います。
aws-cliのコマンドはMakefileに記述しています。
cfnディレクトリで、下記のmakeコマンドを実行すると、CloudFormationのスタックを作成します。
make に指定する変数は以下のとおり
  • DOMAIN_NAME・・・独自ドメイン名
  • HOSTED_ZONE_ID・・・Route53に作成したホストゾーンのID
  • ALLOW_CIDR_V4・・・アクセスを許可するパブリックIPアドレス(ipv4)
  • ALLOW_CIDR_V6・・・アクセスを許可するパブリックIPアドレス(ipv6)
$ make cfncf DOMAIN_NAME=blue21.tk HOSTED_ZONE_ID=Zxxx ALLOW_CIDR_V4=1.2.3.4/32 ALLOW_CIDR_V6=2001:xxx/128

上記コマンド終了後、
cfnディレクトリで下記コマンドを実行すると、作成したスタック一覧を参照できます。
このコマンドはスタック名に "Blue21" を含むものをリストします。
$ aws cloudformation describe-stacks \
--profile blue21 \
--query 'Stacks[?contains(StackName,`Blue21`)].{StackName:StackName,StackStatus:StackStatus,Desc:Description}' \
--output table
----------------------------------------------------------
|                     DescribeStacks                     |
+-----------------+------------------+-------------------+
|      Desc       |    StackName     |    StackStatus    |
+-----------------+------------------+-------------------+
|  CloudFront & S3|  Blue21Cf00PoC   |  CREATE_COMPLETE  |
|  R53 public zone|  Blue21R5300PoC  |  CREATE_COMPLETE  |
+-----------------+------------------+-------------------+

動作確認


AWS環境確認


Route53のレコードは下図のとおり。
AレコードとAAAAレコードを作成しています。


ACMの証明書は下図のとおり。


WAF(v2)は下図のとおり。


CloudFrontは下図のとおり
  • オリジンはS3のみ。
  • S3バケットにアクセスログを格納します。
  • WAFでブロックした場合、WAFは403を返しますが、CloudFrontで503に変更して、エラーページを返すようにしています。


S3バケットは下図のとおり。
なお、S3バケットには2つのディレクトリが存在します。
  • cflogs ・・・ CloudFrontのアクセスログ格納
  • htdocs ・・・ 静的なWEBコンテンツ格納


サンプルのWEBコンテンツをデプロイ


動作確認用のサンプルページをS3バケットにアップロードします。
aws-cli コマンドをMakefileに記述しているので、
cfnディレクトリで下記コマンドを実行するとアップロードできます。
$ make s3deploy

下記コマンドで、S3バケットの中身をリストできます。
2つの html ファイルがあればOKです。
$ make s3ls
aws s3 ls s3://blue21cf00poc-s3bucket-2nwhp37a58d4/htdocs/ --recursive --profile blue21
2020-09-10 16:20:11        212 htdocs/index.html
2020-09-10 16:20:11        214 htdocs/sorry.html

ipv4 でリクエスト


ipv4のみ対応のネットワーク(WSL2のubuntu)から、curlコマンドでCloudFrontにリクエストします。
$ curl https://blue21.tk

CloudFront(https://blue21.tk)にリクエストすると
下図のように CloudFrontアクセスログには ipv4のIPアドレスが記録されます。


CloudFront(https://www.blue21.tk)にリクエストしても、上記と同じようにipv4のIPアドレスがログに記録されます。

ipv6でリクエスト


ipv4/ipv6対応のネットワーク(Windows10)から、ChromeブラウザでCloudFrontにリクエストします。(下図のように表示されます)


CloudFront(https://blue21.tk)にリクエストすると
下図のように CloudFrontアクセスログには ipv6のIPアドレスが記録されます。


CloudFront(https://www.blue21.tk)にリクエストすると、ipv4のIPアドレスがログに記録されます。
CloudFrontは ipv6 有効化していますが、www.blue21.tk は AAAAレコードを登録していないので名前解決できず、ipv4のIPアドレスで通信しています。

環境破棄


AWSコンソールで下記のスタックを上から順番に削除します。
  • スタック(Blue21Cf00PoC)を削除する前に、S3バケットを空にしないと失敗します
  • スタック(Blue21R5300PoC)を削除する前に、ACM用のCNAMEレコードを削除しないと失敗します。
----------------------------------------------------------
|                     DescribeStacks                     |
+-----------------+------------------+-------------------+
|      Desc       |    StackName     |    StackStatus    |
+-----------------+------------------+-------------------+
|  CloudFront & S3|  Blue21Cf00PoC   |  CREATE_COMPLETE  |
|  R53 public zone|  Blue21R5300PoC  |  CREATE_COMPLETE  |
+-----------------+------------------+-------------------+