前置き
2022年8月末ごろにAWSより OriginAccessControl がリリースされました。
これに伴い、旧来の OriginAccessIdentity が非推奨と記載されるようになりました。
よし、では手元の cloudformation yaml をドキュメントに従って書き換えて OAC を使用するようにしよう。
おや?CloufFormation での OAC の作成方法は書いてあるが CloudFront に付ける方法が書いてないぞ。
Console, CLI, API は CloudFront へのアタッチ方も書いてあるのに。
不思議なこともあるもんだ。
まぁ誰か記事くらい書いてるやろ。
と思ったが無いんだなこれが。
誰も・・・
CloudFormation での OAC アタッチ方を書いていないのである!!!
というわけで CloufFormation で OAC の作成から CloudFormation へのアタッチまでをやったので記事を書きました。
OAC の強化点
折角なのでこれから使う OAC についても少し見ておきましょう。
AWS は OAC の注目すべき(OAIからの)強化点を以下としています。
- セキュリティ – OAC は、短期間のクレデンシャル、頻繁なクレデンシャルのローテーション、およびリソースベースのポリシーのような強化されたセキュリティプラクティスで実装されています。これらは、ディストリビューションのセキュリティポスチャを強化し、混乱する代理のような攻撃に対してより良い保護を提供します。
- 包括的な HTTP メソッドのサポート – OAC は GET、PUT、POST、PATCH、DELETE、OPTIONS、および HEAD をサポートしています。
- SSE-KMS – OAC は、SSE-KMS で暗号化された S3 オブジェクトのダウンロードとアップロードをサポートしています。
- すべての AWS リージョンでの S3 にアクセス – OAC は、既存のリージョンと将来のすべてのリージョンを含む、すべての AWS リージョンでの S3 へのアクセスをサポートしています。一方、OAI は既存の AWS リージョンと 2022 年 12 月までに開始されるリージョンでのみサポートされます。
逆に、現在の OAI でできないことは Amazon S3 オリジンへのアクセスの制限 - オリジンアクセスアイデンティティの使用 (レガシー、非推奨) で確認できます。
従来は cloudfront に OAI を設定して、S3 バケットポリシーにてこの OAI を許可することで S3 バケットやオブジェクトをパブリックにすることなく cloudfront からのアクセスのみを許可するようにアクセス制限を設けられました。
OAC ではこれに加えて S3 オブジェクトの SSE-KMS による暗号化に対応するようです。
(OAI では SSE-KMS で暗号化したオブジェクトを利用できなかった。(バケット内のオブジェクトが AWS Key Management Service (AWS KMS) を使用して暗号化されていないことを確認します))
実際の yaml
---
AWSTemplateFormatVersion: '2010-09-09'
Description: origin access control test.
Resources:
S3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: {bucket name}
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
OriginAccessControl:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Description: ''
Name: {origin access contlor name}
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: !GetAtt S3Bucket.RegionalDomainName
Id: oac-test-bucket
OriginAccessControlId: !GetAtt OriginAccessControl.Id
S3OriginConfig: {}
DefaultCacheBehavior:
ForwardedValues:
QueryString: 'false'
Cookies:
Forward: none
TargetOriginId: oac-test-bucket
ViewerProtocolPolicy: allow-all
Enabled: true
BucketPolicy:
Type: "AWS::S3::BucketPolicy"
Properties:
Bucket: !Ref S3Bucket
PolicyDocument:
Statement:
- Action: "s3:GetObject"
Effect: Allow
Resource: !Join
- ''
- - 'arn:aws:s3:::'
- !Ref S3Bucket
- /*
Principal:
Service: cloudfront.amazonaws.com
Condition:
StringEquals:
AWS:SourceArn: !Join
- ''
- - 'arn:aws:cloudfront::{your AWS account ID}:distribution/'
- !Ref CloudFrontDistribution
あまり OAC と関係のない項目は適当に Amazon CloudFront テンプレートスニペット の 「Amazon S3 オリジンを使用した Amazon CloudFront Distribution リソース」 あたりから値を拝借している。
private な s3 bucket を作り、同時に作成する cloudfront からのアクセスのみを許可した。
それぞれの項目に軽く触れていく
S3Bucket
S3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: {bucket name}
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
とりあえず PublicAccessBlockConfiguration
はすべて true
にしておいた。
- BlockPublicAcls - 新たに、バケットやオブジェクトの ACL をパブリックにすることや、パブリックなオブジェクトを配置することを禁止する。(= 作成も更新も禁止)
- IgnorePublicAcls - バケットとオブジェクトのパブリック ACL を無視する。
- BlockPublicPolicy - パブリックなバケットポリシー、アクセスポイントポリシーへの変更を禁止する。
- RestrictPublicBuckets - パブリックポリシーを持つバケットやアクセスポイントへのアクセスをバケット所有者のAWSサービスと承認されたユーザーのみに制限する。
総合して、現在のパブリック設定を無視し、新規にパブリック設定を作ることを禁止する。
OriginAccessControl
OriginAccessControl:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Description: ''
Name: {origin access contlor name}
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
これはほとんど Amazon S3 オリジンへのアクセスの制限 の例のまま。
詳細は AWS::CloudFront::OriginAccessControl
注意点
- 例では
DisplayName
と記載があるが、cloudformation ドキュメントではName
となっているのでそっちに従った -
Description
は非必須項目だが、空文字を許容するだけで項目自体が存在しないとエラーが出るようだ。
CloudFrontDistribution
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: !GetAtt S3Bucket.RegionalDomainName
Id: oac-test-bucket
OriginAccessControlId: !GetAtt OriginAccessControl.Id
S3OriginConfig: {}
DefaultCacheBehavior:
ForwardedValues:
QueryString: 'false'
Cookies:
Forward: none
TargetOriginId: oac-test-bucket
ViewerProtocolPolicy: allow-all
Enabled: true
とにかく、ここまでで作成した s3 origin へ oac を使ってアクセスする簡単な cloudfront を作成した。
S3 origin への OAC のアタッチだが、AWS::CloudFront::Distribution Origin に OriginAccessControlId
という項目が存在し、AWS::CloudFront::OriginAccessControl
にも Fn::GetAtt - Id
が存在したので与えてみたところうまくいった。
BucketPolicy
BucketPolicy:
Type: "AWS::S3::BucketPolicy"
Properties:
Bucket: !Ref S3Bucket
PolicyDocument:
Statement:
- Action: "s3:GetObject"
Effect: Allow
Resource: !Join
- ''
- - 'arn:aws:s3:::'
- !Ref S3Bucket
- /*
Principal:
Service: cloudfront.amazonaws.com
Condition:
StringEquals:
AWS:SourceArn: !Join
- ''
- - 'arn:aws:cloudfront::{your AWS account ID}:distribution/'
- !Ref CloudFrontDistribution
OAI では Principal
に OAI を指定して、OAI を実行元サービスとして許容していたが、OAC では実行元サービスは cloudfront となる。
Condition
に Amazon S3 オリジンへのアクセスの制限 の「S3 バケットへのアクセス許可をオリジンアクセスコントロールに付与する」 を参考に distribution を指定。
アクセスしてみる
作成された s3 へ適当なファイルを置いて、cloudfront のディストリビューションドメイン名を確認してブラウザからアクセスしてみます。
デフォルトルートオブジェクトは指定しなかったので適当にパスを付けて、
やったぜ。
念のため S3 オブジェクトへ直接アクセスもしておきましょう。
以上。
cloudformation での OAC 作成から cloudfront distribution へのアタッチまででした。
参考情報
- Amazon CloudFront でオリジンアクセスコントロール (OAC) をリリース
- Amazon CloudFront オリジンアクセスコントロール(OAC)のご紹介
- Amazon S3 オリジンへのアクセスの制限
- Amazon CloudFront テンプレートスニペット
- AWS::CloudFront::Distribution Origin
- AWS::CloudFront::OriginAccessControl
- CloudFront ディストリビューションのオリジンとして S3 ウェブサイトのエンドポイントを使用しています。403 Access Denied エラーが発生するのはなぜですか?