CloudFormation StackSetsを使ってマルチアカウント/マルチリージョンでAWS Configを有効化する

記事タイトルとURLをコピーする

最近足つぼマットにハマっているCI部2課の山﨑です。

本日はCloudFormation StackSetsを使ってマルチアカウント/マルチリージョンでAWS Configを有効化してみましたので検証内容を記録していきます。

CloudFormation StackSetsとは

複数のアカウントおよびリージョンのスタックを 1度のオペレーションで、作成、更新、削除できる機能となります。

詳細は以下のブログをご参照ください。

blog.serverworks.co.jp

検証イメージ

  • ManagementアカウントとMemberアカウントの2つのアカウントを利用

f:id:swx-yamasaki:20210803203139p:plain
Organizationsイメージ

  • ManagementアカウントのCloudFormation StackSetsを利用してMemberアカウントのAWS Configを有効化する
  • Memberアカウントでは大阪リージョンとシドニーリージョンのConfigを有効化する
  • MemberアカウントのAWS ConfigのログはManagementアカウントに配置しているS3に出力する

f:id:swx-yamasaki:20210803203159p:plain
構成イメージ

いざ検証

ログ出力用S3バケットの作成

今回はManagementアカウントの東京リージョンで yamasaki-config-test という名前のS3バケットを作成しました。バケットポリシーにはAWSドキュメントを参考に以下のポリシーを記載しています。

Amazon S3 バケットのアクセス許可 - AWS Config

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AWSConfigBucketPermissionsCheck",
            "Effect": "Allow",
            "Principal": {
                "Service": "config.amazonaws.com"
            },
            "Action": "s3:GetBucketAcl",
            "Resource": "arn:aws:s3:::yamasaki-config-test"
        },
        {
            "Sid": "AWSConfigBucketExistenceCheck",
            "Effect": "Allow",
            "Principal": {
                "Service": "config.amazonaws.com"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::yamasaki-config-test"
        },
        {
            "Sid": "AWSConfigBucketDelivery",
            "Effect": "Allow",
            "Principal": {
                "Service": "config.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::yamasaki-config-test/AWSLogs/*",
            "Condition": {
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control"
                }
            }
        }
    ]
}

Configの有効化

今回はManagementアカウントの東京リージョンからStackSetsを流しました。

f:id:swx-yamasaki:20210802192632p:plain
StackSetの作成

AWS Configを有効化するStackSetsはAWSがサンプルテンプレートを提供しているので、今回はサンプルテンプレートを参考に以下のテンプレートを流しました。

AWSTemplateFormatVersion: 2010-09-09
Description: Enable AWS Config

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Recorder Configuration
        Parameters:
          - AllSupported
          - IncludeGlobalResourceTypes
          - ResourceTypes
      - Label:
          default: Delivery Channel Configuration
        Parameters:
          - DeliveryChannelName
          - Frequency
    ParameterLabels:
      AllSupported:
        default: Support all resource types
      IncludeGlobalResourceTypes:
        default: Include global resource types
      ResourceTypes:
        default: List of resource types if not all supported
      DeliveryChannelName:
        default: Configuration delivery channel name
      Frequency:
        default: Snapshot delivery frequency

Parameters:
  AllSupported:
    Type: String
    Default: True
    Description: Indicates whether to record all supported resource types.
    AllowedValues:
      - True
      - False

  IncludeGlobalResourceTypes:
    Type: String
    Default: True
    Description: Indicates whether AWS Config records all supported global resource types.
    AllowedValues:
      - True
      - False

  IncludeGlobalResourceTypeRegion:
    Type: String
    Default: ap-northeast-1

  ResourceTypes:
    Type: List<String>
    Description: A list of valid AWS resource types to include in this recording group, such as AWS::EC2::Instance or AWS::CloudTrail::Trail.
    Default: <All>

  DeliveryChannelName:
    Type: String
    Default: ConfigDeliveryChannel
    Description: The name of the delivery channel.

  Frequency:
    Type: String
    Default: 24hours
    Description: The frequency with which AWS Config delivers configuration snapshots.
    AllowedValues:
      - 1hour
      - 3hours
      - 6hours
      - 12hours
      - 24hours

Conditions:
  IsAllSupported: !Equals
    - !Ref AllSupported
    - True
  IsGeneratedDeliveryChannelName: !Equals
    - !Ref DeliveryChannelName
    - <Generated>
  IsIncludeGlobalResourceTypeRegion: !Equals [ !Ref IncludeGlobalResourceTypeRegion, !Ref "AWS::Region" ]
  GlobalServiceDeployRegion: !Equals [!Ref AWS::Region, ap-northeast-3]

Mappings:
  Settings:
    FrequencyMap:
      1hour   : One_Hour
      3hours  : Three_Hours
      6hours  : Six_Hours
      12hours : Twelve_Hours
      24hours : TwentyFour_Hours

