1
0

More than 3 years have passed since last update.

ConfigをCloudFormationにより有効化して色々やってみた

Last updated at Posted at 2021-01-24

はじめに

 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

 テンプレートを見ると、意外と多くのリソースが作成されていることがわかります。
 一見して分かりにくいので、図にしてみます。

Config.png

 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は、ConfigS3バケットに正常に書き込めることを確認するためのテストファイルです。
 アカウント名が最初から入っているのは、別アカウントから集約する際に区別できるようにするためでしょうか。
 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を追加する必要があります。
 しかし、今回は元々記載していたのでテンプレートを変更する必要はなく、最初のスタック作成と同じテンプレートを使用します。
 最初と異なるのは、既存のリソースを使用する方法でスタックを作成するだけです。

スクリーンショット 2021-01-23 20.59.09.png

 リソースをインポートから作成します。

スクリーンショット 2021-01-23 21.01.00.png

スクリーンショット 2021-01-23 21.09.34.png

 なんとエラーが起きました。
 どうやらリソースのインポートで作成する際は、テンプレートのリソースは全て、実際にインポートしないリソースでも、リソースのインポートでサポートされている必要があるようです。

 そのため、スタックを分割して対処します。
 今回は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

スクリーンショット 2021-01-23 21.28.02.png

 先ほどと異なり、エラーが発生せずにテンプレートを指定できました。

スクリーンショット 2021-01-23 21.30.02.png

 しかし、次の画面でインポート操作では出力を追加することができないとのこと。
 仕方がないので、出力はインポート操作後に行います。

スクリーンショット 2021-01-23 21.33.13.png

 出力のセクションを削除したら成功しました。
 今度はStackを更新し、出力を追加します。

スクリーンショット 2021-01-23 21.39.19.png

 成功です。

 今度は、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の仕組みが少し分かった気がします。
 S3Configを集約した場合、どのような階層で保存されるのか気になっていたので、今回階層状況を実際に目にすることができてよかったです。
 今度はControl Tower管理下のアカウントに対し、スタックセットでConfigを一気に有効化する方法について記事にしたいです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0