[AWS CDK] CloudFrontの標準ログV2をカスタムリソースとして設定してみた

[AWS CDK] CloudFrontの標準ログV2をカスタムリソースとして設定してみた

早くCloudFormationでサポートして欲しい
Clock Icon2025.01.28

標準ログV2の設定をしたいけどCloudFormationですら対応していない

こんにちは、のんピ(@non____97)です。

皆さんはCloudFrontの標準ログV2をAWS CDKで設定したいなと思ったことはありますか? 私はあります。

標準ログV2により、パーティションキーやログのフォーマットやフィールドの指定が可能になります。

https://dev.classmethod.jp/articles/cloudfront-access-log-update-202411/

特にパーティションキーの設定ができるのは非常に嬉しいです。今までは以下記事で紹介しているように、S3バケットにログオブジェクトがPUTされたら、オブジェクトキーを変更する手間がかかりました。

https://dev.classmethod.jp/articles/aws-cdk-cloudfront-s3-website-log-analytics/

これは積極的に標準ログV2を採用したいですね。

私は基本的に構築はAWS CDKで行っています。

しかし、残念ながら2025/1/28時点ではAWS CDKで標準ログV2の設定ができません。GitHubのIssueにも上がっています。

https://github.com/aws/aws-cdk/issues/32813

これはそもそも、CloudFormation側で標準ログV2をサポートしていないためです。

CloudFormationがサポートするまで待つのも、もどかしいです。

ということで、標準ログV2をカスタムリソースとして設定してみます。

APIを用いた場合の標準ログV2の設定プロセス

いきなり標準ログV2をAWS CDKで設定する前に、APIを用いた場合の標準ログV2の設定プロセスを確認します。

標準ログV2の詳細は以下AWS公式ドキュメントに記載されています。

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/standard-logging.html

CloudFrontディストリビューションと送信先のS3バケットが同一アカウントの場合、以下のような設定プロセスを踏みます。

  1. PutDeliverySourceでCloudFrontディストリビューションをログの送信元として定義する
  2. PutDeliveryDestinationでログの送信先を定義する
  3. 送信先のS3バケットのバケットポリシーにて、ログの送信元のARN(DeliverySource ARN != CloudFrontディストリビューションのARN)からのPutObjectを許可する
  4. 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] CloudFrontの標準ログV2をカスタムリソースとして設定してみた検証環境構成図.png

検証環境は全てAWS CDKでデプロイしました。使用したコードは以下GitHubリポジトリに保存しています。

https://github.com/non-97/cloudfront-s3-website/tree/v4.0.0

こちらのベースとなったコードの詳細な説明は以下記事をご覧ください。

https://dev.classmethod.jp/articles/aws-cdk-cloudfront-s3-website/

https://dev.classmethod.jp/articles/aws-cdk-cloudfront-s3-website-log-analytics/

https://dev.classmethod.jp/articles/cloudfront-s3-website-webp-image-delivery/

カスタムリソースの紹介

標準ログV2のカスタムリソース周りを紹介します。

今回はレガシー標準ログとV2を選択できるようにしています。

AWS CDKとしては以下のように定義をしています。

./lib/construct/contents-delivery-construct.ts
  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()は使用していません。

./lib/construct/contents-delivery-construct.ts
      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関数を定義しています。

./lib/construct/contents-delivery-construct.ts
      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でした。

https://github.com/aws/aws-sdk-js-v3/commit/107033b0e928fe5e2ab240afe174b0ee4614b046

そのため、対応としてbundleAwsSDK: trueとして、ローカルにインストールしたAWS SDKをバンドルするように定義しています。

また、ESMでバンドルする場合Dynamic require of "buffer" is not supportedと出力されます。こちらの対応として以下で紹介されているようにスクリプトにbanner挿入するようにしました。

https://github.com/aws/aws-cdk/issues/29310#issuecomment-2070347125

あとはこちらのLambda関数を用いてCustom Resource Provider Frameworkでカスタムリソースを設定しています。Custom Resource Provider Frameworkは以下記事が分かりやすいです。

https://dev.classmethod.jp/articles/cfn-custom-resource-via-cdk/

Lambda関数内では先述の1と2、4の処理を行っています。また、Update時はUpdateDeliveryConfigurationを、Delete時は作成した各種リソースを削除するように定義しています。

https://github.com/non-97/cloudfront-s3-website/blob/v4.0.0/lib/src/lambda/standard-logging-v2/index.ts

Athenaで使用するGlueテーブルの紹介

Athenaで使用するGlueテーブルもAWS CDKで定義しています。

今回は以下のようにParquetを使用するようにしました。

./lib/construct/log-analytics-construct.ts
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で設定されていることが分かります。

1.標準ログ.png

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のログを出力します。

3.1:28のアクセス一覧.png

問題なく出力されましたね。

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'

にて、キャッシュヒットしなかったリクエストのログを出力します。

2.キャッシュヒットしなかったリクエスト.png

こちらも意図したとおり出力されました。

カスタムリソースの削除

カスタムリソースが正常に削除できるかも確認しておきます。

> 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)でした!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.