見出し画像

CloudFront で代替ドメイン名を CloudFormation を使って設定する場合にはまる罠

Solution Architect の t_maru です。

今回は CloudFront の Distribution に代替ドメイン名 (CNAME) を CloudFormation により設定する場合に遭遇する可能性がある罠についてお話します。

1 点注意事項があります。この記事の内容は 2022/8 時点での状況のため、皆様がこの記事をご覧になっているときには私が遭遇した問題が起きない可能性もありますのでご了承ください。

CloudFront とドメイン名

CloudFront を使ってコンテンツを配信する際、デフォルトでは `.cloudfront.net` というドメイン名が使われコンテンツ配信されることになります。このドメインについては、AWS 側で SSL 証明書も付与してくれるので、ちょっとした動作確認やコンテンツ配信で使うには手間が少なく便利だと思います。

ただし、独自のサービスを展開する場合、サイトの信頼性やブランディングといった観点でドメインを取得して、Web サービスや API に割当を行って使うことが多いと思います。

CloudFront にドメイン名を割り当てる事自体はもともと想定されているユースケースであり、AWS の公式ドキュメントにも設定方法が掲載されています。

下記、AWS 公式のドキュメントです。
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/CNAMEs.html

おおまかな流れとしては下記のようになります。

  1. ドメインを取得する (既に持っているドメインでも良い)

  2. 使用する予定のドメイン or サブドメインに対して SSL 証明書を生成

  3. CloudFront の Distribution にドメインと SSL 証明書を割り当てる

  4. DNS サービスにて CNAME の登録を行う

上記のいずれの手順においても AWS のサービスを使用することができるので、AWS 利用に関して制約がない場合は AWS のサービスで完結すると比較的運用が楽になると思います。

CloudFormation の必要性

さて、タイトルにもありますように今回は CloudFormation も登場します。

機能の動作確認をしたい場合やリリース前にそれほど厳密なチェックが不要な場合は 1 つの環境があれば事足りるため、何度も設定が必要なものでもなければ、手動設定で良いというケースもあると思います。

一方、複数環境が存在しており、特定の環境で動作することを確認してから別の環境に同様の設定を反映するなどの手順がある場合、Cloud リソースのデプロイも自動化されている方が、リリースまでにかかる時間と品質 (手順書を作ってダブルチェックしたとしてもヒューマンエラーはゼロにはできない) という観点でメリットが大きいと思います。

AWS に話を戻すと、AWS ではリソースをコード (YAML or JSON) として定義し、リソースのデプロイ (構築) を自動化するサービスとして CloudFormation というものが存在しています。現在ではマルチクラウドに対応したデプロイツールなども複数存在していると思いますが、 AWS に完結している場合は CloudFormation を使うのが一番シンプルで良いと思います。

また、最近では AWS が Cloud Development Kit (CDK) というツールを公開しており、これを使用することで TypeScript、Python、Java、Go などの慣れ親しんだ言語を使って AWS リソースの定義を行うこともできますが、デプロイの際は裏側で CloudFormation が使われています。

CDK の詳細については、下記の公式ドキュメントを御覧ください。
https://docs.aws.amazon.com/cdk/v2/guide/home.html

CloudFormation を使って CloudFront の CNAME を設定する際の落とし穴

本題です。今回 CloudFormation を使って管理され、CloudFront より配信されている Web システムに対して CNAME を設定する場合に遭遇し、解決まで多少時間を要してしまった落とし穴について解説します。

まず、下記のものは既に設定及び作成済みであるとします。

  • ドメインの取得及び Route53 の Host zone への登録

  • CloudFront に設定する予定のドメイン名に対する SSL 証明書の作成 (us-east-1 の AWS Certificate Manager)

ドメイン及び証明書の設定・作成は完了しているので冒頭で紹介した手順でいくと次はいよいよ CloudFront の Distribution に対してドメイン名と SSL 証明書を割り当てる作業となります。

さて、今回は CloudFormation により CloudFront に CNAME を設定するので AWS の公式ドキュメントから CloudFront Distribution の Template についてのドキュメントを確認します。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-distributionconfig.html

まず今回 CloudFront の Distribution に設定するドメイン名を `Aliases` というプロパティに記載します。プロパティ一覧を見ると `CNAMEs` というプロパティも存在していますが、こちらは現時点では使用できないプロパティなのでご注意ください。(こちらについては上記のドキュメントの中でも使えないプロパティであることは明示されているため、あまり問題になることはないと思います。)

次に設定が必要なプロパティは `ViewerCertificate` になりますが、こちらに罠が潜んでいます。

ViewerCertificate の設定値については下記のページに詳細があります。
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-viewercertificate.html

こちらは設定項目はそこまで多くないため、上記のドキュメントより YAML で記載する場合のプロパティを下記に転記しました。