Resources:

  ConfigRecorderRole:
    Type: AWS::IAM::Role
    Condition: GlobalServiceDeployRegion
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - config.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      RoleName: "Config-Yamasaki-Role"
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/service-role/AWS_ConfigRole"

  ConfigRecorder:
    Type: AWS::Config::ConfigurationRecorder
    Properties:
      Name: !Sub "configuration-recorder-${AWS::Region}"
      RoleARN: !Sub "arn:aws:iam::${AWS::AccountId}:role/Config-Yamasaki-Role"
      RecordingGroup:
        AllSupported: "true"
        IncludeGlobalResourceTypes: !If [IsIncludeGlobalResourceTypeRegion, true, false]
        ResourceTypes: !If
          - IsAllSupported
          - !Ref AWS::NoValue
          - !Ref ResourceTypes

  ConfigDeliveryChannel:
    Type: AWS::Config::DeliveryChannel
    Properties:
      Name: !If
        - IsGeneratedDeliveryChannelName
        - !Ref AWS::NoValue
        - !Ref DeliveryChannelName
      ConfigSnapshotDeliveryProperties:
        DeliveryFrequency: !FindInMap
          - Settings
          - FrequencyMap
          - !Ref Frequency
      S3BucketName: "yamasaki-config-test"

StackSetsでは、デプロイターゲットで指定するOU配下のAWSアカウント(今回はMemberアカウント)で指定したリージョン毎にCloudFormationのStackを1つずつ流していきます。そのため、グローバルリソースであるIAMロールをConfig有効化のStackSetsでそのまま流してしまうとIAMロールを各リージョンごとに作成することになる=構築処理が複数回発生するため重複エラーとなります。

f:id:swx-yamasaki:20210802203902p:plain
IAMロールの重複エラー

今回は以下の2つの手順で重複エラーを回避しました。

特定リージョンでのみIAMロールを作成する

CloudFormationのConditionを利用して大阪リージョンでStackを流す時のみIAMロールを作成するように記述しています。

Conditions:
〜〜
〜〜
  GlobalServiceDeployRegion: !Equals [!Ref AWS::Region, ap-northeast-3]


Resources:

  ConfigRecorderRole:
    Type: AWS::IAM::Role
    Condition: GlobalServiceDeployRegion
 〜〜
 〜〜

StackSetsで大阪リージョンからStackを流すように設定する

OUとリージョンの設定画面より、デプロイターゲットで指定するOU配下のAWSアカウント(今回はMemberアカウント)でStackを流す際に大阪リージョンからStackを流すように順番を変更します。

f:id:swx-yamasaki:20210803094142p:plain
OUとリージョンの指定

動作確認

Memberアカウントの大阪リージョンとシドニーリージョンのAWS Configが有効化されていることが確認できました

f:id:swx-yamasaki:20210802195233p:plain
有効化されたAWS Config(大阪リージョンとシドニーリージョン)

補足: StackSets の自働デプロイのデプロイ順序について ※2021年9月30日追記

補足内容

StackSets ではOrganizations のOUに新規アカウントが追加されたことをトリガーにしてStackを流すことができる自働デプロイ機能がありますが、この機能を利用して複数のリージョンにStackを流す場合は注意が必要です。

StackSets のコンソール画面でデプロイするリージョンを1つ以上選択します。Stackはここで指定したリージョンの順序で流れます。ただし自働デプロイ機能でデプロイされる場合はコンソール画面で指定した順序ではありません。

f:id:swx-yamasaki:20210930172421p:plain

Configを有効化するStackSetsで注意すべき点

本ブログではConfigを有効化するにあたって必要なIAMロールを大阪リージョンでのみ作成するようにCloudFormationのテンプレートに条件文を書き、大阪リージョンからStackSetsがデプロイされるようにStackSetsのコンソール画面上で順序を指定しました。これはIAMロールがグローバルリソースであるためです。しかし、自働デプロイの場合は大阪リージョンからデプロイされるとは限りません。仮にバージニア北部リージョンからデプロイされた場合、Config用のIAMロールが作成されないためStackSetsが失敗してしまいます。

これを回避するためには上述の条件文を削除し、以下のようにIAMロールをデプロイするリージョンごとに作成するようにCloudFormationテンプレートを記述する必要があります。

Resources:

  ConfigRecorderRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - config.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      RoleName: !Sub "Config-Yamasaki-Role-${AWS::Region}"
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/service-role/AWS_ConfigRole"

まとめ

CloudFormation StackSetsはマルチアカウント/マルチリージョンでAWS環境構築する際はかなり使えるサービスですので押さえておくと良さそうです。

その他参考記事

blog.serverworks.co.jp

山﨑 翔平 (Shohei Yamasaki) 記事一覧はコチラ

2019/12〜2023/2までクラウドインテグレーション部でお客様のAWS導入支援を行っていました。現在はIE(インターナルエデュケーション)課にて採用周りのお手伝いや新卒/中途オンボーディングの業務をしています。2023 Japan AWS Top Engineers/2023 Japan AWS Ambassadors