🚀
【AWSCDK】CloudFront+S3でOACを使いたい(L2)
今までCloudFront+S3でOACを使いたい場合はL1で細工していたのですが、v2.156.0
で晴れてL2でのサポートが行われました!
早速試していきましょう!
OAIで対応していた時の記事
前提
- AWSCDK v2.156.0がインストールされていること
OAIでの実装
v2.156.0
以前の実装方法は以下の通り。
OriginAccessIdentity
を作成し、バケットに権限付与します。
lib/cdkstack.ts
import { RemovalPolicy, Stack, type StackProps } from "aws-cdk-lib";
import { Distribution, OriginAccessIdentity } from "aws-cdk-lib/aws-cloudfront";
import { S3Origin } from "aws-cdk-lib/aws-cloudfront-origins";
import { Bucket } from "aws-cdk-lib/aws-s3";
import { BucketDeployment, Source } from "aws-cdk-lib/aws-s3-deployment";
import type { Construct } from "constructs";
export class AwsCdkCloudfrontStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// S3
const bucket = new Bucket(this, "MyBucket", {
removalPolicy: RemovalPolicy.DESTROY,
autoDeleteObjects: true,
});
// OAI
const originAccessIdentity = new OriginAccessIdentity(
this,
"OriginAccessIdentity",
);
// grant read permission to the OAI
bucket.grantRead(originAccessIdentity);
// CloudFront
const distribution = new Distribution(this, "Distribution", {
defaultRootObject: "index.html",
defaultBehavior: {
origin: new S3Origin(bucket, {
originAccessIdentity,
}),
},
});
// deploy
new BucketDeployment(this, "DeployWebsite", {
sources: [Source.asset("../out")],
destinationBucket: bucket,
distribution,
distributionPaths: ["/*"],
});
}
}
OAIの時に使用していたS3Origin
は非推奨になっていました。
デプロイが完了した後、CloudFormationで確認するとOAIが作成されていることを確認できます。
CloudFront側でも確認。
Distribution URLにアクセスすると、デプロイしたアプリが表示されます。
OACでの実装
S3Origin
が非推奨になり、S3BucketOrigin
が新たに用意されています。
S3BucketOrigin.withOriginAccessControl
を使って、OACを設定していきます。
lib/cdkstack.ts
import { RemovalPolicy, Stack, type StackProps } from "aws-cdk-lib";
import { Distribution } from "aws-cdk-lib/aws-cloudfront";
import { S3BucketOrigin } from "aws-cdk-lib/aws-cloudfront-origins";
import { Bucket } from "aws-cdk-lib/aws-s3";
import { BucketDeployment, Source } from "aws-cdk-lib/aws-s3-deployment";
import type { Construct } from "constructs";
export class AwsCdkCloudfrontStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// s3
const bucket = new Bucket(this, "MyBucket", {
removalPolicy: RemovalPolicy.DESTROY,
autoDeleteObjects: true,
});
// cloudfront
const distribution = new Distribution(this, "Distribution", {
defaultRootObject: "index.html",
defaultBehavior: {
origin: S3BucketOrigin.withOriginAccessIdentity(bucket),
},
});
// deploy
new BucketDeployment(this, "DeployWebsite", {
sources: [Source.asset("../out")],
destinationBucket: bucket,
distribution,
distributionPaths: ["/*"],
});
}
}
OAIとOACのdiff
lib/cdkstack.ts
import { RemovalPolicy, Stack, type StackProps } from "aws-cdk-lib";
- import { Distribution, OriginAccessIdentity } from "aws-cdk-lib/aws-cloudfront";
- import { S3Origin } from "aws-cdk-lib/aws-cloudfront-origins";
+ import { Distribution } from "aws-cdk-lib/aws-cloudfront";
+ import { S3BucketOrigin } from "aws-cdk-lib/aws-cloudfront-origins";
import { Bucket } from "aws-cdk-lib/aws-s3";
import { BucketDeployment, Source } from "aws-cdk-lib/aws-s3-deployment";
import type { Construct } from "constructs";
export class AwsCdkCloudfrontStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// s3
const bucket = new Bucket(this, "MyBucket", {
removalPolicy: RemovalPolicy.DESTROY,
autoDeleteObjects: true,
});
- // OAI
- const originAccessIdentity = new OriginAccessIdentity(
- this,
- "OriginAccessIdentity",
- );
- // grant read permission to the OAI
- bucket.grantRead(originAccessIdentity);
// cloudfront
const distribution = new Distribution(this, "Distribution", {
defaultRootObject: "index.html",
defaultBehavior: {
- origin: new S3Origin(bucket, {
- originAccessIdentity,
- }),
+ origin: S3BucketOrigin.withOriginAccessControl(bucket),
},
});
// deploy
new BucketDeployment(this, "DeployWebsite", {
sources: [Source.asset("../out")],
destinationBucket: bucket,
distribution,
distributionPaths: ["/*"],
});
}
}
リソースの差分は以下の通り。
PrincipalがCanonicalUser
からService
に変わっていることがわかります。
cdk diff
Stack AwsCdkCloudfrontStack
Hold on while we create a read-only change set to get a diff with accurate replacement information (use --no-change-set to use a less accurate but faster template-only diff)
IAM Statement Changes
┌───┬────────────────────────────────────────────┬────────┬────────────────────────────────────────────┬────────────────────────────────────────────┬─────────────────────────────────────────────┐
│ │ Resource │ Effect │ Action │ Principal │ Condition │
├───┼────────────────────────────────────────────┼────────┼────────────────────────────────────────────┼────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ - │ ${MyBucket.Arn} │ Allow │ s3:GetBucket* │ CanonicalUser:${OriginAccessIdentity.S3Can │ │
│ │ ${MyBucket.Arn}/* │ │ s3:GetObject* │ onicalUserId} │ │
│ │ │ │ s3:List* │ │ │
├───┼────────────────────────────────────────────┼────────┼────────────────────────────────────────────┼────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ - │ ${MyBucket.Arn}/* │ Allow │ s3:GetObject │ CanonicalUser:${OriginAccessIdentity.S3Can │ │
│ │ │ │ │ onicalUserId} │ │
├───┼────────────────────────────────────────────┼────────┼────────────────────────────────────────────┼────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ + │ ${MyBucket.Arn}/* │ Allow │ s3:GetObject │ Service:cloudfront.amazonaws.com │ "StringEquals": { │
│ │ │ │ │ │ "AWS:SourceArn": "arn:${AWS::Partition}:c │
│ │ │ │ │ │ loudfront::${AWS::AccountId}:distribution/$ │
│ │ │ │ │ │ {Distribution}" │
│ │ │ │ │ │ } │
└───┴────────────────────────────────────────────┴────────┴────────────────────────────────────────────┴────────────────────────────────────────────┴─────────────────────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)
Resources
[-] AWS::CloudFront::CloudFrontOriginAccessIdentity OriginAccessIdentity OriginAccessIdentityDF1E3CAC destroy
[+] AWS::CloudFront::OriginAccessControl Distribution/Origin1/S3OriginAccessControl DistributionOrigin1S3OriginAccessControlEB606076
[~] AWS::S3::BucketPolicy MyBucket/Policy MyBucketPolicyE7FBAC7B
└─ [~] PolicyDocument
└─ [~] .Statement:
└─ @@ -39,53 +39,33 @@
[ ] ]
[ ] },
[ ] {
[-] "Action": [
[-] "s3:GetBucket*",
[-] "s3:GetObject*",
[-] "s3:List*"
[-] ],
[-] "Effect": "Allow",
[-] "Principal": {
[-] "CanonicalUser": {
[-] "Fn::GetAtt": [
[-] "OriginAccessIdentityDF1E3CAC",
[-] "S3CanonicalUserId"
[-] ]
[+] "Action": "s3:GetObject",
[+] "Condition": {
[+] "StringEquals": {
[+] "AWS:SourceArn": {
[+] "Fn::Join": [
[+] "",
[+] [
[+] "arn:",
[+] {
[+] "Ref": "AWS::Partition"
[+] },
[+] ":cloudfront::",
[+] {
[+] "Ref": "AWS::AccountId"
[+] },
[+] ":distribution/",
[+] {
[+] "Ref": "Distribution830FAC52"
[+] }
[+] ]
[+] ]
[+] }
[ ] }
[ ] },
[-] "Resource": [
[-] {
[-] "Fn::GetAtt": [
[-] "MyBucketF68F3FF0",
[-] "Arn"
[-] ]
[-] },
[-] {
[-] "Fn::Join": [
[-] "",
[-] [
[-] {
[-] "Fn::GetAtt": [
[-] "MyBucketF68F3FF0",
[-] "Arn"
[-] ]
[-] },
[-] "/*"
[-] ]
[-] ]
[-] }
[-] ]
[-] },
[-] {
[-] "Action": "s3:GetObject",
[ ] "Effect": "Allow",
[ ] "Principal": {
[-] "CanonicalUser": {
[-] "Fn::GetAtt": [
[-] "OriginAccessIdentityDF1E3CAC",
[-] "S3CanonicalUserId"
[-] ]
[-] }
[+] "Service": "cloudfront.amazonaws.com"
[ ] },
[ ] "Resource": {
[ ] "Fn::Join": [
[~] AWS::CloudFront::Distribution Distribution Distribution830FAC52
└─ [~] DistributionConfig
└─ [~] .Origins:
└─ @@ -7,18 +7,14 @@
[ ] ]
[ ] },
[ ] "Id": "AwsCdkCloudfrontStackDistributionOrigin1C6C3A1F0",
[+] "OriginAccessControlId": {
[+] "Fn::GetAtt": [
[+] "DistributionOrigin1S3OriginAccessControlEB606076",
[+] "Id"
[+] ]
[+] },
[ ] "S3OriginConfig": {
[-] "OriginAccessIdentity": {
[-] "Fn::Join": [
[-] "",
[-] [
[-] "origin-access-identity/cloudfront/",
[-] {
[-] "Ref": "OriginAccessIdentityDF1E3CAC"
[-] }
[-] ]
[-] ]
[-] }
[+] "OriginAccessIdentity": ""
[ ] }
[ ] }
[ ] ]
✨ Number of stacks with differences: 1
リソースのデプロイ後CloudFormationにて確認すると、OACが作成されています。
CloudFrontのオリジンアクセスについてもOACに変わっていることが確認できます。
Distribution URLにアクセスすると、OAIと変わらずデプロイしたアプリが表示されます。
まとめ
L2にてOACの対応ができるようになったのは待ちに待ったアップデートでした。(ありがたや)
CDKで対応するのは大変だったためマネコンから実施する人もいたのではないでしょうか。
この記事が誰かの参考になると嬉しいです。
Discussion