AcmCertificateArn: String
CloudFrontDefaultCertificate: Boolean
IamCertificateId: String
MinimumProtocolVersion: String
SslSupportMethod: String

今回は ACM (AWS Certificate Manager) に登録した SSL 証明書を使うため、`AcmCertificateArn` を設定することになるため、 `IamCertificateId` は設定しません。

`MinimumProtocolVersion` や `SslSupportMethod` に関しては、システムの要件に合わせて選択してもらえれば特に問題は発生しないと思います。

さて、最後に `CloudFrontDefaultCertificate` の設定ですが、ここに罠が潜んでいます。

※ 冒頭でも記載しましたが、2022/8 時点での状況のため、皆様がこの記事をご覧になっているときは今回の問題が起きない可能性もあります。ご了承ください。

先程のドキュメントで `CloudFrontDefaultCertificate` の説明を読むと、下記のような表記になっていました。(英語のドキュメントを要約して記載しています)

  • CloudFront のデフォルトのドメイン名 (.cloudfront.net) を使用する場合は true に設定

  • `Aliases` を使用する場合はこの項目は false に設定し、下記のフィールドを設定する必要がある

    • ACMCertificateArn or IAMCertificateId (両方でなく一方の値を指定)。 CloudFormation では、これらのフィールド名は AcmCertificateArn, IamCertificateId で、大文字、小文字に注意。

    • MinimumProtocolVersion

    • SSLSupportMethod (ただし、CloudFormation でのフィールド名は SslSupportMethod なので注意)

この記載に従って私は下記のような設定を作りました。

※ CNAME を設定するために必要な項目のみを記載しているので、この設定だけではデプロイできませんのでご注意ください。また、ドメイン名や ARN についてはサンプルとして本来使用したものとは別のものを記載しています。

Aliases:
  - "xxx.example.com"
ViewerCertificate:
  AcmCertificateArn: "arn:aws:acm:us-east-1:<アカウント番号>:certificate/<証明書番号>"
  CloudFrontDefaultCertificate: false
  MinimumProtocolVersion: "TLSv1.2_2021"
  SslSupportMethod: "sni-only"

先程のドキュメントの通り、 `CloudFrontDefaultCertificate` を false に設定する代わりに AcmCertificateArn、MinimumProtocolVersion、SslSupportMethod を設定しているので、間違ったことはしていない・・・はずですが、この設定で CloudFormation デプロイを走らせ、Console を見ていると下記のようなエラーメッセージが表示され、デプロイが失敗します。

CloudFormation で発生したエラー

このメッセージを見たときの私の感想は ??? という表現が一番適切かなと思います(笑)

このメッセージにかかれているプロパティはすべて適切に設定されているはずなので、他のプロパティで設定ミスをしたかなと思い、色々と設定を変えて再デプロイなど実験を行い小一時間ほど時間を使ってしまいましたが、最終的にエラーを起こさずにデプロイできた設定は下記となります。

Aliases:
  - "xxx.example.com"
ViewerCertificate:
  AcmCertificateArn: "arn:aws:acm:us-east-1:<アカウント番号>:certificate/<証明書番号>"
  MinimumProtocolVersion: "TLSv1.2_2021"
  SslSupportMethod: "sni-only"

先程と何が違うかというと、`CloudFrontDefaultCertificate` をそもそもテンプレートに含めていないという点です。
エラーが解消したときの私の気持ちは、`・・・。・・・そこかよ!!!`

先程掲載した CloudFormation のエラーメッセージには、`Exactly one of [AcmCertificateArn, CloudFrontDefaultCertificate, IamCertificateId] needs to be specified.` という記載があるので、どれか 1 つのみを設定するようにとのことなので、このメッセージの通りではあるのですが、 先に読んでいた CloudFormation template の reference では、 Aliases を設定する場合は CloudFrontDefaultCertificate を false に設定し、必要なパラメータを設定するようにとの記載があったので、そこではまってしまったというのが今回の顛末でした。

ということで、長くなってしまいましたが、 `CloudFormation で CloudFront に CNAME を設定する場合は CloudFrontDefaultCertificate をテンプレートに記載しない` ように注意しましょう。

まとめ

今回は CloudFormation を使って CloudFront に代替ドメイン名を設定する際の注意点を説明しました。

結論としては、 `CloudFrontDefaultCertificate` というプロパティをテンプレートに記載しないことで余計なエラーに遭遇せず設定が完了します。

冒頭にも書きましたが、この事象は皆様がこの記事を読まれたときには発生しないかもしれませんが、もし同様のエラーでお困りの方がいらっしゃいましたら参考にしていただければ幸いです。

この記事が気に入ったらサポートをしてみませんか?