×
採用サイトはこちら

設定ミスを自動で防ぐ!AWS Configで非準拠DBを自動修復

はじめに

各リソースの設定が適切か、確認するのが大変だった」「手作業で適切な設定に修正するのが大変だった」、皆さんはこんな経験ありませんか? このような状況では、作業者の確認漏れや設定の修正ミスが起こる可能性があります。

例えば、暗号化されていないDBインスタンスを放置した場合、ユーザーの個人情報や企業の重要なデータを平文で保存することとなり、情報漏洩のリスクを伴います。

作業者が暗号化のルールを徹底することも重要ですが、ルール非準拠の構成を検知し自動で修正する仕組みがあるとセキュリティリスクがぐっと下がります

本記事では、AWS Configを利用し、ルール非準拠のDBインスタンスを検知しAmazon SNSで担当者に通知、SSM Automationで該当インスタンスを停止する手順を紹介します。

目次

サービス概要

今回のハンズオンに使用するAWSサービスについて、簡単に概要を説明します。

AWS Config

AWS Configは、AWSアカウント内のリソース構成を管理するサービスです。リソースの作成、変更、削除を継続的に記録し、設定したルールと照らし合わせて評価します。

AWS Configがサポートしているリソースには様々なものがあります。EC2、S3、RDSなどのイメージしやすいものだけでなく、IAMポリシーなどもサポートしています。サポート対象のリソースタイプは随時追加されています。

AWS Configに設定できるルールには大きく2種類あります。

AWS Config マネージドルール

AWS Config マネージドルールはAWSが予め定義したConfigルールです。多くのマネージドルールが用意されており、設定するだけですぐに運用開始することができます。また、マネージドルールはカスタマイズすることも可能です。

以下はマネージドルールの例です。

ルール名 ルール内容
access-keys-rotated アクティブなIAMアクセスキーが指定された日数内にローテーションされるかどうか
cloudfront-s3-origin-access-control-enabled S3オリジンタイプを使用するCloudFrontディストリビューションで、オリジンアクセスコントロール(OAC)が有効かどうか
rds-storage-encrypted RDS DBインスタンスでストレージの暗号化が有効になっているかどうか

本記事ではrds-storage-encryptedを使用してハンズオンを実施します。

AWS Config カスタムルール

AWS Config カスタムルールは、ゼロから作成するConfigルールです。カスタムルールにはAWS Config カスタム Lambda ルール(Java または Python を使用したLambda関数で定義したルール)と、AWS Config カスタムポリシールール(Guardというpolicy-as-code言語で定義したルール)の2種類があります。

詳しくは公式のデベロッパーガイドをご覧ください。

Amazon SNS

Amazon SNS(Simple Notification Service)は、完全マネージド型のメッセージングサービスです。発信元(パブリッシャー)が「トピック」と呼ばれるチャネルにメッセージを送り、そこに登録された宛先(サブスクライバー)へ一斉に通知を配信する仕組みを提供します。

Amazon SNSのパブリッシャーには、EC2やECS上で動くアプリケーション開発、Lambda関数、Amazon CloudWatchのアラートなど様々なAWSサービスがなり得ます。

サブスクライバーにはAmazon SQSやLambdaなどのAWSサービス、EメールやSMSなどの通知、HTTP/HTTPSによるWebサーバへJSONメッセージをプッシュ送信などが挙げられます。

より詳しく知りたい方はこちらの記事もご参照ください。

今すぐできる!Amazon SNSでイベントのメール通知を実装しよう

Amazon EventBridge

Amazon EventBridgeは、AWSサービスや独自のアプリケーションで発生したイベントを受け取り、あらかじめ定義したルールに従って別のサービスへ振り分けるサーバーレスのイベントバスサービスです。

ルールには受け取りたいイベントの種類やイベントパターン(内容の条件)を指定します。条件に一致したイベントは、ターゲットとして設定したAmazon SNSやSSM Automationなど複数のAWSサービスへ配信することができます。

また、「入力変換」という機能を使うと、イベント本文の一部を変数として取り出し、ターゲットに渡すペイロードを任意の形式に加工できます。本記事でも、AWS Configから送られてくるイベントを読みやすい通知メッセージや、SSM Automationのランブックに渡すパラメータ形式に変換するために、この入力変換を活用します。

