一つの組織の中で、複数アカウント×複数リージョンに AWS Config ルールを一括して適用したくなるケースがあるかと思います。CloudFormations StackSets で一括設定と自動デプロイが実現可能ですが、リージョン毎に設定を変えるのは慣れてないと意外と大変です。StackSets でリージョン毎の設定を柔軟に実装するために、Condition句、 DependsOn 句と WaitCondition 機能を組み合わせて CloudFormation テンプレートを定義する方法を紹介します。
「AWS Control Tower を使えばよいじゃないか」と考えたくなりますよね。でも、自分ではそれを選択できない苦しい立場で実装を考えなければいけない人もいると信じて記事を作成してみました。
なお、この記事では CloudFormation StackSets, AWS Config の基本的な知識を前提としています。これらの基本から学びたい方は、BlackBelt 等を参考にしていただけると良いかと思います。
AWS Config と Config ルールの展開におけるリージョンの問題
この構成図のように AWS Config の有効化(レコーダーの設定)と Config ルールを3つのリージョンに展開することが要件とします。
AWS Config には「グローバルリソース (AWS IAM リソースなど) を含める」というオプションがあります。このオプションはいずれかのリージョンで有効にしておくことが望ましいですが、複数のリージョンで有効にしても同じログを複数のリージョンで取得することになるので、コストが無駄になってしまいます。
Resources:
EnableConfigMainRegion:
Type: AWS::Config::ConfigurationRecorder
Properties:
Name: "default"
RecordingGroup:
AllSupported: true
# ここの設定は代表リージョンだけ true にしたい
IncludeGlobalResourceTypes: <true or false>
RoleARN: <Config Recorder 用の IAM Role ARN>
この問題は下記項で説明している通り、Conditions 設定で解決できます。
ただしこの AWS Config レコーダーと共に Config ルールを設定しようとすると、別の問題が発生します。Config レコーダーが有効になっていない状態で Config Rule を実装しようとするとエラーになってしまうため、依存関係の設定が必要になります。
しかし例えば以下の定義だと AWS Config レコーダーのリソース定義が東京とそれ以外で異なる場合、東京以外のリージョンでエラーが発生してしまいます。
ConfigRule1:
Type: AWS::Config::ConfigRule
# !この依関係の設定がエラーとなる!
DependsOn: <東京リージョンのみで実装する AWS Config レコーダーを指定>
Properties:
ConfigRuleName: eip-attached
Source:
Owner: AWS
SourceIdentifier: EIP_ATTACHED
これらの問題を起こさない CloudFormation テンプレートをどのように設計すればよいかを解説していきます。
1つのリージョンの Stack だけ AWS Config のグローバルリージョンの設定をするには
Conditions 句を使うことで、指定のリージョンだけにリソースを作成する定義ができます。
まず条件式を定義します。「代表リージョンか、それ以外か」という条件判定ができるようにします。
Conditions:
# 代表リージョン(東京)か否かを判定
MainRegion:
!Equals [!Ref "AWS::Region", ap-northeast-1]
# それ以外(東京)のリージョンか否かを判定
OtherRegion:
!Not [ !Equals [!Ref "AWS::Region", ap-northeast-1] ]
以下は実際に AWS Config を設定する定義です。代表リージョンである東京だけで「グローバルリソースを含める」オプションを有効にしています。
Resources:
# 代表リージョン(東京以外)の AWS Config 設定
ConfigRecorderMainRegion:
Type: AWS::Config::ConfigurationRecorder
Condition: MainRegion
Properties:
Name: "default"
RecordingGroup:
AllSupported: true
# 代表リージョン(東京以外)はグローバルリソースを含める
IncludeGlobalResourceTypes: true
RoleARN: <Config Recorder 用の IAM Role ARN>
# その他のリージョン(東京以外)の AWS Config 設定
ConfigRecorderOtherRegion:
Type: AWS::Config::ConfigurationRecorder
Condition: OtherRegion
Properties:
Name: "default"
RecordingGroup:
AllSupported: true
# その他のリージョン(東京以外)はグローバルリソースを含めない
IncludeGlobalResourceTypes: false
RoleARN: <Config Recorder 用の IAM Role ARN>
AWS Config レコーダーと Config ルールの間で依存関係を定義する
AWS Config レコーダーを、代表リージョン(東京)とそれ以外のリージョンで別々に定義したので、それを踏まえた依存関係の設定をします。しかし Config ルールから直接リージョン毎に異なる Config レコーダーの定義と依存設定することはできません。そこで WaitCondition 機能を用います。
以下の例では、東京リージョン用と、それ以外のリージョン用の WaitConditionHandle を定義した上で、さらにディスパッチ用の WaitConditionHandle で参照先を分岐できるようにします。
# 東京リージョンで有効になる WaitConditionHandle
WaitHandleTokyo:
Condition: MainRegion
# 東京だけで有効になる Config レコーダーの定義を指定
DependsOn: ConfigRecorderMainRegion
Type: "AWS::CloudFormation::WaitConditionHandle"
# 東京以外のリージョンで有効になる WaitConditionHandle
WaitHandleOtherRegions:
Condition: OtherRegion
# 東京以外のリージョンで有効になる Config レコーダーの定義を指定
DependsOn: ConfigRecorderOtherRegion
Type: "AWS::CloudFormation::WaitConditionHandle"
# ディスパッチ用の WaitConditionHandle
WaitConditionDespatch:
Type: "AWS::CloudFormation::WaitCondition"
Properties:
Handle: !If [MainRegion, !Ref WaitHandleTokyo, !Ref WaitHandleOtherRegions]
Timeout: "1"
Count: 0
上記の WaitConditionHandle を Config ルールの依存先に指定します。上記でリージョンによるディスパッチをしてくれるため、リージョンによらない Config ルールを定義することができます。
ConfigRule1:
Type: AWS::Config::ConfigRule
DependsOn: WaitConditionDespatch
Properties:
ConfigRuleName: eip-attached
Source:
Owner: AWS
SourceIdentifier: EIP_ATTACHED
ConfigRule2:
Type: AWS::Config::ConfigRule
DependsOn: WaitConditionDespatch
Properties:
ConfigRuleName: s3-default-encryption-kms
Source:
Owner: AWS
SourceIdentifier: S3_DEFAULT_ENCRYPTION_KMS
WaitConditionHandle を活用しているケースは多くないかもしれませんが、上記のようなリージョンに依存したリソース定義が必要な場合には役に立つという例を紹介させていただきました。もっと望ましい実装例などありましたらコメントいただければ幸いです。