CloudFormation で OAI を使った CloudFront + S3 の静的コンテンツ配信インフラを作る
よく訓練されたアップル信者、都元です。年末に Fitbit Alta HR を買いました。 睡眠や心拍がほぼ24時間体制でトラッキングされるって面白いですね。え? アップルウォッうわなにをする
はじめに
さて、S3 + CloudFront で静的コンテンツ配信をしよう、というのはもう今さら言うまでもない鉄板構成だと思います。かつてAWSにおける静的コンテンツ配信パターンカタログ(アンチパターン含む)でご紹介した「横綱」パターンですね。
公開サイトとして、この構成を雑に作る場合
CloudFront を介して配信するということは基本的に公開サイトとして配信するユースケースが多いと思います。
つまり、原則としてはみんな CloudFront を介してコンテンツにアクセスして欲しいのですが、最悪 S3 に直接アクセスしてコンテンツを読まれたとしてもセキュリティ上は問題ない、ということです。
このような要件であれば、S3 の設定を Public にしてしまい、CloudFront からも(どこからでも) 自由にコンテンツを読み出せるように設定してしまうのが楽だと思います。
プライベートコンテンツを配信したい場合
一方で、CloudFront の署名付きURL(下記のリンクを参照)などの機能を使ってプライベートコンテンツを配信したい時は、前述のように S3 バケットを Public にしてしまうわけにはいきません。
このような時は、CloudFront の Origin Access Identity (以下、OAI) という機能を使います。 要するに S3 を公開状態にすることなく、S3 へのアクセスを CloudFront からのリクエストに絞るための仕組みです。詳細は次のエントリーを参照してください。
[CloudFront + S3]特定バケットに特定ディストリビューションのみからアクセスできるよう設定する
要するに次のような作業をします。
- S3 バケットを作成
- CloudFront の OAI を作成
- S3 バケットに、作成した OAI からのアクセスを許可するバケットポリシーを設定
- オリジンとして S3 バケットを設定、そしてオリジンアクセスの際にこの OAI を利用するように設定して、CloudFront distribution を作成
CloudFront + S3 with OAI の構成を CloudFormation で。
しかし、この構成の手動構築はそこそこ面倒です。こういう時は、CloudFormation でテンプレート化しておくのが吉でしょう。
ただ、私の古い記憶によると、CloudFormation はステップ 2 の Origin Access Identity 作成をサポートしていませんでした。当時やる気を失い、テンプレートを作らないでいた気がします。カスタムリソースを使うという手もありますが、いや、まぁ……ねぇ…w
しかし、先日あらためて調べてみたところ、いつの間にかサポートがありました。え、これいつの間にリリースされたの! 誰もブログ書いてないんじゃ…。やべえ、ということでいま筆を取っている次第です。
AWS::CloudFront::CloudFrontOriginAccessIdentity リソース
はい、テンプレート置いておきます。
AWSTemplateFormatVersion: 2010-09-09 Description: Static contents distribution using S3 and CloudFront. Resources: # S3 bucket contains static contents AssetsBucket: Type: AWS::S3::Bucket DeletionPolicy: Retain # S3 bucket policy to allow access from CloudFront OAI AssetsBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref AssetsBucket PolicyDocument: Statement: - Action: s3:GetObject Effect: Allow Resource: !Sub arn:aws:s3:::${AssetsBucket}/* Principal: AWS: !Sub arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${CloudFrontOriginAccessIdentity} # CloudFront Distribution for contents delivery AssetsDistribution: Type: AWS::CloudFront::Distribution Properties: DistributionConfig: Origins: - Id: S3Origin DomainName: !GetAtt AssetsBucket.DomainName S3OriginConfig: OriginAccessIdentity: !Sub origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity} Enabled: true DefaultRootObject: index.html Comment: !Sub ${AWS::StackName} distribution DefaultCacheBehavior: TargetOriginId: S3Origin ForwardedValues: QueryString: false ViewerProtocolPolicy: redirect-to-https CloudFrontOriginAccessIdentity: Type: AWS::CloudFront::CloudFrontOriginAccessIdentity Properties: CloudFrontOriginAccessIdentityConfig: Comment: !Ref AWS::StackName Outputs: URL: Value: !Join [ "", [ "https://", !GetAtt [ AssetsDistribution, DomainName ]]]
ご自由にご利用ください!