SSM Automation

SSM Automationは、AWSのサービス(EC2、RDS、S3など)のメンテナンスやデプロイなどのタスクを自動化するためのAWS Systems Manager(SSM)のツールです。

SSM Automationで実行したい操作はランブックというものに定義します。ランブックには順次実行されるステップ(操作)が1つ以上含まれます。AWSが事前定義したランブックを使用したり、ユーザーがPythonやPowerShellスクリプトを直接埋め込んだ独自のランブックを作成して使用することができます。今回のハンズオンでは独自ランブックを使用します。

ランブックはAmazon EventBridgeイベントのターゲットとして指定することもできます。これにより、ある操作を定期的に実行させたり、特定のAWSシステムイベントが発生したときに実行させることが可能です。

実装

実装の手順は以下の通りです。 前提として必要なVPC、サブネット、セキュリティグループなどは作成されているものとします。

  1. AWS Configでrds-storage-encryptedルールを使用するよう設定する
  2. Amazon SNSでルール非準拠インスタンス検知の通知用トピックを作成する
  3. Amazon EventBridgeからAmazon SNSをターゲットにし、メール通知を行う
  4. Amazon EventBridgeからSSM Automationランブックをターゲットにし、自動でインスタンス停止を行う
  5. DBインスタンスを作成し、Configが検知して非準拠のインスタンスのみが停止になっていることを確認する

今回のハンズオンでの構成図は以下のようになります。

AWS Configでrds-storage-encryptedルールを使用するよう設定する

AWS Configのダッシュボードにアクセスすると以下のような画面が表示されます。

画面左側のパネルにある「ルール」からルールを作成していきます。

「ルールを追加」をクリックし、AWSマネージドルールが選択された状態でrds-storage-encryptedを検索します。

表示されたルールを選択し「次へ」をクリックすると、評価モードなどの設定画面が表示されます。 リソースをデプロイする前に検知するプロアクティブモードもありますが、今回は検知モードを使用します。 「変更範囲」を「リソース」、「リソースタイプ」を「AWS RDS DBInstance」と設定します。

AWS Configルールの中にはパラメータを受け取るものもあります。 以下はルールのパラメータとタグを設定する画面です。 rds-storage-encryptedにはkmsKeyIdというパラメータがあり、ストレージの暗号化に使用するKMSキーIDまたはAmazonリソースネーム(ARN)を渡すことが可能です。これにより特定のキーでの暗号化がなされているかどうか検知できます。 今回は特に指定せずこのまま作成します。

以下は確認画面です。

作成後は以下のようにルール一覧画面に表示されます。

Amazon SNSでルール非準拠インスタンス検知の通知用トピックを作成する

AWS Configで非準拠リソースを検知した際に、管理者としてメールで通知を受け取るようAmazon SNSを設定していきます。 まず、SNSのページからトピックを作成します。

今回はEメールで通知を受け取りたいため、「スタンダード」を選択します。 その他の設定はデフォルトのままです。

トピックを作成すると詳細ページに遷移します。 ここからサブスクリプションを設定していきます。

サブスクリプション作成ページでサブスクライブプロトコルを選択できます。 今回はメール通知を受け取りたいので「Eメール」を選択し、エンドポイントにメールアドレスを入力します。

サブスクリプションを作成すると以下のように表示され、該当メールアドレスに確認メールが送信されます。

確認メール内の「Confirm subscription」をクリックすると確認ページが表示されます。 その後サブスクリプション詳細ページを更新すると、ステータスが「確認済み」に変わっているのが確認できます。 これでAmazon SNSの準備は完了です。

Amazon EventBridgeからAmazon SNSをターゲットにし、メール通知を行う

Amazon EventBridgeの設定

ここから、Amazon EventBridgeを設定していきます。 トップページから「イベントパターンを含むEventBridgeルール」を選択しルールを作成します。

ルール作成に進むと、以下のような画面が表示されます。 「トリガーイベント」にルール実行のきっかけとなるイベントを、ターゲットに最終的に実行させたい処理を設定します。

今回作成したConfigルールが該当するイベントは「Config Rules Compliance Change」なのでそれをトリガーイベントに設定します。

次にターゲットに先ほど設定したSNSトピックを選択します。

