TOP>コラム一覧>Cfnドリフト検知

Cfnドリフト検知

はじめに

こんにちは。CTCの須永です。
CloudFormationを利用している環境では、手動変更による意図しない変更が発生することがあります。こちらを効率よく管理するにはどのようにすればよいでしょうか? 本記事では、CloudFormationの「ドリフト検知」機能を活用し、リソースの状態を継続的に監視する仕組みを構築する方法をご紹介します。

ドリフト検知とは?

CloudFormationには、「ドリフト検知」という機能があります。これは、CloudFormationテンプレートの定義と、実際のリソース状態の差異を検出する機能です。
この機能を活用することによって、意図していないリソースの変更が発生していないか確認することできます。
また、ConfigにはCloudFormationのドリフト状態を監視するマネージドルールが提供されています。そのため、一見するとCloudFormationのドリフト検知機能とConfigを組み合わせることで、リソースの状態を継続的に監視できるように思えます。
しかし、Configではあくまで「ドリフト状態の監視」しかできず、CloudFormationのドリフト検知を自動的に実行することはできません。
そのため、リソースのドリフトを継続的に検知するためには、CloudFormationのドリフト検知を定期的に実行する仕組みが必要です。

実装の方針

本記事では、以下の仕組みを活用し、ドリフト検知を自動的に実行する方法を紹介します。

  • Lambda → CloudFormationのドリフト検知を実行
  • EventBridge → 定期的にLambda関数を実行
  • AWS Config → CloudFormationのドリフト状態を監視

この仕組みにより、CloudFormationのリソース状態を継続的に監視し、意図しない変更を検知できる環境を実現します。

構築するリソースと構成図

今回は構成をシンプルにするため、以下の構成で構築します。
なお、通知部分は本記事の対象外といたします。

  • CloudFormationのドリフト検知を実行するLambda関数を用意し、EventBridgeスケジューラで定期実行する。
  • S3を定義しているCloudFormation Stackを対象にドリフト検知を行う。
  • Configのマネージドルールを利用し、CloudFormationのドリフト状態を監視する。
  • Configルールのドリフト状態でSNSを実行するEventBridgeを作成し、SNSで運用者へメール通知を行う。(本記事の対象外)

リソースを実装してみる

本セクションでは、以下のステップで実装を進めます。

手順 サービス 実装内容
1 CloudFormation S3作成用テンプレートを用意し、デプロイ済みの状態にする
2 Config 対象のCloudFormationに対して、ドリフト状態の監視を設定する
3 Lambda CloudFormationに対して、ドリフト検知を実行する処理を設定する
4 EventBridge 作成したLambda関数を定期実行するように設定する

それではさっそく実装してみます。

1. CloudFormationによってS3をデプロイ

CloudFormationを使用してS3バケットとバケットポリシーを作成します。以下のテンプレートを適用し、S3が正しくデプロイされたことを確認します。

Resources:
    Bucket:
        Type: AWS::S3::Bucket
        Properties:
        BucketName: !Sub ${AWS::StackName}-bucket-${AWS::AccountId}
        PublicAccessBlockConfiguration:
            BlockPublicAcls: true
            BlockPublicPolicy: true
            IgnorePublicAcls: true
            RestrictPublicBuckets: true
        BucketEncryption:
            ServerSideEncryptionConfiguration:
            - ServerSideEncryptionByDefault:
                SSEAlgorithm: aws:kms
                KMSMasterKeyID: alias/aws/s3

BucketBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
        Bucket: !Ref Bucket
        PolicyDocument:
            Id: RequireEncryptionInTransit
            Version: "2012-10-17"
            Statement:
            - Principal: "*"
                Action: "*"
                Effect: Deny
                Resource:
                - !GetAtt Bucket.Arn
                - !Sub ${Bucket.Arn}/*
              Condition:
                Bool:
                  aws:SecureTransport: "false"  

上記のテンプレートによって、S3バケットとバケットポリシーが作成されていることがCloudFormation Stackから確認できます。

2. Config の設定

以下の手順でConfigルールを作成します。

  1. Configルール用のIAMロールを作成し、CloudFormationのドリフト検知に必要な権限を付与します。ポリシーの詳細はAWS公式ドキュメントを参照してください。

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "cloudformation:DetectStackDrift",
                    "cloudformation:DescribeStackDriftDetectionStatus",
                    "cloudformation:DescribeStacks",
                    "cloudformation:ListStackResources",
                    "s3:GetBucketPolicy",
                    "s3:GetBucketLocation",
                    "s3:ListBucket",
                    "s3:GetObject",
                    "iam:GetRole",
                    "iam:ListRolePolicies",
                    "iam:GetRolePolicy"
                ],
                "Resource": "*"
            }
        ]
    }    
    

  2. Configルールの設定に移ります。
    「cloudformation-stack-drift-detection-check」というマネージドルールを指定します。
    こちらがCloudFormationのドリフト状態を監視するマネージドルールになります。

  3. 評価モードの設定では変更範囲として「リソース」を指定し、リソースカテゴリを「AWS CloudFormation Stack」に設定します。

  4. パラメータには、事前に2.1.で作成したドリフトチェックに必要となるIAMロールのARNを指定します。

  5. CloudFormationに対する監視を有効化するために、「設定」→「記録されたリソースタイプ」で「CloudFormation Stack」を指定します。

3. Lambda の設定

以下の手順でLambda関数を作成します。

  1. ランタイムを「Python 3.13(執筆時点の最新バージョン)」に指定します。
  2. 以下のコードでLambda関数を作成し、デプロイします。
    こちらのコードは、スタック一覧を取得し全てのスタックに対してドリフト検知を実行するものとなっています。

    import boto3
      
      cloudformation_client = boto3.client("cloudformation")
      
      def lambda_handler(event, context):
          try:
              target_stacks = get_stacks()  # すべてのスタックを対象にする
      
              for stack in target_stacks:
                  stack_name = stack["StackName"]
                  start_drift_detection(stack_name)
          except Exception as e:
              print(f"Error processing event: {str(e)}")
              raise
      
      def get_stacks():
          """CloudFormation Stacks の一覧を取得する。
      
          Returns:
              list: Stack のリスト。
          """
          paginator = cloudformation_client.get_paginator("list_stacks")
          stacks = []
          for page in paginator.paginate(StackStatusFilter=["CREATE_COMPLETE", "UPDATE_COMPLETE"]):
              stacks.extend(page["StackSummaries"])
          return stacks
      
      def start_drift_detection(stack_name):
          """ドリフト検知を実行する。
      
          Args:
              stack_name (str): 対象の Stack 名。
          """
          try:
              response = cloudformation_client.detect_stack_drift(StackName=stack_name)
              print(f"Drift detection started for {stack_name}. Response: {response}")
          except Exception as e:
              print(f"Error initiating drift detection for {stack_name}: {str(e)}")    
      

  3. Lambda関数がCloudFormationのドリフト検知を実行できるように、実行ロールの権限を編集し、以下の2つのポリシーを付与します。
    • AWSCloudFormationReadOnlyAccess
    • AmazonS3ReadOnlyAccess(本記事ではCloudFormationでS3をデプロイしているため)

4. EventBridge の設定

以下の手順でEventBridgeのスケジューラ機能を作成します。

  1. CloudFormationのドリフト検知を定期的に実行するため「頻度」で「定期的なスケジュール」を指定します。
    ここでは例として、スケジュールのパターンに「毎日8時(cron(0 8 * * ? *))」を指定します。

  2. ターゲットに「AWS Lambda」を指定し、作成したLambda関数を指定します。

以上で、実装は完了です。

実際に使用してみる

本セクションでは、設定したドリフト検知が正しく動作するかを確認するため、2つのケースで検証を行いました。

A.ドリフトが発生していないケース

  1. S3をCloudFormationによってデプロイされた状態にします。
    今回S3に変更は加えていないのでそのまま次のステップに進みます。
  2. EventBridge実行時間になるとドリフトチェックが実行され、対象CloudFormation Stackの「ドリフトステータス」が「IN_SYNC」になっていることを確認します。

    こちらでドリフト検知が実行されたことが確認できます。
  3. Configルールから対象CloudFormation Stackのコンプライアンスが「準拠」であることを確認します。

    こちらによって、ドリフト検知が正常に実行されたことが確認できました。

B.ドリフトが発生しているケース

  1. S3をCloudFormationテンプレートと異なる状態になるように手動で変更します。
    今回は「パブリックアクセスをすべてブロック」をオフに変更します。
  2. EventBridge実行時間になるとドリフトチェックが実行され、対象CloudFormation Stackの「ドリフトステータス」が「DRIFTED」になっていることを確認します。

  3. Configルールから対象CloudFormation Stackのコンプライアンスが「非準拠」であることを確認します

    こちらによって、意図していないリソースの変更を適切に検知できることが確認できました。

さいごに

今回はCloudFormationのドリフト検知を定期実行するための手順をご紹介しました。
CloudFormationのドリフト検知を適切に運用することで、手動による変更を素早く検知し、環境の一貫性を維持できます。
また、この構成を応用すれば、マルチアカウント環境で作成したCloudFormation StackSetsのドリフト検知を実施し、マルチアカウントのガードレールとして活用することも可能です。
リソースをIaCとして適切に管理することで、セキュアで安定した環境を維持していきましょう。

CTCは、AWSのビジネス利活用に向けて、お客様のステージに合わせた幅広い構築・運用支援サービスを提供しています。
経験豊富なエンジニアが、ワンストップかつ柔軟にご支援します。
ぜひ、お気軽にお問い合わせください。

お問い合わせ

【著者プロフィール】

須永 響(すなが ひびき)

伊藤忠テクノソリューションズ株式会社 クラウドアーキテクト

マルチアカウント環境におけるシステム基盤の提案・構築業務を担当。

TOP>コラム一覧>Cfnドリフト検知

pagetop