Skip to main content

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 に以下のような通知をおこなうことができます。 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 バケットを設定します。

単一アカウント構成 - 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

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:
DependsOn: ConfigRecorder
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 を使用します。

単一アカウント構成 - Alert

通知先の 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

送信先のアカウントに 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

送信先のアカウントに 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 は送信元、送信先アカウントの両方に定義します。この例では同じ条件を指定しています。

マルチアカウント構成 - Alert

送信先のアカウントに 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