1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS CDKでAWS Configを有効化する

Last updated at Posted at 2025-03-13

はじめに

最近AWS ConfigをCDKで有効化したのですが、少しハマったのでコードと共に記録を残しておきます

ハマったところ

ハマったのはAWS Configの仕様です。

具体的にはConfigを有効化する際にAWS::Config::ConfigurationRecorderAWS::Config::ConfigDeliveryChannelを作成する必要があるのですが、これらは同時に有効化する必要があるようです。DependsOnなどでどちらかを優先すると一向に作成が終わりませんでした。

公式にはRecorderを先に作るべしという記述を見つけてDependsOnしていたので、少し気づくのに時間がかかりました。

image.png

なぜ同時に有効化する必要があるのか。APIリファレンスを見たところ、Configuration Recorderの有効化にあたって2つのAPIを実行する必要があるとわかりました。一つ目はPutConfigurationRecorder、二つ目はStartConfigurationRecorderです。なお1つ目のAPIはDeliveryChannel作成の前、二つ目は作成の後に叩く必要があります。

CDK/CloudFormation経由でConfiguration Recorderを有効化するとPutConfigurationRecorderとStartConfigurationRecorderのタイミングを制御できないので、DependsOnをどちらかにつけるとエラーになってしまうようです。

コード

というわけでCDK(Stack部分)のコードを置いておきます

import * as cdk from "aws-cdk-lib";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as iam from "aws-cdk-lib/aws-iam";
import * as config from "aws-cdk-lib/aws-config";
import { Construct } from "constructs";

export class ConfigStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);


    const configBucket = new cdk.aws_s3.Bucket(this, "configBucket", {
      blockPublicAccess: cdk.aws_s3.BlockPublicAccess.BLOCK_ALL,
      encryption: cdk.aws_s3.BucketEncryption.S3_MANAGED,
      enforceSSL: true,
      versioned: false,
      removalPolicy: cdk.RemovalPolicy.DESTROY,
      autoDeleteObjects: true,
    });

    // Add bucket policy
    const bucketPolicy = new iam.PolicyStatement({
      sid: "AWSConfigBucketPermissionsCheck",
      effect: iam.Effect.ALLOW,
      principals: [new iam.ServicePrincipal("config.amazonaws.com")],
      actions: ["s3:GetBucketAcl"],
      resources: [configBucket.bucketArn],
      conditions: {
        StringEquals: {
          "AWS:SourceAccount": this.account, // Using the account ID of the stack
        },
      },
    });

    const listBucketPolicy = new iam.PolicyStatement({
      sid: "AWSConfigBucketExistenceCheck",
      effect: iam.Effect.ALLOW,
      principals: [new iam.ServicePrincipal("config.amazonaws.com")],
      actions: ["s3:ListBucket"],
      resources: [configBucket.bucketArn],
      conditions: {
        StringEquals: {
          "AWS:SourceAccount": this.account,
        },
      },
    });

    const putObjectPolicy = new iam.PolicyStatement({
      sid: "AWSConfigBucketDelivery",
      effect: iam.Effect.ALLOW,
      principals: [new iam.ServicePrincipal("config.amazonaws.com")],
      actions: ["s3:PutObject"],
      resources: [`${configBucket.bucketArn}/AWSLogs/${this.account}/Config/*`],
      conditions: {
        StringEquals: {
          "s3:x-amz-acl": "bucket-owner-full-control",
          "AWS:SourceAccount": this.account,
        },
      },
    });

    // Add the policy statements to the bucket
    configBucket.addToResourcePolicy(bucketPolicy);
    configBucket.addToResourcePolicy(listBucketPolicy);
    configBucket.addToResourcePolicy(putObjectPolicy);

    const configRole = new iam.Role(this, "ConfigRole", {
      assumedBy: new iam.ServicePrincipal("config.amazonaws.com"),
      managedPolicies: [
        iam.ManagedPolicy.fromAwsManagedPolicyName(
          "service-role/AWS_ConfigRole"
        ),
      ],
    });

    const configRecorder = new config.CfnConfigurationRecorder(
      this,
      "ConfigRecorder",
      {
        name: "CloudFrontVpcOriginConfigRecorder",
        roleArn: configRole.roleArn,
        recordingGroup: {
          allSupported: true,
          includeGlobalResourceTypes: true,
        },
      }
    );

    const configDeliveryChannel = new config.CfnDeliveryChannel(
      this,
      "ConfigDeliveryChannel",
      {
        name: "CloudFrontVpcOriginConfigDeliveryChannel",
        s3BucketName: configBucket.bucketName, // S3バケット名を指定
        configSnapshotDeliveryProperties: {
          deliveryFrequency: "TwentyFour_Hours",
        },
      }
    );
    configDeliveryChannel.node.addDependency(configBucket);
    configDeliveryChannel.node.addDependency(configRole);
    configRecorder.node.addDependency(configRole);
    configRecorder.node.addDependency(configBucket);
  }
}

おわりに

本記事が誰かのお役に立てば幸いです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?