AWS Config を AWS Organizations 配下に CloudFormation でデプロイ
概要
AWS Config は、AWS アカウントに作成したリソースの変更履歴を記録し、コンプライアンス要件などのルールに適合しているか継続的に監視するサービスです。Organizations 環境では、複数の AWS アカウントに対してまとめて適用したり、記録を集約することが多いと思いますが、様々なパターンについて CloudFormation で展開する方法を整理してみました。
複数のアカウントに一括適用するには CloudFormation StackSets を使用すると便利です。
参考) AWS CloudFormation StackSet を AWS Organizations 配下に AWS CLI でデプロイ
AWS Config に割り当てる権限は、IAM ロールを設定する代わりにプリセットされた Service-linked role を使用することもできます。その場合、保存先 S3 バケット、送信先 SNS トピックや EventBrigde のリソースポリシーにサービスプリンシパルからの書き込みを許可する設定をおこなう形になりますが、アクセス元を制限するにはアカウント ID をすべて列挙する必要があり Organization ID 指定でまとめて制限することができないようです。そのため、ここではそのパターンについては記述しません。
構成例
単一アカウント構成
リソースの変更履歴を保存する S3 バケット、通知する SNS トピック、および EventBridge を使用して条件に一致するイベント(コンプライアンス違反検知など)を通知する SNS トピックを同一アカウント内に作成します。
- ConfigBucket : リソースの変更履歴を保存する S3 バケット (必須)
- ConfigTopic : リソースの変更を通知する SNS トピック (OPTIONAL)
- ConfigAlertTopic : 特定のイベント(コンプライアンス違反検知など)を通知する SNS トピック (OPTIONAL)
AWS Chatbot から Subscribe すれば Slack に以下のような通知をおこなうことができます。
マルチアカウント構成 (別アカウントに保存・通知)
リソースの変更履歴を保存する S3 バケット、通知する SNS トピック、および EventBridge を使用して条件に一致するイベント(コンプライアンス違反検知など)を通知する SNS トピックは、それぞれ別のアカウントに作成することもできます。Organizations 内の複数のメンバーアカウントの情報を一元的に保存、通知したい場合に有効です。
デプロイ前に
先に管理コンソールから AWS Config を有効にしたことがある場合、記録を停止しても設定が残っていてデプロイに失敗してしまいます。AWS CLI で以下のコマンドを実行して削除しておきましょう。
aws configservice stop-configuration-recorder --configuration-recorder-name default
aws configservice delete-delivery-channel --delivery-channel-name default
aws configservice delete-configuration-recorder --configuration-recorder-name default
テンプレートパターン
基本
単一アカウントによる AWS Config の最小設定です。リソースの変更履歴を保存する S3 バケットを設定します。
Configuration Recorder (ConfigRecorder
) がアカウント内のリソース情報を取得します。全てのリソースを読み取るための権限 AWS_ConfigRole
ポリシーをアタッチしたロール (ConfigRecorderRole
) を作成し、付与します。管理コンソールから有効化する場合はサービス用にプリセットされた Service-linked role を使用することもできますが、権限としてはこれと同等のものです。S3 バケットへの書き込み権限もこのロールに追加します。
# リソースの変更履歴を保存する S3 バケット
ConfigBucket:
DeletionPolicy: Retain
Type: AWS::S3::Bucket
# Configuration Recorder
ConfigRecorderRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- config.amazonaws.com
Action:
- sts:AssumeRole
Path: /
ManagedPolicyArns:
# Configuration Recorder 用の管理ポリシーをアタッチ
- !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AWS_ConfigRole"
Policies:
# S3 バケットへの書き込み権限
- PolicyName: RecorderPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:PutObject
Resource:
- !Sub "${ConfigBucket.Arn}/*"
ConfigRecorder:
Type: AWS::Config::ConfigurationRecorder
Properties:
RoleARN: !GetAtt ConfigRecorderRole.Arn
RecordingGroup:
AllSupported: True
IncludeGlobalResourceTypes: False
SNS トピックへの通知
SNS トピックにもリソースの変更を通知します。
SNS トピック (ConfigTopic
) を追加して Delivery Channel (ConfigDeliveryChannel
) に SnsTopicARN
プロパティを追記します。IAM ロール (ConfigRecorderRole
) に SNS トピックへ通知する権限も追加します。
# 通知先 SNS トピック
ConfigTopic:
Type: AWS::SNS::Topic
Properties:
DisplayName: AWS Config Topic
# Configuration Recorder
ConfigRecorderRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- config.amazonaws.com
Action:
- sts:AssumeRole
Path: /
ManagedPolicyArns:
- !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AWS_ConfigRole"
Policies:
- PolicyName: RecorderPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:PutObject
Resource:
- !Sub "${ConfigBucket.Arn}/*"
# SNS トピックへの通知権限を追加
- Effect: Allow
Action:
- sns:Publish
Resource:
- !Ref ConfigTopic
# Delivery Channel
ConfigDeliveryChannel:
Type: AWS::Config::DeliveryChannel
Properties:
ConfigSnapshotDeliveryProperties:
DeliveryFrequency: TwentyFour_Hours
S3BucketName: !Ref ConfigBucket
SnsTopicARN: !Ref ConfigTopic # 通知先 SNS トピックを追加
ルールを設定
Config Rule を追加して、リソースの変更を監視します。
以下は s3-bucket-public-write-prohibited マネージドルールの場合の例です。ルールによって設定は異なりますので、それぞれ確認してください。
参考) AWS Config マネージドルールのリスト
CheckS3BucketPublicWriteProhibited:
Type: AWS::Config::ConfigRule
Properties:
MaximumExecutionFrequency: TwentyFour_Hours
Scope:
ComplianceResourceTypes:
- AWS::S3::Bucket
Source:
Owner: AWS
SourceIdentifier: S3_BUCKET_PUBLIC_WRITE_PROHIBITED
イベントを SNS トピックへ通知
Config Rule により検出された非準拠イベントを通知するには、Event Bridge を使用します。
通知先の SNS トピック (ConfigAlertTopic
) を作成し、Amazon EventBridge ルール (NonCompliantEventsRule
) に通知条件を設定します。SNS トピックのアクセスポリシー (ConfigAlertTopicPolicy
) には EventBridge からの通知を許可します。
# Config Rule による非準拠イベントを通知する EventBridge Rule
NonCompliantEventsRule:
Type: AWS::Events::Rule
Properties:
# 通知するイベントを指定
EventPattern:
source:
- aws.config
detail-type:
- Config Rules Compliance Change
detail:
messageType:
- ComplianceChangeNotification
newEvaluationResult:
complianceType:
- NON_COMPLIANT
State: ENABLED
Targets:
- Id: ConfigAlertTopic
Arn: !Ref ConfigAlertTopic # 通知先 SNS トピック
# イベントを通知する SNS トピック
ConfigAlertTopic:
Type: AWS::SNS::Topic
Properties:
DisplayName: AWS Config Alert Topic
ConfigAlertTopicPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
Topics:
- !Ref ConfigAlertTopic
PolicyDocument:
Statement:
- Action:
- sns:Publish
Effect: Allow
Resource: !Ref ConfigAlertTopic
Principal:
Service:
- events.amazonaws.com # Amazon EventBridge からの通知を許可
別アカウントの S3 バケットに記録
リソースの変更履歴を、別の AWS アカウントの S3 バケットに保存します。
送信先のアカウントに S3 バケット (ConfigBucket
) を作成します。バケットポリシー (ConfigBucketPolicy
) に送信元の Organization ID を指定して許可します。
参考) Amazon S3 バケットへのアクセス許可を AWS Config に与える
ConfigBucket:
DeletionPolicy: Retain
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "config-bucket-${AWS::AccountId}"
ConfigBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: (バケット名)
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: AWSConfigBucketPermissionsCheck
Effect: Allow
Action: s3:GetBucketAcl
Resource:
- !Sub "arn:${AWS::Partition}:s3:::${ConfigBucket}"
Principal:
AWS: "*"
Condition:
StringEquals:
aws:PrincipalOrgID: (Organization ID)
- Sid: AWSConfigBucketExistenceCheck
Effect: Allow
Action: s3:ListBucket
Resource:
- !Sub "arn:${AWS::Partition}:s3:::${ConfigBucket}"
Principal:
AWS: "*"
Condition:
StringEquals:
aws:PrincipalOrgID: (Organization ID)
- Sid: AWSConfigBucketDelivery
Effect: Allow
Action: s3:PutObject
Resource:
- !Sub "arn:${AWS::Partition}:s3:::${ConfigBucket}/*"
Principal:
AWS: "*"
Condition:
StringEquals:
s3:x-amz-acl: bucket-owner-full-control
aws:PrincipalOrgID: (Organization ID)
アカウント ID を指定して制限する場合は Principal
で指定します。
Principal:
AWS:
- (アカウント ID)
- (アカウント ID)
送信元アカウントから、保存先としてこの S3 バケット名を指定します。
# Configuration Recorder
ConfigRecorderRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- config.amazonaws.com
Action:
- sts:AssumeRole
Path: /
Policies:
# 別アカウントの S3 バケットへの書き込みを許可
- PolicyName: RecorderPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:PutObject
Resource:
- !Sub "arn:${AWS::Partition}:s3:::(バケット名)/*"
ManagedPolicyArns:
- !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AWS_ConfigRole"
# Delivery Channel
ConfigDeliveryChannel:
Type: AWS::Config::DeliveryChannel
Properties:
ConfigSnapshotDeliveryProperties:
DeliveryFrequency: TwentyFour_Hours
# 保存先に別アカウントの S3 バケットを指定
S3BucketName: (バケット名)
別アカウントの SNS トピックへ通知
変更を別の AWS アカウントの SNS トピックに通知します。SNS トピックは送信元と同じリージョンに作成する必要があります。
送信先のアカウントに SNS トピック (ConfigTopic
) を作成します。アクセスポリシー (ConfigTopicPolicy
) に送信元の Organization ID を指定して許可します。
参考) Amazon SNS トピックへのアクセス許可
ConfigTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: (トピック名)
DisplayName: AWS Config Topic
ConfigTopicPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
Topics:
- !Ref ConfigTopic
PolicyDocument:
Statement:
- Sid: AWSConfigSNSPolicy
Action:
- sns:Publish
Effect: Allow
Resource:
- !Ref ConfigTopic
Principal:
AWS: "*"
Condition:
StringEquals:
aws:PrincipalOrgID: (Organization ID)
アカウント ID を指定して制限する場合は Principal
で指定します。
Principal:
AWS:
- (アカウント ID)
- (アカウント ID)
送信元アカウントから、通知先としてこの SNS トピックの ARN を指定します。
# Configuration Recorder
ConfigRecorderRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- config.amazonaws.com
Action:
- sts:AssumeRole
Path: /
Policies:
- PolicyName: RecorderPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:PutObject
Resource:
- !Sub "arn:${AWS::Partition}:s3:::(バケット名)/*"
# 別アカウントの SNS トピックへの通知を許可
- Effect: Allow
Action:
- sns:Publish
Resource:
- !Sub "arn:${AWS::Partition}:sns:${AWS::Region}:(送信先アカウント ID):(SNS トピック名)"
ManagedPolicyArns:
- !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AWS_ConfigRole"
# Delivery Channel
ConfigDeliveryChannel:
Type: AWS::Config::DeliveryChannel
Properties:
ConfigSnapshotDeliveryProperties:
DeliveryFrequency: TwentyFour_Hours
S3BucketName: (バケット名)
# 通知先に別アカウントの SNS トピックを指定
SnsTopicARN: !Sub "arn:${AWS::Partition}:sns:${AWS::Region}:(送信先アカウント ID):(SNS トピック名)"
イベントを別アカウントの SNS トピックへ通知
Config Rule により検出された非準拠イベントを、別の AWS アカウントの SNS トピックに通知します。Event Bridge から直接送信することはできないため、EventBus を中継します。EventBus は送信元とリージョンが異なっていても問題ありません。Event Rule は送信元、送信先アカウントの両方に定義します。この例では同じ条件を指定しています。
送信先のアカウントに EventBus (ConfigEventBus
) を作成します。EventBus のリソースポリシー (ConfigEventBusPolicy
) に送信元の Organization ID を指定して許可します。
ConfigEventBus:
Type: AWS::Events::EventBus
Properties:
Name: (イベントバス名)
ConfigEventBusPolicy:
Type: AWS::Events::EventBusPolicy
Properties:
EventBusName: !GetAtt ConfigEventBus.Name
Statement:
Sid: ConfigEventBusPolicy
Action:
- events:PutEvents
Effect: Allow
Resource: !GetAtt ConfigEventBus.Arn
Principal:
AWS: "*"
Condition:
StringEquals:
aws:PrincipalOrgID: !Ref OrganizationId
StatementId: ConfigEventBusPolicy
ConfigAlertTopic:
Type: AWS::SNS::Topic
Properties:
DisplayName: AWS Config Alert Topic
ConfigAlertTopicPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
Topics:
- !Ref ConfigAlertTopic
PolicyDocument:
Statement:
- Action:
- sns:Publish
Effect: Allow
Resource: !Ref ConfigAlertTopic
Principal:
Service:
- events.amazonaws.com
NonCompliantEventsRule:
Type: AWS::Events::Rule
Properties:
EventBusName: !GetAtt ConfigEventBus.Name
EventPattern:
source:
- aws.config
detail-type:
- Config Rules Compliance Change
detail:
messageType:
- ComplianceChangeNotification
newEvaluationResult:
complianceType:
- NON_COMPLIANT
State: ENABLED
Targets:
- Id: NonCompliantNotification
Arn: !Ref ConfigAlertTopic
送信元アカウントから、通知先としてこの EventBus を指定します。
NonCompliantEventsRuleRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- events.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: PutEventsPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: PutEvents
Action:
- events:PutEvents
Effect: Allow
Resource:
# 別アカウントの EventBus への送信を許可
- !Sub "arn:${AWS::Partition}:events:(送信先リージョン):(送信先アカウント ID):event-bus/(イベントバス名)"
Path: /
NonCompliantEventsRule:
Type: AWS::Events::Rule
Properties:
EventPattern:
source:
- aws.config
detail-type:
- Config Rules Compliance Change
detail:
messageType:
- ComplianceChangeNotification
newEvaluationResult:
complianceType:
- NON_COMPLIANT
State: ENABLED
Targets:
# イベントを EventBus へ送信する
- Id: ConfigAlertTopic
Arn: !Sub "arn:${AWS::Partition}:events:(送信先リージョン):(送信先アカウント ID):event-bus/(イベントバス名)"
RoleArn: !GetAtt NonCompliantEventsRuleRole.Arn
Discussion