[AWS CDK] CloudFrontの標準ログV2をカスタムリソースとして設定してみた
標準ログV2の設定をしたいけどCloudFormationですら対応していない
こんにちは、のんピ(@non____97)です。
皆さんはCloudFrontの標準ログV2をAWS CDKで設定したいなと思ったことはありますか? 私はあります。
標準ログV2により、パーティションキーやログのフォーマットやフィールドの指定が可能になります。
特にパーティションキーの設定ができるのは非常に嬉しいです。今までは以下記事で紹介しているように、S3バケットにログオブジェクトがPUTされたら、オブジェクトキーを変更する手間がかかりました。
これは積極的に標準ログV2を採用したいですね。
私は基本的に構築はAWS CDKで行っています。
しかし、残念ながら2025/1/28時点ではAWS CDKで標準ログV2の設定ができません。GitHubのIssueにも上がっています。
これはそもそも、CloudFormation側で標準ログV2をサポートしていないためです。
CloudFormationがサポートするまで待つのも、もどかしいです。
ということで、標準ログV2をカスタムリソースとして設定してみます。
APIを用いた場合の標準ログV2の設定プロセス
いきなり標準ログV2をAWS CDKで設定する前に、APIを用いた場合の標準ログV2の設定プロセスを確認します。
標準ログV2の詳細は以下AWS公式ドキュメントに記載されています。
CloudFrontディストリビューションと送信先のS3バケットが同一アカウントの場合、以下のような設定プロセスを踏みます。
- PutDeliverySourceでCloudFrontディストリビューションをログの送信元として定義する
- PutDeliveryDestinationでログの送信先を定義する
- 送信先のS3バケットのバケットポリシーにて、ログの送信元のARN(DeliverySource ARN != CloudFrontディストリビューションのARN)からの
PutObject
を許可する - CreateDeliveryでログの送信元と送信先の関連付けを行う
3の手順は先述のAWS公式ドキュメントに記載はありませんが、実際は必要になります。
バケットポリシーにて許可がない場合はAccess Denied for this Delivery Destination. Please make sure that you have correct permissions to access the Log Destination Resource.
とエラーになります。
マネジメントコンソールにて標準ログV2を設定する際にも以下のようにPutBucketPolicy
が叩かれていました。
{
"eventVersion": "1.11",
"userIdentity": {
"type": "AssumedRole",
"principalId": "<プリンシパルID>:<IAMユーザー名>",
"arn": "arn:aws:sts::<AWSアカウントID>:assumed-role/<iamロール名>/<セッション名>",
"accountId": "<AWSアカウントID>",
"accessKeyId": "ASIA6KUFAVPUWWDYOVBG",
"sessionContext": {
"sessionIssuer": {
"type": "Role",
"principalId": "<プリンシパルID>",
"arn": "arn:aws:iam::<AWSアカウントID>:role/<iamロール名>",
"accountId": "<AWSアカウントID>",
"userName": "<IAMユーザー名>"
},
"attributes": {
"creationDate": "2025-01-23T09:08:03Z",
"mfaAuthenticated": "true"
}
},
"invokedBy": "logs.amazonaws.com"
},
"eventTime": "2025-01-23T09:55:01Z",
"eventSource": "s3.amazonaws.com",
"eventName": "PutBucketPolicy",
"awsRegion": "us-east-1",
"sourceIPAddress": "logs.amazonaws.com",
"userAgent": "logs.amazonaws.com",
"requestParameters": {
"bucketPolicy": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AWSLogDeliveryWrite-732640224",
"Effect": "Allow",
"Principal": {
"Service": "delivery.logs.amazonaws.com"
},
"Action": [
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::aurora-postgresql-log/AWSLogs/<AWSアカウントID>/CloudFront/*"
],
"Condition": {
"StringEquals": {
"s3:x-amz-acl": [
"bucket-owner-full-control"
],
"aws:SourceAccount": [
"<AWSアカウントID>"
]
},
"ArnLike": {
"aws:SourceArn": [
"arn:aws:logs:us-east-1:<AWSアカウントID>:delivery-source:CreatedByCloudFront-E21YV8QMTCNCR6"
]
}
}
}
],
"Id": "AWSLogDeliveryWrite20150319"
},
"bucketName": "aurora-postgresql-log",
"Host": "aurora-postgresql-log.s3.us-east-1.amazonaws.com",
"policy": ""
},
"responseElements": null,
"additionalEventData": {
"SignatureVersion": "SigV4",
"CipherSuite": "TLS_AES_128_GCM_SHA256",
"bytesTransferredIn": 526,
"AuthenticationMethod": "AuthHeader",
"x-amz-id-2": "rvHUp7xb3FtGrHVw/wDpzKLekhlLVDDdUX8oYAdOKktg2G0oq5qH2WhD91NPFKatazbUmRxTnSg=",
"bytesTransferredOut": 0
},
"requestID": "Q1T768Y5F745V4ED",
"eventID": "a6b27fb9-429a-431c-bde8-146fe17d8d43",
"readOnly": false,
"resources": [
{
"accountId": "<AWSアカウントID>",
"type": "AWS::S3::Bucket",
"ARN": "arn:aws:s3:::aurora-postgresql-log"
}
],
"eventType": "AwsApiCall",
"managementEvent": true,
"recipientAccountId": "<AWSアカウントID>",
"sharedEventID": "bd7acfb6-d73d-41ff-ba54-889f03ad4395",
"vpcEndpointId": "logs.amazonaws.com",
"vpcEndpointAccountId": "logs.amazonaws.com",
"eventCategory": "Management"
}
また、1と2、4はいずれもCloudWatch LogsのAPIです。CloudFrontのAPIではないので注意しましょう。
その他の注意点としてはCreateDelivery
でプレフィックスを指定していない場合もAWSLogs/<AWSアカウントID>/CloudFront/
が必ず付与されます。一方、更新処理であるUpdateDeliveryConfigurationをする際はAWSLogs/<AWSアカウントID>/CloudFront/
が付与されません。
やってみた
検証環境
検証環境は以下のとおりです。
検証環境は全てAWS CDKでデプロイしました。使用したコードは以下GitHubリポジトリに保存しています。
こちらのベースとなったコードの詳細な説明は以下記事をご覧ください。
カスタムリソースの紹介
標準ログV2のカスタムリソース周りを紹介します。
今回はレガシー標準ログとV2を選択できるようにしています。
AWS CDKとしては以下のように定義をしています。
private configureLogAnalytics(props: ContentsDeliveryConstructProps) {
if (
!props.enableLogAnalytics?.length ||
!props.cloudFrontAccessLogBucketConstruct
) {
return;
}
// CloudFront Standard Log Legacy
if (props.enableLogAnalytics.includes("cloudFrontStandardLogLegacy")) {
const targetKeyPrefix = props.logFilePrefix
? `${props.logFilePrefix}/partitioned/${cdk.Stack.of(this).account}/${
this.distribution.distributionId
}/`
: `partitioned/${cdk.Stack.of(this).account}/${
this.distribution.distributionId
}/`;
const moveLogLambda = this.createMoveLogLambda(targetKeyPrefix);
this.configureMoveLogLambdaPermissions(props, moveLogLambda);
this.createLogEventRule(props, targetKeyPrefix, moveLogLambda);
}
// CloudFront Standard Log V2
if (props.enableLogAnalytics.includes("cloudFrontStandardLogV2")) {
// Remove CloudFront Standard Log Legacy
const cfnDistribution = this.distribution.node
.defaultChild as cdk.aws_cloudfront.CfnDistribution;
cfnDistribution.addPropertyDeletionOverride("DistributionConfig.Logging");
const logPrefix = this.getStandardLogV2Prefix(props.logFilePrefix);
props.cloudFrontAccessLogBucketConstruct.bucket.addToResourcePolicy(
new cdk.aws_iam.PolicyStatement({
actions: ["s3:PutObject"],
effect: cdk.aws_iam.Effect.ALLOW,
principals: [
new cdk.aws_iam.ServicePrincipal("delivery.logs.amazonaws.com"),
],
resources: [
`${props.cloudFrontAccessLogBucketConstruct.bucket.bucketArn}/${logPrefix.awsLogObjectPrefix}*`,
],
conditions: {
StringEquals: {
"s3:x-amz-acl": "bucket-owner-full-control",
"aws:SourceAccount": cdk.Stack.of(this).account,
},
ArnLike: {
"aws:SourceArn": `arn:aws:logs:${cdk.Stack.of(this).region}:${
cdk.Stack.of(this).account
}:delivery-source:cf-${this.distribution.distributionId}`,
},
},
})
);
const configCloudFrontStandardLogV2Lambda =
new cdk.aws_lambda_nodejs.NodejsFunction(
this,
"ConfigCloudFrontStandardLogV2Lambda",
{
entry: path.join(
__dirname,
"../src/lambda/standard-logging-v2/index.ts"
),
bundling: {
minify: true,
tsconfig: path.join(__dirname, "../src/lambda/tsconfig.json"),
format: cdk.aws_lambda_nodejs.OutputFormat.ESM,
bundleAwsSDK: true,
mainFields: ["module", "main"],
banner:
"const require = (await import('node:module')).createRequire(import.meta.url);const __filename = (await import('node:url')).fileURLToPath(import.meta.url);const __dirname = (await import('node:path')).dirname(__filename);",
},
runtime: cdk.aws_lambda.Runtime.NODEJS_22_X,
architecture: cdk.aws_lambda.Architecture.ARM_64,
timeout: cdk.Duration.seconds(30),
initialPolicy: [
new cdk.aws_iam.PolicyStatement({
effect: cdk.aws_iam.Effect.ALLOW,
actions: [
"logs:CreateDelivery",
"logs:PutDeliveryDestination",
"logs:PutDeliverySource",
"logs:DeleteDelivery",
"logs:DeleteDeliveryDestination",
"logs:DeleteDeliverySource",
"logs:UpdateDeliveryConfiguration",
],
resources: ["*"],
}),
new cdk.aws_iam.PolicyStatement({
effect: cdk.aws_iam.Effect.ALLOW,
actions: ["cloudfront:AllowVendedLogDeliveryForResource"],
resources: [
`arn:aws:cloudfront::${
cdk.Stack.of(this).account
}:distribution/${this.distribution.distributionId}`,
],
}),
],
}
);
const configCloudFrontStandardLogV2Provider =
new cdk.custom_resources.Provider(
this,
"ConfigCloudFrontStandardLogV2Provider",
{
onEventHandler: configCloudFrontStandardLogV2Lambda,
}
);
new cdk.CustomResource(this, "ConfigCloudFrontStandardLogV2", {
serviceToken: configCloudFrontStandardLogV2Provider.serviceToken,
serviceTimeout: cdk.Duration.seconds(60),
properties: {
DistributionId: this.distribution.distributionId,
DistributionArn: `arn:aws:cloudfront::${
cdk.Stack.of(this).account
}:distribution/${this.distribution.distributionId}`,
BucketArn: props.cloudFrontAccessLogBucketConstruct.bucket.bucketArn,
LogPrefix: logPrefix.logPrefix,
},
});
}
}
ポイントをかいつまんで紹介します。
以下ではログ送信先のS3バケットのバケットポリシーに、ポリシーステートメントを追加しています。Conditionが複雑であったためgrantPut()
は使用していません。
props.cloudFrontAccessLogBucketConstruct.bucket.addToResourcePolicy(
new cdk.aws_iam.PolicyStatement({
actions: ["s3:PutObject"],
effect: cdk.aws_iam.Effect.ALLOW,
principals: [
new cdk.aws_iam.ServicePrincipal("delivery.logs.amazonaws.com"),
],
resources: [
`${props.cloudFrontAccessLogBucketConstruct.bucket.bucketArn}/${logPrefix.awsLogObjectPrefix}*`,
],
conditions: {
StringEquals: {
"s3:x-amz-acl": "bucket-owner-full-control",
"aws:SourceAccount": cdk.Stack.of(this).account,
},
ArnLike: {
"aws:SourceArn": `arn:aws:logs:${cdk.Stack.of(this).region}:${
cdk.Stack.of(this).account
}:delivery-source:cf-${this.distribution.distributionId}`,
},
},
})
);
以下ではカスタムリソースのLambda関数を定義しています。
const configCloudFrontStandardLogV2Lambda =
new cdk.aws_lambda_nodejs.NodejsFunction(
this,
"ConfigCloudFrontStandardLogV2Lambda",
{
entry: path.join(
__dirname,
"../src/lambda/standard-logging-v2/index.ts"
),
bundling: {
minify: true,
tsconfig: path.join(__dirname, "../src/lambda/tsconfig.json"),
format: cdk.aws_lambda_nodejs.OutputFormat.ESM,
bundleAwsSDK: true,
mainFields: ["module", "main"],
banner:
"const require = (await import('node:module')).createRequire(import.meta.url);const __filename = (await import('node:url')).fileURLToPath(import.meta.url);const __dirname = (await import('node:path')).dirname(__filename);",
},
runtime: cdk.aws_lambda.Runtime.NODEJS_22_X,
architecture: cdk.aws_lambda.Architecture.ARM_64,
timeout: cdk.Duration.seconds(30),
initialPolicy: [
new cdk.aws_iam.PolicyStatement({
effect: cdk.aws_iam.Effect.ALLOW,
actions: [
"logs:CreateDelivery",
"logs:PutDeliveryDestination",
"logs:PutDeliverySource",
"logs:DeleteDelivery",
"logs:DeleteDeliveryDestination",
"logs:DeleteDeliverySource",
"logs:UpdateDeliveryConfiguration",
],
resources: ["*"],
}),
new cdk.aws_iam.PolicyStatement({
effect: cdk.aws_iam.Effect.ALLOW,
actions: ["cloudfront:AllowVendedLogDeliveryForResource"],
resources: [
`arn:aws:cloudfront::${
cdk.Stack.of(this).account
}:distribution/${this.distribution.distributionId}`,
],
}),
],
}
);
2025/1/28時点のNode.js 22のLambda関数のランタイムにバンドルされているAWS SDK for JavaScript v3は3.632.0
であり、UpdateDeliveryConfiguration
が含まれていませんでした。
AWS SDKのバージョンは以下で確認可能です。
import packageJson from '@aws-sdk/client-cloudwatch-logs/package.json' with { type: 'json' };
export const handler = async () => ({ version: packageJson.version });
GitHubを確認したところUpdateDeliveryConfiguration
が追加されたのは3.643
でした。
そのため、対応としてbundleAwsSDK: true
として、ローカルにインストールしたAWS SDKをバンドルするように定義しています。
また、ESMでバンドルする場合Dynamic require of "buffer" is not supported
と出力されます。こちらの対応として以下で紹介されているようにスクリプトにbanner挿入するようにしました。
あとはこちらのLambda関数を用いてCustom Resource Provider Frameworkでカスタムリソースを設定しています。Custom Resource Provider Frameworkは以下記事が分かりやすいです。
Lambda関数内では先述の1と2、4の処理を行っています。また、Update
時はUpdateDeliveryConfiguration
を、Delete
時は作成した各種リソースを削除するように定義しています。
Athenaで使用するGlueテーブルの紹介
Athenaで使用するGlueテーブルもAWS CDKで定義しています。
今回は以下のようにParquetを使用するようにしました。
const cloudFrontStandardLogV2: LogTable = {
location:
"s3://#{logBucketName}/AWSLogs/#{logSrcResourceAccountId}/CloudFront/#{prefix}#{logSrcResourceId}",
storageLocationTemplate: "#{location}/${partition_date}",
tableInput: {
name: "cloudfront_access_log",
tableType: "EXTERNAL_TABLE",
storageDescriptor: {
columns: [
{ name: "date", type: "string" },
{ name: "time", type: "string" },
{ name: "x_edge_location", type: "string" },
{ name: "sc_bytes", type: "string" },
{ name: "c_ip", type: "string" },
{ name: "cs_method", type: "string" },
{ name: "cs_host", type: "string" },
{ name: "cs_uri_stem", type: "string" },
{ name: "sc_status", type: "string" },
{ name: "cs_referer", type: "string" },
{ name: "cs_user_agent", type: "string" },
{ name: "cs_uri_query", type: "string" },
{ name: "cs_cookie", type: "string" },
{ name: "x_edge_result_type", type: "string" },
{ name: "x_edge_request_id", type: "string" },
{ name: "x_host_header", type: "string" },
{ name: "cs_protocol", type: "string" },
{ name: "cs_bytes", type: "string" },
{ name: "time_taken", type: "string" },
{ name: "x_forwarded_for", type: "string" },
{ name: "ssl_protocol", type: "string" },
{ name: "ssl_cipher", type: "string" },
{ name: "x_edge_response_result_type", type: "string" },
{ name: "cs_protocol_version", type: "string" },
{ name: "fle_status", type: "string" },
{ name: "fle_encrypted_fields", type: "string" },
{ name: "c_port", type: "string" },
{ name: "time_to_first_byte", type: "string" },
{ name: "x_edge_detailed_result_type", type: "string" },
{ name: "sc_content_type", type: "string" },
{ name: "sc_content_len", type: "string" },
{ name: "sc_range_start", type: "string" },
{ name: "sc_range_end", type: "string" },
],
inputFormat:
"org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat",
outputFormat:
"org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat",
serdeInfo: {
serializationLibrary:
"org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe",
},
},
parameters: {
has_encrypted_data: true,
classification: "parquet",
"projection.enabled": true,
"projection.partition_date.type": "date",
"projection.partition_date.interval": "1",
"projection.partition_date.interval.unit": "DAYS",
"projection.partition_date.range": "NOW-1YEARS, NOW+9HOUR",
"projection.partition_date.format": "yyyy/MM/dd",
},
partitionKeys: [{ name: "partition_date", type: "string" }],
},
};
動作確認
デプロイをして、実際にログ出力できるのか確認します。
マネジメントコンソールを確認すると、確かに標準ログV2で設定されていることが分かります。
AWS CLIでも確認しておきます。
> aws logs describe-delivery-destinations
{
"deliveryDestinations": [
{
"name": "cf-E21YV8QMTCNCR6-websitestack-cloudfrontaccesslogbucketcons",
"arn": "arn:aws:logs:us-east-1:<AWSアカウントID>:delivery-destination:cf-E21YV8QMTCNCR6-websitestack-cloudfrontaccesslogbucketcons",
"deliveryDestinationType": "S3",
"outputFormat": "parquet",
"deliveryDestinationConfiguration": {
"destinationResourceArn": "arn:aws:s3:::websitestack-cloudfrontaccesslogbucketconstruct221-bwzpr29ygir6"
}
}
]
}
> aws logs describe-delivery-sources
{
"deliverySources": [
{
"name": "cf-E21YV8QMTCNCR6",
"arn": "arn:aws:logs:us-east-1:<AWSアカウントID>:delivery-source:cf-E21YV8QMTCNCR6",
"resourceArns": [
"arn:aws:cloudfront::<AWSアカウントID>:distribution/E21YV8QMTCNCR6"
],
"service": "cloudfront",
"logType": "ACCESS_LOGS"
}
]
}
> aws logs describe-deliveries
{
"deliveries": [
{
"id": "A3U6gznrrsa513iw",
"arn": "arn:aws:logs:us-east-1:<AWSアカウントID>:delivery:A3U6gznrrsa513iw",
"deliverySourceName": "cf-E21YV8QMTCNCR6",
"deliveryDestinationArn": "arn:aws:logs:us-east-1:<AWSアカウントID>:delivery-destination:cf-E21YV8QMTCNCR6-websitestack-cloudfrontaccesslogbucketcons"
}
]
}
ログ送信先のS3バケットのオブジェクト一覧を確認します。
> s3-tree websitestack-cloudfrontaccesslogbucketconstruct221-bwzpr29ygir6
websitestack-cloudfrontaccesslogbucketconstruct221-bwzpr29ygir6
└── AWSLogs
└── <AWSアカウントID>
└── CloudFront
└── E21YV8QMTCNCR6
└── 2025
└── 01
├── 27
│ ├── 08
│ │ ├── E21YV8QMTCNCR6.2025-01-27-08.0e02c932.parquet
│ │ └── E21YV8QMTCNCR6.2025-01-27-08.e08777cf.parquet
│ ├── 09
│ │ └── E21YV8QMTCNCR6.2025-01-27-09.48db76a5.parquet
│ ├── 11
│ │ └── E21YV8QMTCNCR6.2025-01-27-11.e683c889.parquet
│ ├── 12
│ │ └── E21YV8QMTCNCR6.2025-01-27-12.b789c834.parquet
│ ├── 16
│ │ └── E21YV8QMTCNCR6.2025-01-27-16.3978d74c.parquet
│ └── 21
│ ├── E21YV8QMTCNCR6.2025-01-27-21.78bb1a81.parquet
│ └── E21YV8QMTCNCR6.2025-01-27-21.cc331e5a.parquet
└── 28
└── 01
└── E21YV8QMTCNCR6.2025-01-28-01.76ba7939.parquet
16 directories, 9 files
意図したパーティションになっていますね。
Athenaによる標準ログのクエリ
Athenaによる標準ログのクエリも試します。
SELECT
*
FROM
"access_log"."cloudfront_access_log"
WHERE
partition_date = '2025/01/28'
にて、1/28のログを出力します。
問題なく出力されましたね。
SELECT
date,
time,
cs_uri_stem,
sc_status,
x_edge_result_type,
time_taken,
sc_content_type
FROM
"access_log"."cloudfront_access_log"
WHERE
partition_date = '2025/01/28' AND
x_edge_result_type = 'Miss'
にて、キャッシュヒットしなかったリクエストのログを出力します。
こちらも意図したとおり出力されました。
カスタムリソースの削除
カスタムリソースが正常に削除できるかも確認しておきます。
> npx cdk diff --no-change-set
Bundling asset WebsiteStack/ContentsDeliveryConstruct/RewriteToWebpLambdaEdge/Code/Stage...
cdk.out/bundling-temp-a0b0205c5ae59be4b27b17777568e9cab4257b303b38ab098d49bca58284c947/index.mjs 731b
⚡ Done in 5ms
Stack WebsiteStack
IAM Statement Changes
┌───┬───────────────────────────────────────────────────────────────┬────────┬───────────────────────────────────────────────────────────────┬───────────────────────────────────────────────────────────────┬───────────────────────────────────────────────────────────────┐
│ │ Resource │ Effect │ Action │ Principal │ Condition │
├───┼───────────────────────────────────────────────────────────────┼────────┼───────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────┤
│ - │ ${CloudFrontAccessLogBucketConstruct/Default.Arn}/AWSLogs/984 │ Allow │ s3:PutObject │ Service:delivery.logs.amazonaws.com │ "StringEquals": { │
│ │ 900217833/CloudFront/* │ │ │ │ "s3:x-amz-acl": "bucket-owner-full-control", │
│ │ │ │ │ │ "aws:SourceAccount": "<AWSアカウントID>" │
│ │ │ │ │ │ }, │
│ │ │ │ │ │ "ArnLike": { │
│ │ │ │ │ │ "aws:SourceArn": "arn:aws:logs:us-east-1:<AWSアカウントID>:deliv │
│ │ │ │ │ │ ery-source:cf-${ContentsDeliveryConstruct/Default}" │
│ │ │ │ │ │ } │
├───┼───────────────────────────────────────────────────────────────┼────────┼───────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────┤
│ - │ ${ContentsDeliveryConstruct/ConfigCloudFrontStandardLogV2Lamb │ Allow │ lambda:InvokeFunction │ AWS:${ContentsDeliveryConstruct/ConfigCloudFrontStandardLogV2 │ │
│ │ da.Arn} │ │ │ Provider/framework-onEvent/ServiceRole} │ │
│ │ ${ContentsDeliveryConstruct/ConfigCloudFrontStandardLogV2Lamb │ │ │ │ │
│ │ da.Arn}:* │ │ │ │ │
├───┼───────────────────────────────────────────────────────────────┼────────┼───────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────┤
│ - │ ${ContentsDeliveryConstruct/ConfigCloudFrontStandardLogV2Lamb │ Allow │ sts:AssumeRole │ Service:lambda.amazonaws.com │ │
│ │ da/ServiceRole.Arn} │ │ │ │ │
├───┼───────────────────────────────────────────────────────────────┼────────┼───────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────┤
│ - │ ${ContentsDeliveryConstruct/ConfigCloudFrontStandardLogV2Prov │ Allow │ sts:AssumeRole │ Service:lambda.amazonaws.com │ │
│ │ ider/framework-onEvent/ServiceRole.Arn} │ │ │ │ │
├───┼───────────────────────────────────────────────────────────────┼────────┼───────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────┤
│ - │ * │ Allow │ logs:CreateDelivery │ AWS:${ContentsDeliveryConstruct/ConfigCloudFrontStandardLogV2 │ │
│ │ │ │ logs:DeleteDelivery │ Lambda/ServiceRole} │ │
│ │ │ │ logs:DeleteDeliveryDestination │ │ │
│ │ │ │ logs:DeleteDeliverySource │ │ │
│ │ │ │ logs:PutDeliveryDestination │ │ │
│ │ │ │ logs:PutDeliverySource │ │ │
│ │ │ │ logs:UpdateDeliveryConfiguration │ │ │
├───┼───────────────────────────────────────────────────────────────┼────────┼───────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────┤
│ - │ arn:aws:cloudfront::<AWSアカウントID>:distribution/${ContentsDeliv │ Allow │ cloudfront:AllowVendedLogDeliveryForResource │ AWS:${ContentsDeliveryConstruct/ConfigCloudFrontStandardLogV2 │ │
│ │ eryConstruct/Default} │ │ │ Lambda/ServiceRole} │ │
└───┴───────────────────────────────────────────────────────────────┴────────┴───────────────────────────────────────────────────────────────┴───────────────────────────────────────────────────────────────┴───────────────────────────────────────────────────────────────┘
IAM Policy Changes
┌───┬──────────────────────────────────────────────────────────────────────────────────────────────────┬────────────────────────────────────────────────────────────────────────────────┐
│ │ Resource │ Managed Policy ARN │
├───┼──────────────────────────────────────────────────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ - │ ${ContentsDeliveryConstruct/ConfigCloudFrontStandardLogV2Lambda/ServiceRole} │ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole │
├───┼──────────────────────────────────────────────────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ - │ ${ContentsDeliveryConstruct/ConfigCloudFrontStandardLogV2Provider/framework-onEvent/ServiceRole} │ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole │
└───┴──────────────────────────────────────────────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)
Resources
[-] AWS::IAM::Role ContentsDeliveryConstruct/ConfigCloudFrontStandardLogV2Lambda/ServiceRole ContentsDeliveryConstructConfigCloudFrontStandardLogV2LambdaServiceRole7A20A853 destroy
[-] AWS::IAM::Policy ContentsDeliveryConstruct/ConfigCloudFrontStandardLogV2Lambda/ServiceRole/DefaultPolicy ContentsDeliveryConstructConfigCloudFrontStandardLogV2LambdaServiceRoleDefaultPolicyBF9E9901 destroy
[-] AWS::Lambda::Function ContentsDeliveryConstruct/ConfigCloudFrontStandardLogV2Lambda ContentsDeliveryConstructConfigCloudFrontStandardLogV2Lambda144F3709 destroy
[-] AWS::IAM::Role ContentsDeliveryConstruct/ConfigCloudFrontStandardLogV2Provider/framework-onEvent/ServiceRole ContentsDeliveryConstructConfigCloudFrontStandardLogV2ProviderframeworkonEventServiceRole00533326 destroy
[-] AWS::IAM::Policy ContentsDeliveryConstruct/ConfigCloudFrontStandardLogV2Provider/framework-onEvent/ServiceRole/DefaultPolicy ContentsDeliveryConstructConfigCloudFrontStandardLogV2ProviderframeworkonEventServiceRoleDefaultPolicy63645C4E destroy
[-] AWS::Lambda::Function ContentsDeliveryConstruct/ConfigCloudFrontStandardLogV2Provider/framework-onEvent ContentsDeliveryConstructConfigCloudFrontStandardLogV2ProviderframeworkonEvent9D7253EE destroy
[-] AWS::CloudFormation::CustomResource ContentsDeliveryConstruct/ConfigCloudFrontStandardLogV2 ContentsDeliveryConstructConfigCloudFrontStandardLogV2FDB7D8D0 destroy
[-] AWS::Glue::Table LogAnalyticsConstruct/CloudFrontAccessLogTable LogAnalyticsConstructCloudFrontAccessLogTable60944DF1 destroy
[~] AWS::S3::BucketPolicy CloudFrontAccessLogBucketConstruct/Default/Policy CloudFrontAccessLogBucketConstructPolicy1FDA13BB
└─ [~] PolicyDocument
└─ [~] .Statement:
└─ @@ -71,45 +71,5 @@
[ ] ]
[ ] }
[ ] ]
[-] },
[-] {
[-] "Action": "s3:PutObject",
[-] "Condition": {
[-] "StringEquals": {
[-] "s3:x-amz-acl": "bucket-owner-full-control",
[-] "aws:SourceAccount": "<AWSアカウントID>"
[-] },
[-] "ArnLike": {
[-] "aws:SourceArn": {
[-] "Fn::Join": [
[-] "",
[-] [
[-] "arn:aws:logs:us-east-1:<AWSアカウントID>:delivery-source:cf-",
[-] {
[-] "Ref": "ContentsDeliveryConstructE854BE87"
[-] }
[-] ]
[-] ]
[-] }
[-] }
[-] },
[-] "Effect": "Allow",
[-] "Principal": {
[-] "Service": "delivery.logs.amazonaws.com"
[-] },
[-] "Resource": {
[-] "Fn::Join": [
[-] "",
[-] [
[-] {
[-] "Fn::GetAtt": [
[-] "CloudFrontAccessLogBucketConstruct22103865",
[-] "Arn"
[-] ]
[-] },
[-] "/AWSLogs/<AWSアカウントID>/CloudFront/*"
[-] ]
[-] ]
[-] }
[ ] }
[ ] ]
[~] AWS::CloudFront::Distribution ContentsDeliveryConstruct/Default ContentsDeliveryConstructE854BE87
└─ [~] DistributionConfig
└─ [+] Added: .Logging
✨ Number of stacks with differences: 1
> npx cdk deploy
Bundling asset WebsiteStack/ContentsDeliveryConstruct/RewriteToWebpLambdaEdge/Code/Stage...
cdk.out/bundling-temp-a0b0205c5ae59be4b27b17777568e9cab4257b303b38ab098d49bca58284c947/index.mjs 731b
⚡ Done in 9ms
✨ Synthesis time: 8.87s
WebsiteStack: start: Building c15d5653758b0df7d3d183ae2a98b2e6c8fdfc779da56f25c1b0c61bae64a987:<AWSアカウントID>-us-east-1
WebsiteStack: success: Built c15d5653758b0df7d3d183ae2a98b2e6c8fdfc779da56f25c1b0c61bae64a987:<AWSアカウントID>-us-east-1
WebsiteStack: start: Publishing c15d5653758b0df7d3d183ae2a98b2e6c8fdfc779da56f25c1b0c61bae64a987:<AWSアカウントID>-us-east-1
WebsiteStack: success: Published c15d5653758b0df7d3d183ae2a98b2e6c8fdfc779da56f25c1b0c61bae64a987:<AWSアカウントID>-us-east-1
WebsiteStack: deploying... [1/1]
WebsiteStack: creating CloudFormation changeset...
WebsiteStack | 0/14 | 10:36:29 | UPDATE_IN_PROGRESS | AWS::CloudFormation::Stack | WebsiteStack User Initiated
WebsiteStack | 0/14 | 10:36:34 | UPDATE_IN_PROGRESS | AWS::CDK::Metadata | CDKMetadata/Default (CDKMetadata)
WebsiteStack | 0/14 | 10:36:35 | UPDATE_IN_PROGRESS | AWS::S3::BucketPolicy | CloudFrontAccessLogBucketConstruct/Default/Policy (CloudFrontAccessLogBucketConstructPolicy1FDA13BB)
WebsiteStack | 1/14 | 10:36:35 | UPDATE_COMPLETE | AWS::CDK::Metadata | CDKMetadata/Default (CDKMetadata)
WebsiteStack | 2/14 | 10:36:36 | UPDATE_COMPLETE | AWS::S3::BucketPolicy | CloudFrontAccessLogBucketConstruct/Default/Policy (CloudFrontAccessLogBucketConstructPolicy1FDA13BB)
WebsiteStack | 2/14 | 10:36:37 | UPDATE_IN_PROGRESS | AWS::CloudFront::Distribution | ContentsDeliveryConstruct/Default (ContentsDeliveryConstructE854BE87)
2/14 Currently in progress: WebsiteStack, ContentsDeliveryConstructE854BE87
WebsiteStack | 3/14 | 10:38:05 | UPDATE_COMPLETE | AWS::CloudFront::Distribution | ContentsDeliveryConstruct/Default (ContentsDeliveryConstructE854BE87)
WebsiteStack | 4/14 | 10:38:07 | UPDATE_COMPLETE_CLEA | AWS::CloudFormation::Stack | WebsiteStack
WebsiteStack | 4/14 | 10:38:08 | DELETE_IN_PROGRESS | AWS::Glue::Table | LogAnalyticsConstructCloudFrontAccessLogTable60944DF1
WebsiteStack | 4/14 | 10:38:08 | DELETE_IN_PROGRESS | AWS::CloudFormation::CustomResource | ContentsDeliveryConstructConfigCloudFrontStandardLogV2FDB7D8D0
WebsiteStack | 5/14 | 10:38:09 | DELETE_COMPLETE | AWS::Glue::Table | LogAnalyticsConstructCloudFrontAccessLogTable60944DF1
WebsiteStack | 6/14 | 10:38:14 | DELETE_COMPLETE | AWS::CloudFormation::CustomResource | ContentsDeliveryConstructConfigCloudFrontStandardLogV2FDB7D8D0
WebsiteStack | 6/14 | 10:38:14 | DELETE_IN_PROGRESS | AWS::Lambda::Function | ContentsDeliveryConstructConfigCloudFrontStandardLogV2ProviderframeworkonEvent9D7253EE
WebsiteStack | 7/14 | 10:38:18 | DELETE_COMPLETE | AWS::Lambda::Function | ContentsDeliveryConstructConfigCloudFrontStandardLogV2ProviderframeworkonEvent9D7253EE
WebsiteStack | 7/14 | 10:38:19 | DELETE_IN_PROGRESS | AWS::IAM::Policy | ContentsDeliveryConstructConfigCloudFrontStandardLogV2ProviderframeworkonEventServiceRoleDefaultPolicy63645C4E
WebsiteStack | 8/14 | 10:38:20 | DELETE_COMPLETE | AWS::IAM::Policy | ContentsDeliveryConstructConfigCloudFrontStandardLogV2ProviderframeworkonEventServiceRoleDefaultPolicy63645C4E
WebsiteStack | 8/14 | 10:38:20 | DELETE_IN_PROGRESS | AWS::IAM::Role | ContentsDeliveryConstructConfigCloudFrontStandardLogV2ProviderframeworkonEventServiceRole00533326
WebsiteStack | 8/14 | 10:38:20 | DELETE_IN_PROGRESS | AWS::Lambda::Function | ContentsDeliveryConstructConfigCloudFrontStandardLogV2Lambda144F3709
WebsiteStack | 9/14 | 10:38:24 | DELETE_COMPLETE | AWS::Lambda::Function | ContentsDeliveryConstructConfigCloudFrontStandardLogV2Lambda144F3709
WebsiteStack | 9/14 | 10:38:24 | DELETE_IN_PROGRESS | AWS::IAM::Policy | ContentsDeliveryConstructConfigCloudFrontStandardLogV2LambdaServiceRoleDefaultPolicyBF9E9901
WebsiteStack | 10/14 | 10:38:25 | DELETE_COMPLETE | AWS::IAM::Policy | ContentsDeliveryConstructConfigCloudFrontStandardLogV2LambdaServiceRoleDefaultPolicyBF9E9901
WebsiteStack | 10/14 | 10:38:26 | DELETE_IN_PROGRESS | AWS::IAM::Role | ContentsDeliveryConstructConfigCloudFrontStandardLogV2LambdaServiceRole7A20A853
WebsiteStack | 11/14 | 10:38:30 | DELETE_COMPLETE | AWS::IAM::Role | ContentsDeliveryConstructConfigCloudFrontStandardLogV2ProviderframeworkonEventServiceRole00533326
WebsiteStack | 12/14 | 10:38:38 | DELETE_COMPLETE | AWS::IAM::Role | ContentsDeliveryConstructConfigCloudFrontStandardLogV2LambdaServiceRole7A20A853
WebsiteStack | 13/14 | 10:38:39 | UPDATE_COMPLETE | AWS::CloudFormation::Stack | WebsiteStack
✅ WebsiteStack
✨ Deployment time: 158.87s
Stack ARN:
arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/WebsiteStack/aeeadb90-d96b-11ef-a0e7-0afff9169823
✨ Total time: 167.73s
正常に削除できたようです。
AWS CLIで確認してみます。
> aws logs describe-delivery-destinations
{
"deliveryDestinations": []
}
> aws logs describe-delivery-sources
{
"deliverySources": []
}
> aws logs describe-deliveries
{
"deliveries": []
}
確かに削除されていますね。
早くCloudFormationでサポートして欲しい
AWS CDKを用いてCloudFrontの標準ログV2をカスタムリソースとして設定してみました。
カスタムリソースを使えば、大体のことはなんでもできますが、手間ではあります。早くCloudFormationでサポートして欲しいですね。
この記事が誰かの助けになれば幸いです。
以上、クラウド事業本部 コンサルティング部の のんピ(@non____97)でした!