EventBridgeのルールを作成するとき、EventBridgeが引き受ける実行ロールを作成してくれます。

作られたロールは以下のようになっています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "sns:Publish"
            ],
            "Resource": [
                "arn:aws:sns:ap-northeast-1:{{accountID}}:MyHandsonTopic"
            ]
        }
    ]
}

これでEventBridgeルールの作成は完了です。

Amazon EventBridgeからSSM Automationランブックをターゲットにし、自動でインスタンス停止を行う

SSM Automation ランブックの作成

自動でルール非準拠DBインスタンスを停止させるためにSSM Automationのランブック(ドキュメント)を作成していきます。 以下の画像は実行したオートメーション(自動処理)の一覧ページです。 ここの「Create runbook」からランブックを作成できます。

もしくはドキュメントのページから作成ページに飛ぶことも可能です。 こちらではAWSが事前に作成しているドキュメントや、自分が作成したドキュメント、共有されたドキュメントを確認することができます。

AWS-StopRdsInstance」という、いかにもおあつらえ向きなAWSドキュメントがあるのですが、残念なことに今回の構成ではそのまま使用することはできません… というのも、AWS-StopRdsInstanceはパラメータとしてインスタンスIDを受け取るのですが、Configから送られてくるイベントにインスタンスIDは存在しません。 なのでイベントで送られてくるリソースIDをインスタンスIDに変換する必要があります。 今回はそれも含めてオリジナルのランブックを作成していきます。

ランブック作成画面は以下のようになっております。 左のパネルから基本的なアクションやAWS API、定義済みランブックを真ん中のパネルにドラッグしていき処理を組み立てていきます。

今回のランブックの構成は以下の通りです。 前段のスクリプトで「リソースID → インスタンスID」の変換を行います。 そのスクリプトの出力をAWS-StopRdsInstanceに渡し、該当インスタンスを停止させます。

リソースIDからインスタンスIDへの変換は以下のスクリプトで行っています。 RDSのdescribe_db_instancesにリソースIDを渡し、インスタンスIDを取得しています。

import boto3

def script_handler(events, context):
    rds = boto3.client('rds', region_name='ap-northeast-1')
    response = rds.describe_db_instances(
        Filters=[
            {
                'Name': 'dbi-resource-id',
                'Values': [
                    events['rdsResourceId']
                ]
            }
        ]
    )
    instanceId = response['DBInstances'][0]['DBInstanceIdentifier']
    return {'InstanceId': instanceId, 'AutomationAssumeRole': events['automationAssumeRole']}

ランブックの定義はyamlコードで作成することも可能です。 今回のランブックのコードは以下のようになっています。

schemaVersion: '0.3'
description: Stop RDS instance from a resource ID.
assumeRole: '{{ AutomationAssumeRole }}'
parameters:
  ResourceId:
    type: String
    description: (Required) RDS Resource Id to stop
    allowedPattern: ^[a-zA-Z]*([-]?[\w]+)*$
  AutomationAssumeRole:
    type: String
    description: (Optional) The ARN of the role that allows Automation to perform the actions on your behalf.
    default: ''
    allowedPattern: ^$|arn:(aws[a-zA-Z-]*)?:iam::\d{12}:role\/?[a-zA-Z_0-9+=,.@\-_\/]+
mainSteps:
  - name: TransformResourceId2InstanceId
    action: aws:executeScript
    nextStep: AWS_StopRdsInstance
    isEnd: false
    inputs:
      Runtime: python3.12
      Handler: script_handler
      InputPayload:
        rdsResourceId: '{{ ResourceId }}'
        automationAssumeRole: '{{ AutomationAssumeRole }}'
      Script: |-
        import boto3

        def script_handler(events, context):
          rds = boto3.client('rds', region_name='ap-northeast-1')
          response = rds.describe_db_instances(
              Filters=[
                  {
                      'Name': 'dbi-resource-id',
                      'Values': [
                          events['rdsResourceId']
                      ]
                  }
              ]
          )
          instanceId = response['DBInstances'][0]['DBInstanceIdentifier']
          return {'InstanceId': instanceId, 'AutomationAssumeRole': events['automationAssumeRole']}
    outputs:
      - Type: String
        Name: InstanceId
        Selector: $.Payload.InstanceId
      - Type: String
        Name: AutomationAssumeRole
        Selector: $.Payload.AutomationAssumeRole
  - name: AWS_StopRdsInstance
    action: aws:executeAutomation
    isEnd: true
    inputs:
      DocumentName: AWS-StopRdsInstance
      RuntimeParameters:
        InstanceId: '{{ TransformResourceId2InstanceId.InstanceId }}'
        AutomationAssumeRole: '{{ AutomationAssumeRole }}'

