はじめに
AWSサービスを用いて静的コンテンツを配信する場合、S3とCloudFrontを組み合わせて構築することが一般的かと思いますが、この際セキュリティを強化するためにOAC(Origin Access Control)
の設定が推奨されています。OACを設定することで、S3バケットへの直接的なアクセスを防ぎ、CloudFront経由の安全なアクセスだけを許可することが可能となります。
上記の構成をCDKで構築する場合、L2 Constructが提供されていなかったため、構築が少し手間でした。しかし、CDKのバージョン2.156.0
から、OACのL2 Constructがサポートされるようになりました。これにより簡単にOACを構成できるようになったので、早速試してみました。
OACとは
OAC(Origin Access Control)とは、CloudFrontとS3バケット間のセキュアなアクセスを制御するための仕組みです。元々OAI(Origin Access Identity)という方法があったのですが、現在ではOACの方が推奨される方法となっています。
詳しくは下記の記事をご覧ください。
https://dev.classmethod.jp/articles/amazon-cloudfront-origin-access-control/
動作環境
- Node.js 20.15.0
- TypeScript 5.5.2
- AWS CDK v2(2.156.0)
cdkのバージョン2.156.0からのサポートされた機能なので、2.156.0未満のバージョンを使用している場合はバージョンアップ対応をお願いします。
L2 Constructを使ったOACの実装
CloudFrontのdistributionを作成する時に、S3BucketOrigin.withOriginAccessControl
を使ってOriginとなるS3を指定することで、OACを設定しています。
app
ディレクトリにindex.htmlファイルを格納しており、このファイルを静的コンテンツ配信用のS3 バケットにdeployしています。
import {
RemovalPolicy,
Stack,
StackProps,
aws_cloudfront as cloudfront,
aws_cloudfront_origins as cloudfront_origins,
aws_s3 as s3,
aws_s3_deployment as s3_deployment,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class StaticSiteStack extends Stack {
constructor(scope: Construct, id: string, props: StackProps) {
super(scope, id, props);
// 静的コンテンツを配置する S3 バケットを作成
const staticContentBucket = new s3.Bucket(this, 'StaticContentBucket', {
removalPolicy: RemovalPolicy.DESTROY,
});
// CloudFront ディストリビューションを作成
const distribution = new cloudfront.Distribution(this, 'Distribution', {
defaultRootObject: 'index.html',
defaultBehavior: {
viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
origin: cloudfront_origins.S3BucketOrigin.withOriginAccessControl(staticContentBucket)
},
});
// 静的コンテンツをS3にデプロイ
new s3_deployment.BucketDeployment(this, 'staticContentDeploy', {
sources: [s3_deployment.Source.asset('./app')],
destinationBucket: staticContentBucket,
distribution: distribution,
distributionPaths: ['/*'],
});
}
}
<h1>Hello, World!</h1>
たったこれだけの記述でOACが設定できるようになりました。
動作確認
cdkで作成したリソースの設定が問題ないか、マネージメントコンソールから確認してみます。
ディストリビューションドメインからのアクセス確認
CloudFrontのディストリビューションドメイン名を確認して、ブラウザからアクセスしてみます。
Hello, World!が表示されました。
オリジンの設定の確認
また、CloudFrontのオリジンを確認してみるとOACが設定されていること確認できます。
直接S3にアクセスできないことの確認
次に静的コンテンツを設置したS3に直接アクセスしてみます。
Origin domain欄に記載されているURLにブラウザからアクセスしてみます。
ブラウザからS3に直接アクセスできないことも確認できました。
S3バケットポリシーの確認
静的コンテンツをデプロイしたS3バケットのバケットポリシーを確認してみます。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::staticwebstack-frontendstaticcontentbucketf9d324c0-yrfwytyz71ki/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::AccountId:distribution/E25JIDG0CN8B70"
}
}
}
]
}
上記のようなポリシーが作成されていて、cdkで作成したディストリビューションからのアクセスのみを許可していることがわかります。
(補足)L2がない場合のcdkでのOAC実装方法
以下の記事では、L2 Constructがサポートされていなかった時にcdkでOACを設定するやり方について紹介されています。
s3バケットポリシーの変更やCloudFrontのオリジン設定の変更などを記述する必要があり、結構手間だったんではないでしょうか。
https://zenn.dev/thyt_lab/articles/d6423c883882b7
まとめ
本記事では、OACのL2 Constructの使って、安全に静的コンテンツを配信する方法を試してみました。L2 ConstructがサポートされたことでCDKでの実装も簡単になったかと思うで、是非使っていきたいと思います。
参考
https://github.com/aws/aws-cdk/releases/tag/v2.156.0
https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudfront_origins-readme.html