AWS ConfigをCloudFormationで有効化する際のハマりポイント2選
AWS ConfigをCloudFormationで構築する際に躓いたポイントをまとめます。
同じエラーで困っている方の参考になれば幸いです。
環境
- AWS CloudFormation
- AWS Config(初回有効化)
ハマりポイント① サービスリンクロールが自動作成されない
発生したエラー
Resource handler returned message: "Service role name AWSServiceRoleForConfig
has been taken in this account, please try a different suffix."
または、ConfigurationRecorderが30分以上 CREATE_IN_PROGRESS のまま止まる。
原因
AWS ConfigはIAMサービスリンクロール(AWSServiceRoleForConfig)を使用しますが、
AWSのサービスを初めて使うアカウントではこのロールが存在しない場合があります。
存在しない状態でConfigurationRecorderを作成しようとすると処理が止まります。
解決策
CloudFormationテンプレートに AWS::IAM::ServiceLinkedRole を追加してロールを明示的に作成します。
ConfigServiceLinkedRole:
Type: AWS::IAM::ServiceLinkedRole
Properties:
AWSServiceName: config.amazonaws.com
Description: "Service-linked role for AWS Config"
注意点
一度スタックが作成に成功すると AWSServiceRoleForConfig がアカウントに残ります。
その状態で再度スタックを作成しようとすると「すでに存在する」エラーが発生します。
対処法: 2回目以降のスタック作成時は AWS::IAM::ServiceLinkedRole のリソース定義をテンプレートから削除してください。
ハマりポイント② ConfigurationRecorder と DeliveryChannel の循環依存
発生したエラー(パターンA)
DeliveryChannel → ConfigurationRecorder の順で作成しようとした場合:
Configuration recorder is not available to put delivery channel.
(NoAvailableConfigurationRecorderException)
発生したエラー(パターンB)
ConfigurationRecorder → DeliveryChannel の順で作成しようとした場合:
Delivery channel is not available to start configuration recorder.
(NoAvailableDeliveryChannelException)
原因
AWS::Config::ConfigurationRecorder と AWS::Config::DeliveryChannel は
お互いに循環依存の関係にあります。
AWSのドキュメントには「ConfigurationRecorderを先に作成せよ」と記載がありますが、
実際には DependsOn で順番を制御するとどちらの順番でもエラーになります。
解決策
ConfigurationRecorder と DeliveryChannel はお互いに DependsOn してはいけません。
両リソースともS3バケットポリシーにのみ依存させ、CloudFormationに並列で作成させます。
# ✅ 正しい依存関係
ConfigurationRecorder:
Type: AWS::Config::ConfigurationRecorder
DependsOn:
- ConfigBucketPolicy # S3のみに依存
Properties:
...
DeliveryChannel:
Type: AWS::Config::DeliveryChannel
DependsOn:
- ConfigBucketPolicy # S3のみに依存(ConfigurationRecorderへの依存はNG)
Properties:
...
# ❌ NG例その1:DeliveryChannel が ConfigurationRecorder に依存
DeliveryChannel:
DependsOn:
- ConfigurationRecorder # → NoAvailableConfigurationRecorderException
# ❌ NG例その2:ConfigurationRecorder が DeliveryChannel に依存
ConfigurationRecorder:
DependsOn:
- DeliveryChannel # → NoAvailableDeliveryChannelException
最終的に動作したテンプレート全文
※SecurityHubCSPM検証用です。
AWSTemplateFormatVersion: "2010-09-09"
Description: >
AWS Config baseline. Creates DeliveryChannel/Recorder,
uses existing AWSServiceRoleForConfig (does NOT create ServiceLinkedRole).
Parameters:
ConfigBucketName:
Type: String
Description: "Globally unique S3 bucket name for AWS Config delivery (3-63 chars, lowercase letters, numbers, hyphens, dots)."
MinLength: 3
MaxLength: 63
AllowedPattern: "^[a-z0-9][a-z0-9.-]*[a-z0-9]$"
ConstraintDescription: "3〜63文字。小文字英数字・ハイフン・ドットのみ使用可。先頭・末尾は英数字。"
ConfigBucketPrefix:
Type: String
Default: aws-config
Description: "Prefix for AWS Config objects in the bucket. Do NOT include leading/trailing '/'."
AllowedPattern: "^[A-Za-z0-9][A-Za-z0-9._-]*$"
ConstraintDescription: "Use only letters/numbers/._- and do not start with '/'. Do not include '/'."
Resources:
ConfigBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref ConfigBucketName
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
VersioningConfiguration:
Status: Enabled
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
ConfigBucketPolicy:
Type: AWS::S3::BucketPolicy
DependsOn: ConfigBucket
Properties:
Bucket: !Ref ConfigBucket
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: AWSConfigBucketPermissionsCheck
Effect: Allow
Principal:
Service: config.amazonaws.com
Action: s3:GetBucketAcl
Resource: !GetAtt ConfigBucket.Arn
- Sid: AWSConfigBucketDelivery
Effect: Allow
Principal:
Service: config.amazonaws.com
Action: s3:PutObject
Resource: !Sub "${ConfigBucket.Arn}/${ConfigBucketPrefix}/AWSLogs/${AWS::AccountId}/Config/*"
Condition:
StringEquals:
s3:x-amz-acl: bucket-owner-full-control
# ConfigurationRecorder と DeliveryChannel は循環依存のため
# お互いに DependsOn してはいけない。両方ともS3にのみ依存させる。
ConfigurationRecorder:
Type: AWS::Config::ConfigurationRecorder
DependsOn:
- ConfigBucketPolicy
Properties:
Name: default
RoleARN: !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig
RecordingGroup:
AllSupported: false
IncludeGlobalResourceTypes: false
ResourceTypes:
- AWS::CloudFront::Distribution
- AWS::ElasticLoadBalancingV2::LoadBalancer
- AWS::ElasticLoadBalancingV2::Listener
- AWS::ElasticLoadBalancingV2::TargetGroup
- AWS::EC2::Instance
- AWS::EC2::SecurityGroup
- AWS::EC2::NetworkInterface
- AWS::EC2::VPC
- AWS::EC2::Subnet
- AWS::EC2::RouteTable
- AWS::EC2::NetworkAcl
- AWS::EC2::InternetGateway
- AWS::EC2::NatGateway
- AWS::EC2::EIP
- AWS::EC2::Volume
- AWS::EC2::FlowLog
- AWS::S3::Bucket
- AWS::RDS::DBInstance
- AWS::RDS::DBSubnetGroup
DeliveryChannel:
Type: AWS::Config::DeliveryChannel
DependsOn:
- ConfigBucketPolicy
Properties:
Name: default
S3BucketName: !Ref ConfigBucket
S3KeyPrefix: !Ref ConfigBucketPrefix
Outputs:
ConfigBucketOut:
Value: !Ref ConfigBucket
DeliveryChannelOut:
Value: default
RecorderOut:
Value: default
RoleArnUsed:
Value: !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig
まとめ
| ハマりポイント | 原因 | 解決策 |
|---|---|---|
| ConfigurationRecorderが止まる | AWSServiceRoleForConfigが存在しない |
AWS::IAM::ServiceLinkedRole をテンプレートに追加 |
| どちらの順番でもエラーになる | ConfigurationRecorderとDeliveryChannelの循環依存 | お互いに DependsOn せず、両方をS3にのみ依存させる |
CloudFormationに慣れていると DependsOn で順番制御しようとしてしまいがちですが、
AWS Config特有の仕様として覚えておくと良さそうです。