詳しいランブックの作成方法は公式ドキュメントに載っています。

独自のランブックの作成

AutomationAssumeRoleにはSSMが処理を実行するために必要な権限ロールを渡します。 今回の権限は以下のように設定しております。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "HandsonStopRDSInstance",
            "Effect": "Allow",
            "Action": [
                "rds:DescribeDBInstances",
                "rds:StopDBInstance"
            ],
            "Resource": "arn:aws:rds:*:{accountId}:db:*"
        }
    ]
}

インスタンス停止用EventBridgeルールの作成

作成したランブックを使用してインスタンス停止用のEventBridgeルールを作成します。 ターゲットに「Systems Manager オートメーション」をドラッグで挿入し、先ほど作成したランブックを選択します。

入力変換を利用してランブックに必要な情報を抽出します。

注意点

ランブックのパラメータに値を渡すとき、そのまま値を渡しても動作しません。 パラメータに値を渡すときは各キーに対する値をリストにする必要があります。

SSM Automationは内部的にStartAutomationExecutionAPIを呼び出しており、そのシンタックスではParametersをリストで受け取っています。

NG:

{
   "ResourceId": "<resourceId>"
}

OK:

{
   "ResourceId": ["<resourceId>"]
}

参照: StartAutomationExecution

これでインスタンス停止用ルールの作成は完了です。

DBインスタンスを作成し、Configが検知して非準拠のインスタンスのみ停止になっていることを確認する

RDS DBインスタンスの作成

ここまでで、非準拠となるインスタンスを検知し、自動で停止させるルールを作成しました。 作成したルールを検証するため、実際にRDS DBインスタンスを作成していきます。

右上の「データベースを作成」ボタンからインスタンスを作成していきます。 「エクスプレス設定」を選ぶと数秒でAurora PostgreSQLサーバーレスデータベースを作成することができますが、今回は普通のDBインスタンスを作成したいため「フル設定」を選択します。

「フル設定」を選択すると、データベースの各種設定ができます。 今回のデータベースエンジンはPostgreSQLを選択しました。(今回のハンズオンではデータベースの操作はしないのでエンジンによる差はないかと思います。) 「簡単に作成」を選択するとインスタンス(ストレージ)の暗号化が自動で設定されます。今回は暗号化されないよう設定したいので「フル設定」を選択します。 テンプレートは「無料利用枠」を選択しました。今回のハンズオンではこれで十分です。

下記ではエンジンのバージョンや、データベースの認証情報を設定できます。 認証情報管理で「AWS Secrets Manager」を選択すると安全かつ簡単にパスワードなどを管理できます。 今回はコスト面から「セルフマネージド」を選択しましたが、実際にデータベースを使用する際は「AWS Secrets Manager」の使用が推奨されます。

以下ではDBインスタンスのネットワークについて設定します。 ハンズオン用に作成したVPCやサブネット、セキュリティグループを選択します。

最後にバックアップや暗号化などの設定をします。 デフォルトでは「暗号を有効化」にチェックが入っていますが、今回は検証のため暗号化せずにインスタンスを作成します。

「データベースを作成」ボタンをクリックすると、データベース一覧画面で作成したインスタンスが「作成中」の状態になっていることが確認できます。 インスタンスの作成には数分かかり、完了後は以下の画像のようにステータスが「利用可能」に変わります。

ルール非準拠インスタンスの検知

ルール非準拠のインスタンスを作成してから数分後にAWS Configのダッシュボードを確認すると以下のようになっていました。 ルールに引っかかっているものが検知されたことがわかります。

まずルールの方を確認してみましょう。 作成したルールに反しているリソースが1件あることが確認できます。

次にリソースを確認してみます。 先ほど作成した「database-1」が検出され、コンプライアンスの状態が「非準拠」となっています。

