AWS

OACを使用してCloudFront経由でS3コンテンツを配信する

スポンサーリンク
OACを使用してCloudFront経由でS3コンテンツを配信する AWS
スポンサーリンク
スポンサーリンク

CloudFrontからS3コンテンツを配信する際に、OACでオリジンへのアクセスを制限する

以下のページで、S3バケットのコンテンツをCloudFrontから配信する際に、OAIを使用することで、オリジンへのアクセスを制限する方法をご紹介しました。

2022年8月にOAC(Origin Access Control)が発表されました。
AWS公式としては、OAIよりもOACを使用することを推奨しています。

OAC は以下をサポートしているため、OAC の使用をお勧めします。

すべての AWS リージョンのすべての Amazon S3 バケット (2022 年 12 月以降に開始されたオプトインリージョンを含む)

AWS KMS による Amazon S3 サーバー側の暗号化 (SSE-KMS)

Amazon S3 に対する動的なリクエスト (POST、PUT など)

Amazon S3 オリジンへのアクセスの制限

今回はOACを使用して、CloudFront経由でS3バケットにアクセスする方法を確認します。

構築する環境

Diagram of delivering S3 content via CloudFront using OAC

全体的な構成は冒頭のページと同様です。
CloudFrontのOACを作成し、S3バケットポリシーには、このOACからのアクセスを許可する設定を行います。

CloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。

awstut-fa/096 at main · awstut-an-r/awstut-fa
Contribute to awstut-an-r/awstut-fa development by creating an account on GitHub.

テンプレートファイルのポイント解説

S3バケット

Resources: Bucket: Type: AWS::S3::Bucket Properties: BucketName: !Ref Prefix AccessControl: Private
Code language: YAML (yaml)

コンテンツを配置するバケットです。
OACを使用する上で、S3バケット側は特別な設定は不要です。

OAC

Resources: OAC: Type: AWS::CloudFront::OriginAccessControl Properties: OriginAccessControlConfig: Name: !Ref Prefix OriginAccessControlOriginType: s3 SigningBehavior: always SigningProtocol: sigv4
Code language: YAML (yaml)

OACを作成する上で、重要なパラメータは以下の3つです。

1つ目はOriginAccessControlOriginTypeプロパティです。
本パラメータは「s3」のみ取り得ます。

2つ目はSigningBehaviorプロパティです。
本パラメータはCloudFrontがオリジン(S3)にアクセスする際に、署名するかに関するものです。
AWS公式では、以下の通り言及されています。

CloudFront が常に着信リクエストに署名するので、アプリケーションが常に動作することを保証するため、ほとんどのお客様は “ 署名リクエスト ” オプションを使用することをお勧めします。さらに、CloudFront がリクエストに署名することで、クライアントと CloudFront 間のデータ転送が少なくなり、アプリケーションのパフォーマンスが向上します。

Amazon CloudFront オリジンアクセスコントロール(OAC)のご紹介

上記に従い、常時署名リクエストするように「always」に設定します。

3つ目はSigningProtocolプロパティです。
本パラメータは「sigv4」のみ取り得ます。

CloudFront

Resources: Distribution: Type: AWS::CloudFront::Distribution Properties: DistributionConfig: DefaultCacheBehavior: AllowedMethods: - GET - HEAD CachedMethods: - GET - HEAD Compress: true ForwardedValues: Cookies: Forward: none QueryString: false TargetOriginId: !Ref BucketName ViewerProtocolPolicy: allow-all DefaultRootObject: index.html Enabled: true Origins: - DomainName: !Ref BucketRegionalDomainName Id: !Ref BucketName #CustomOriginConfig: OriginAccessControlId: !GetAtt OAC.Id S3OriginConfig: OriginAccessIdentity: "" PriceClass: PriceClass_All
Code language: YAML (yaml)

OACを使用する上で、CloudFrontの設定で重要な項目はOriginsプロパティです。
先ほど定義したOACのIDをOriginAccessControlIdプロパティに設定します。

S3OriginConfigプロパティもポイントです。
内部のOriginAccessIdentityプロパティに空文字列を指定します。
仮に上記を設定しない場合、CloudFormationスタック作成時に、以下のエラーが発生します。

Invalid request provided: Exactly one of CustomOriginConfig and S3OriginConfig must be specified

ちなみにCustomOriginConfigプロパティは、静的Webサイトホスティングを有効化したS3バケット用のパラメータですから、こちらは設定を行いません。

