はじめに
1リージョンのみのConfig
の有効化は簡単・迅速に行えますが、マルチアカウント・マルチリージョンに対して有効化する場合、とても面倒な作業になります。
そこで、CloudFormation
によりConfig
を有効化することで、簡単にマルチアカウント環境にConfig
を有効化できるようにします。
ただ、この記事ではスタックセットは作成しません。
小さく始めたいので、まずはスタックから作成します。スタックセットは今後の記事で作成しようと思います。
この記事で行うことは
Aアカウントの一つのリージョンで
Config
を有効化するBアカウントの一つのリージョンで
Config
を有効化し、配信先S3
をAアカウントのS3
にする
ことであり、上記作業を通して
Config
の仕組み・挙動Config
の配信でSNS
を設定した場合の通知量Config
配信を受信したS3
の階層構造PutObject
の無料利用枠が他と比べて簡単に超える理由(超えない方もいると思いますが……)既存リソースからスタックを作成する方法・注意点
CloudFomation
のクロススタック参照
などのことを学べました。
では、早速はじめていきます。
Aアカウントの一つのリージョンでConfig
を有効化する
Config
を有効化するテンプレートは公式が掲載しているものを流用します。
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-sampletemplates.html
リソース部分だけピックアップします。
Resources:
ConfigBucket:
DeletionPolicy: Retain
Type: AWS::S3::Bucket
ConfigBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref ConfigBucket
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: AWSConfigBucketPermissionsCheck
Effect: Allow
Principal:
Service:
- config.amazonaws.com
Action: s3:GetBucketAcl
Resource:
- !Sub "arn:${AWS::Partition}:s3:::${ConfigBucket}"
- Sid: AWSConfigBucketDelivery
Effect: Allow
Principal:
Service:
- config.amazonaws.com
Action: s3:PutObject
Resource:
- !Sub "arn:${AWS::Partition}:s3:::${ConfigBucket}/AWSLogs/${AWS::AccountId}/*"
ConfigTopic:
Condition: CreateTopic
Type: AWS::SNS::Topic
Properties:
TopicName: !Sub "config-topic-${AWS::AccountId}"
DisplayName: AWS Config Notification Topic
ConfigTopicPolicy:
Condition: CreateTopic
Type: AWS::SNS::TopicPolicy
Properties:
Topics:
- !Ref ConfigTopic
PolicyDocument:
Statement:
- Sid: AWSConfigSNSPolicy
Action:
- sns:Publish
Effect: Allow
Resource: !Ref ConfigTopic
Principal:
Service:
- config.amazonaws.com
EmailNotification:
Condition: CreateSubscription
Type: AWS::SNS::Subscription
Properties:
Endpoint: !Ref NotificationEmail
Protocol: email
TopicArn: !Ref ConfigTopic
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"
ConfigRecorder:
Type: AWS::Config::ConfigurationRecorder
DependsOn:
- ConfigBucketPolicy
Properties:
RoleARN: !GetAtt ConfigRecorderRole.Arn
RecordingGroup:
AllSupported: !Ref AllSupported
IncludeGlobalResourceTypes: !Ref IncludeGlobalResourceTypes
ResourceTypes: !If
- IsAllSupported
- !Ref AWS::NoValue
- !Ref ResourceTypes
ConfigDeliveryChannel:
Type: AWS::Config::DeliveryChannel
DependsOn:
- ConfigBucketPolicy
Properties:
Name: !If
- IsGeneratedDeliveryChannelName
- !Ref AWS::NoValue
- !Ref DeliveryChannelName
ConfigSnapshotDeliveryProperties:
DeliveryFrequency: !FindInMap
- Settings
- FrequencyMap
- !Ref Frequency
S3BucketName: !Ref ConfigBucket
SnsTopicARN: !If
- CreateTopic
- !Ref ConfigTopic
- !Ref TopicArn
テンプレートを見ると、意外と多くのリソースが作成されていることがわかります。
一見して分かりにくいので、図にしてみます。
SNSトピック
を設定すると大量に通知が来てしまいそうですが、今回は配信先にSNS
も設定することにします。
スタックの作成は、権限に問題がなければエラーは起きないはずです。
私の場合はControl Tower
で作成された子アカウントで行ったため、権限エラーが発生しました(ガードレールによりConfig
設定が拒否されているため。)。
気を取り直して、Control Tower
管理外のアカウントでスタックを作成します。
無事にConfig
有効化の確認ができました。
それでは、各リソースが正常に作成されているか確認します。
S3の階層状況は以下のようになっていました。
バケット
└── AWSLogs
└──アカウントID
└──Config
├──ConfigWritabilityCheckFile
└──リージョン名
└──配信年
└──配信月
└──配信日
├──ConfigHistory
| ├──アカウントID_Config_リージョン名_ConfigHistory_AWS::Config::ResourceCompliance_20210111T131148Z_20210111T131148Z_1.json.gz
| ├──(変更したリソースの設定履歴ファイルが、変更したリソースの数だけ続く(6h間隔))
└──ConfigSnapshot
└──アカウントID_Config_リージョン名_ConfigSnapshot_20210111T134218Z_3478f352-ce65-47a2-8d32-b4fe3f0827a9.json.gz
ConfigWritabilityCheckFile
は、Config
がS3バケット
に正常に書き込めることを確認するためのテストファイルです。
アカウント名が最初から入っているのは、別アカウントから集約する際に区別できるようにするためでしょうか。
Config
有効化直後の時点では何も配信されていませんでしたが、1時間経たないうちに設定履歴ファイルとスナップショットが配信されていました。
おそらくその配信時刻を基準として、定められた配信間隔(※)により設定履歴ファイルとスナップショットが配信されると思われます。
なお、Config
有効化後に変更していないリソースの設定履歴ファイルもありましたので、リソースを新規作成後に変更していなくても、そのリソースの設定履歴ファイルが配信されていなければ、設定履歴ファイルを配信するようです。
※設定履歴ファイル:6時間、設定スナップショット:1,3,6,12,24時間のうちユーザーが指定
実際にS3の配信状況を確認すると、多くのリソースを作成・変更するほどPutObject
の使用が多くなることが分かりました。
私は、よくPutObject
の無料枠が切れるよというメールを受信していたのですが、Configの配信も原因の一部であることがわかりました(おそらく原因の大部分はCloudTrail
を全リージョン有効化してS3
にもログを配信していたことです。)。
次はSNS
を確認します。
正常に確認できていますが、気になるのがメールの通知量です。
設定履歴ファイルとスナップショットの配信が終わった後にメールを確認すると、デフォルトVPCくらいしかリソースがないリージョンなのに、合計16件も受信していました。
予想通り大量の通知がきそうなので、配信先でSNS
を設定することはやめておきます(設定する場合、SNS
側でフィルタする処置が必須ですね。)。
今度は、このスタックを削除したらどうなるか確認します(S3
だけDeletionPolicy
設定によりリソース自体は残ります)。
気になっているのは、Config
無効化→リソース変更→Config
有効化した場合、設定履歴ファイルの配信やS3バケット
がどのような状態になるかです。
スタックを削除してS3
だけが残った状態を確認します。
適当にリソースを作成したいので、空のSNSトピック
を二つ作成しました。
それでは、再度スタックを作成しますが、Config
の配信先は残しているS3バケット
にしたいです。
本来なら、スタック管理外のリソースをスタックにインポートする場合、テンプレートにDeletionPolicy
を追加する必要があります。
しかし、今回は元々記載していたのでテンプレートを変更する必要はなく、最初のスタック作成と同じテンプレートを使用します。
最初と異なるのは、既存のリソースを使用する方法でスタックを作成するだけです。
リソースをインポートから作成します。
なんとエラーが起きました。
どうやらリソースのインポートで作成する際は、テンプレートのリソースは全て、実際にインポートしないリソースでも、リソースのインポートでサポートされている必要があるようです。
そのため、スタックを分割して対処します。
今回はConfig
の検証なので無理にスタックの管理下におく必要はないのですが、クロススタック参照の学習を兼ねてやってみます。
まず、既存のS3リソースだけをインポートするスタックを作成します。
テンプレートは以下の通りです。
AWSTemplateFormatVersion: 2010-09-09
Description: S3 Config
Resources:
ConfigBucket:
DeletionPolicy: Retain
Type: AWS::S3::Bucket
Outputs:
ConfigBucketOutput:
Description: S3
Value: !Ref ConfigBucket
Export:
Name: !Sub ${AWS::StackName}-S3BucketName
先ほどと異なり、エラーが発生せずにテンプレートを指定できました。
しかし、次の画面でインポート操作では出力を追加することができないとのこと。
仕方がないので、出力はインポート操作後に行います。
出力のセクションを削除したら成功しました。
今度はStackを更新し、出力を追加します。
成功です。
今度は、S3
のスタックで出力した情報を、Config
有効化用のスタックにインポートできれば、再度Config
有効化の設定が完了します。
テンプレートは、リソースセクションからS3バケット
を削除し、S3バケット
を参照していた箇所をインポート形式に変更します。
以下のようにインポート形式に変更しています。
Resources:
ConfigBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Fn::ImportValue: !Sub ${S3StackName}-S3BucketName
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: AWSConfigBucketPermissionsCheck
Effect: Allow
Principal:
Service:
- config.amazonaws.com
Action: s3:GetBucketAcl
Resource:
- !Join
- ""
- - !Sub "arn:${AWS::Partition}:s3:::"
- Fn::ImportValue: !Sub ${S3StackName}-S3BucketName
- Sid: AWSConfigBucketDelivery
Effect: Allow
Principal:
Service:
- config.amazonaws.com
Action: s3:PutObject
Resource:
- !Join
- ""
- - !Sub "arn:${AWS::Partition}:s3:::"
- Fn::ImportValue: !Sub ${S3StackName}-S3BucketName
- !Sub "/AWSLogs/${AWS::AccountId}/*"
スタックの作成は成功しました。
ただ、現在のStackではS3バケット
とバケットポリシーが異なるスタックに存在しているため、不自然です。
そのため、S3バケット
とバケットポリシーを一緒のスタックにするため、S3バケット
のスタックの管理下に置こうとしましたが、これは失敗しました。
少し前でもエラーになっていましたが、バケットポリシーはリソースのインポートではサポートされていないからです。
スタックで既存リソースのインポートを使用する際は、サポートされているかが重要であることがわかりました。
諦めて、次の作業に進みます。
Config
の有効化を確認できました。
S3
を覗いてみると、ConfigWritabilityCheckFile
が更新されていたので、過去にConfig
配信先にしたことがあるS3
であっても、配信確認のテストは行うようです。
スナップショットは1時間弱でS3
に配信されていましたが、設定履歴ファイルは4,5時間後に配信されていました。
Config
無効化後に作成したSNSトピック
はスナップショットの中に入っていました。
設定履歴ファイルは、Config
無効化後、SNSトピック
など変更したリソースの分だけ配信されました。
最初に有効化した時に配信されたデフォルトVPCなどのリソースは配信されませんでした。
ということは、Config
は無効化すると設定情報が全てリセットされるわけではなく、あくまでも記録を止める仕組みのようです。
有効化になって記録が再開されると、無効化前の状態と比較して変更されているリソースの設定履歴ファイルが配信されます。
S3
の保存場所は、有効化前後で変更はありませんでした。
無効化→有効化で日にちが空いていれば、その分だけ設定履歴ファイルとスナップショットが存在しない状態になるか、それとも変更した日にちに合わせたフォルダ(正確にはフォルダではありませんが)に配信されるかのどちらかだと思いますが、検証していないのでわかりません。
個人的な予想だと後者だと思います。
これで一つのリージョンでConfig
を有効化する作業が終わりました。
次は、別のアカウントで有効化したConfig
の配信先を今回作成したS3
に設定してみます。
Bアカウントの一つのリージョンでConfig
を有効化し、配信先S3
をAアカウントのS3
にする
最初のConfig
有効化と異なる点は、配信先が異なるアカウントである点です。
なので、配信先のAアカウントのS3バケット
で、異なるアカウントからのアクションを受け入れる設定を行います。
Config
のロールはアカウントでアクションを制限していないので、権限は変更する必要はありません。
では、BアカウントでConfig
を有効化し、配信先のS3
に前回作成したAアカウントのS3
を指定する作業を行います。
まず、AアカウントのS3
のバケットポリシーを編集します。
編集後はこちら。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AWSConfigBucketPermissionsCheck",
"Effect": "Allow",
"Principal": {
"Service": "config.amazonaws.com"
},
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::enableconfig-configbucket-qnpsr1uetx0v"
},
{
"Sid": "AWSConfigBucketExistenceCheck",
"Effect": "Allow",
"Principal": {
"Service": "config.amazonaws.com"
},
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::enableconfig-configbucket-qnpsr1uetx0v"
},
{
"Sid": "AWSConfigBucketDelivery",
"Effect": "Allow",
"Principal": {
"Service": "config.amazonaws.com"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::enableconfig-configbucket-qnpsr1uetx0v/AWSLogs/アカウントID/*"
},
{
"Sid": "AWSConfigBucketDeliveryCrossAccount",
"Effect": "Allow",
"Principal": {
"Service": "config.amazonaws.com"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::enableconfig-configbucket-qnpsr1uetx0v/AWSLogs/別アカウントID/Config/*",
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "bucket-owner-full-control"
}
}
}
]
}
このバケットポリシーによりConfig
配信を受け入れる準備ができたので、BアカウントでConfig
を有効化し、S3
配信先をAアカウントのS3
に指定します。
今回はコンソールで有効化します。
Config
の有効化が無事完了したので、AアカウントのS3
を確認します。
新たにBアカウントのフォルダが作成されていました。
バケット
└── AWSLogs
├──AアカウントID
| └──Config
| ├──ConfigWritabilityCheckFile
| └──リージョン名
└──BアカウントID
└──Config
└──ConfigWritabilityCheckFile
ConfigWritabilityCheckFile
が置かれているので、バケットポリシーが機能していることがわかりました。
これでConfig
の配信先を別アカウントのS3
にする設定が完了しました。
終わりに
単にコンソールで有効化するより、CloudFormation
で有効化することでConfig
の仕組みが少し分かった気がします。
S3
にConfig
を集約した場合、どのような階層で保存されるのか気になっていたので、今回階層状況を実際に目にすることができてよかったです。
今度はControl Tower
管理下のアカウントに対し、スタックセットでConfig
を一気に有効化する方法について記事にしたいです。