Amazon SNSからのメール受信

非準拠インスタンスの検知がトリガーとなり、以下のようなメールが届きます。

先ほど作成したDBインスタンスがルール非準拠だということがわかります。 ただ、びっくりするほど読みづらい…

なのでEventBridgeの入力変換を活用して読みやすいメッセージに直していきます。 先ほどのルール作成画面中、ターゲット内の「入力変換」を有効化し、以下の画面で編集していきます。

  1. 一番左のパネルでサンプルイベントを選択します。今回は「Config Rules Compliance Change」。
  2. その次のパネルで、テンプレート上で使いたい値を変数として定義します。$.を使うことでイベントからの値を使用することができます。
  3. 次のテンプレートパネルで定義した変数を使い出力させたい文字列を作成していきます。
  4. 最後のパネルで最終的な出力が確認できます。

また非準拠DBインスタンスを作成してみると以下のメールが届きました。 入力変換を利用することで必要な情報のみに絞ることができました。

SSM Automationによるインスタンスの自動停止

メールが送られてきたのを確認し、RDSのインスタンスページにアクセスすると以下のようになっていました。

非準拠インスタンスの検知がトリガーとなりSSM Automationによりインスタンスの停止が確認できました。

ルールに準拠しているDBインスタンスの作成

ルールに準拠しているDBインスタンスを作成してみます。 手順は非準拠インスタンスとほぼ同じで、暗号の有効化のみ違いがあります。

AWS Configのダッシュボードを確認してみます。 ルールには引っかかっておらず、準拠リソースとして表示されています。

リソースの画面を見るとdatabase-2のコンプライアンス状態が「準拠」となっていることが確認できます。

すべてのDBインスタンスを表示すると以下のようになります。

おわりに

今回、Configで非準拠のDBインスタンスを検知して自動で停止してみました。AWS Configを利用することでルールに違反しているリソースや構成を検知してくれます。 また、Amazon SNSで通知を行ったりSSM Automationを利用して様々な操作を自動で実行させることができ、実際の運用にも活用することができます。

このような構成にすることでセキュリティリスクとなるリソースをいち早く検知し、人の手を介さず応急処置をすることが可能で被害を最小限に食い止められるでしょう。

実運用では、SCPや様々なポリシーでルールに違反しているリソースを作らせない「予防的ガードレール」と、実際に作られてしまった際に検知し、責任者への通知やインスタンス停止などの応急処置を行う「発見的ガードレール」を組み合わせることでよりセキュアな環境を構築することができます。

今回のハンズオンを通して、AWS Configの便利さを体感しましたが、どちらかというとAmazon EventBridgeの便利さに感動しました。様々なイベントをトリガーにして処理を実行することもできますし、スケジュールを設定して実行することもできるので多くの場面で利用できるサービスだと実感しました。

ハンズオンで苦労した点はSSM Automationへのパラメータの渡し方です。SSM Automationが内部的にStartAutomationExecutionAPIを呼び出していることを知らなかったので、実行できない原因を突き止めるのに時間がかかりました。

この記事が同じような構成を試そうとしている方への助けとなれば幸いです。

We Are Hiring!

AWSマネージドサービスを活用したセキュリティ自動化の学びを、実践的な現場で活かしてみませんか?

FindConsultingには、異業種から転身してAWSエンジニアとして活躍するメンバーや、SQLのみのスキルからPython・Reactでの開発案件に挑戦するメンバーなど、入社後にキャリアを大きく広げた社員が多くいます。資格取得支援や実案件への早期参画など、次のステップへ踏み出すための環境が整っています。

「今の環境では設計・構築の経験を積む機会が少ない」「AWSを使った運用自動化のスキルを深めていきたい」と感じている方は、ぜひ一度話を聞きに来ませんか?

現在、FindConsultingではキャリアチェンジ・スキルアップを目指す仲間を募集しています。
まずはカジュアル面談からでも、ぜひお気軽にお声がけください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

弊社FindConsulting在籍のエンジニアです。
採用支援Webアプリケーション開発にてフロントエンドを担当してきました。
開発業務に留まらず、開発効率化ツールの導入やドキュメント整備などを通じてチームの成長に注力しています。
本ブログではAWSに関わる技術情報を発信していきます。

目次