バケットポリシー

Resources: BucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref BucketName PolicyDocument: Statement: Action: - s3:GetObject Effect: Allow Principal: Service: - cloudfront.amazonaws.com Resource: !Sub "arn:aws:s3:::${BucketName}/*" Condition: StringEquals: AWS:SourceArn: !Sub "arn:aws:cloudfront::${AWS::AccountId}:distribution/${Distribution}"
Code language: YAML (yaml)

以下のAWS公式ページを参考に、バケットポリシーを定義します。

Amazon S3 オリジンへのアクセスの制限 - Amazon CloudFront
Amazon CloudFront オリジンアクセスコントロール (OAC) で、Amazon S3 オリジンへのアクセスを制限します。

先述のCloudFrontディストリビューションがプリンシパルの場合、オブジェクトの取得するアクションを許可する内容です。

(参考)CloudFormationカスタムリソース

Resources: CustomResource: Type: Custom::CustomResource Properties: ServiceToken: !GetAtt Function.Arn Function: Type: AWS::Lambda::Function Properties: Code: ZipFile: | import boto3 import cfnresponse import os bucket_name = os.environ['BUCKET_NAME'] object_name = 'index.html' object_body = """<html> <head></head> <body> <h1>index.html</h1> <p>{bucket_name}</p> </body> </html>""".format(bucket_name=bucket_name) content_type = 'text/html' char_code= 'utf-8' s3_client = boto3.client('s3') CREATE = 'Create' DELETE = 'Delete' response_data = {} def lambda_handler(event, context): try: if event['RequestType'] == CREATE: put_response = s3_client.put_object( Bucket=bucket_name, Key=object_name, Body=object_body.encode(char_code), ContentEncoding=char_code, ContentType=content_type) print(put_response) elif event['RequestType'] == DELETE: list_response = s3_client.list_objects_v2( Bucket=bucket_name) for obj in list_response['Contents']: delete_response = s3_client.delete_object( Bucket=bucket_name, Key=obj['Key']) print(delete_response) cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data) except Exception as e: print(e) cfnresponse.send(event, context, cfnresponse.FAILED, response_data) Environment: Variables: BUCKET_NAME: !Ref BucketName FunctionName: !Sub "${Prefix}-function" Handler: !Ref Handler Runtime: !Ref Runtime Role: !GetAtt FunctionRole.Arn
Code language: YAML (yaml)

CloudFormationカスタムリソースを使用して、S3バケットに自動的にオブジェクトを作成します。
今回は先述のS3バケット内にindex.htmlを作成します。

詳細につきましては、以下のページをご確認ください。

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。

  • CloudFrontディストリビューション:E3YPSL0CON945
  • CloudFrontドメイン名:d1ujnv40lgk4sa.cloudfront.net
  • OAC:fa-096
  • S3バケット:fa-096

作成されたリソースをAWS Management Consoleから確認します。
OACを確認します。

Detail of CloudFront 1.

OACが作成されています。
SigV4で常に署名を実施するように設定されていることがわかります。

CloudFrontディストリビューションに関連づいていることもわかります。

Detail of CloudFront 2.

CloudFrontディストリビューション側の設定ページを確認しても、OACの設定が有効化されていることがわかります。

またオリジンとしてS3バケットが指定されていることもわかります。

Detail of S3 1 .

バケット内にindex.htmlファイルが設置されています。
CloudFormationカスタムリソースに紐づくLambda関数によって、HTMLファイルが自動的に生成されて設置されました。

Detail of S3 2.

バケットポリシーを確認すると、CloudFrontをプリンシパルとして、S3バケットへのアクセスを許可する内容であることがわかります。

動作確認

準備が整いましたので、CloudFrontディストリビューションにアクセスします。

Detail of CloudFront 3.

S3バケット内のHTMLファイル(index.html)にアクセスすることができました。
本来バケットポリシーによって制限されているバケット内オブジェクトへのアクセスが、OACを使用することによって、CloudFront経由でのアクセスが許可されたということです。

次に直接S3バケットへアクセスします。

Detail of CloudFront 4.

拒否されました。
バケットポリシーが動作しており、直接のアクセスが制限されているということです。

まとめ

OACを使用して、CloudFront経由でS3バケットにアクセスする方法をご紹介しました。

タイトルとURLをコピーしました