AWS Config ルールの違反時に修復アクションを自動実行させる

2019.04.09

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

AWS Config ルールに対して、コンプライアンス違反時のアクションの関連付け・実行ができるようになりました。

AWS Config ルールを使用してコンプライアンス違反のリソースを修正する(2019/03/12)

以前は、コンプライアンス・ステータスが違反になった時のアクションは、ユーザーが AWS Lambda などで自前実装する必要がありましたが、今回の機能追加により、

  • ルールに違反時のアクションを関連付け
  • 違反時にはアクションを実行するだけ

と非常に見通しがよくなりました。

やってみた

この機能を使い

  • 特定の AMI でのみEC2インスタンスを起動可能
  • 違反したインスタンスは直ちに停止

という運用ルールを実際に実装してみます。

以下の流れで作業します。

  1. AWS Config の有効化
  2. AMI を制限するAWS Config ルールを追加
  3. 動作確認:管理コンソールから修復アクションを実行
  4. Lambda 関数の作成
  5. CloudWatch Events で AWS Config と Lambda の紐づけ
  6. 動作確認:イベントドリブンに修復アクションを実行

アーキテクチャー

1: AWS Config の有効化

AWS Config は、AWS リソースの設定を評価、監査、審査できるサービスです。

AWS アカウント解説時には、 AWS CloudTrail と一緒に全リージョンで有効化してください。

2. AMI を制限するAWS Config ルールを追加

AWS Configマネージドルール「approved-amis-by-id」を有効化

このルールは実行中のインスタンスで使用されている AMI が指定したものかどうかを確認します。 実行中のインスタンスで使用されている AMI が、このリストにない場合は NON_COMPLIANT です。

パラメーターの amiids に有効な AMI の一覧をカンマ区切りで指定します。

非準拠時の修復アクションを定義

AWS Config ルールに準拠しない場合の修復アクションは、Choose remediation action のエリアで設定します。

この機能は AWS Systems Manager Automation を使って実現されています。

今回は違反時にEC2インスタンスを停止するため、Remediation actionAWS-StopEC2Instance を指定し、Resource ID parameter には InstanceId を指定します。

もう一つのパラメーター AutomationAssumeRole は必須ではないため、ブランクのままで問題ありません。

参考 AWS-StopEC2Instance - AWS Systems Manager

3. 動作確認:管理コンソールから修復アクションを実行

Compliant 状態を確認

AWS Config ルールと修復アクションの動作を実際に確認します。

有効な AMI ID のインスタンスしか利用されていない場合、コンプライアンス・ステータスは Compliant です。

有効でない AMI ID の EC2 インスタンスを起動

次に有効でない AMI ID の EC2 インスタンスを起動します。

しばらくするると Compliance 列が "1 noncompliant resource(s)" となりました。

AWS Config ルールの詳細画面で、 Noncompliant なリソース一覧からリソースを選択し、 Remediate を実行すると、修復アクションが実行されます。

アクションが成功すると、 Action Status が Action executed successfully となります。

EC2 のインスタンス一覧画面では、このインスタンスの Instance State が stopped となっているはずです。

非準拠のリソースに対して毎回マニュアルで修復アクションを実行するのは手間なため、以降では CloudWatch Events と Lambda を連携してこの処理を自動化する方法を紹介します。

4. Lambda 関数の作成

AWS CloudWatch Events と AWS Config の修復(remediation)アクションをつなげる Lambda 関数を作成します。

Lambda のランタイムには Python 3.6 を利用しました。

修復アクションを CLI/SDK から呼び出す。

修復アクションの実行は Config::StartRemediationExecution API を利用します。

使い方は簡単で、ルール名とリソースのキー情報を渡すだけです。

CLI から呼び出す

$ aws configservice start-remediation-execution \
  --config-rule-name approved-amis-by-id \
  --resource-keys resourceType=AWS::EC2::Instance,resourceId=i-1234
{
    "FailedItems": []
}

Python SDK から呼び出す

import boto3
client = boto3.client('config')
client.start_remediation_execution(
  ConfigRuleName='approved-amis-by-id',
  ResourceKeys=[
   {'resourceType': 'AWS::EC2::Instance',
    'resourceId':'i-1234'}])

# Response
# {'FailedItems': [], 'ResponseMetadata': {'RequestId': '5075946d-59e0-11e9-ae1f-19dab262062b', 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amzn-requestid': '5075946d-59e0-11e9-ae1f-19dab262062b', 'strict-transport-security': 'max-age=86400', 'content-type': 'application/x-amz-json-1.1', 'content-length': '18', 'date': 'Mon, 08 Apr 2019 09:25:56 GMT'}, 'RetryAttempts': 0}}

Lambda Python から呼び出す

AWS Config のコンプライアンス・ステータスが変更するときのイベントを AWS CloudWatch Events でフックし、Lambda をターゲットとして指定する Lambda 関数が以下です。

lambda_function.py

import json
import boto3

client_config = boto3.client('config')

def lambda_handler(event, context):
    new_evaluation_result = event['detail']['newEvaluationResult']
    # NON_COMPLIANT になった場合のみ実行
    if new_evaluation_result['complianceType'] == 'NON_COMPLIANT':
        qualifier = new_evaluation_result['evaluationResultIdentifier']['evaluationResultQualifier']
        # 修復アクションを呼び出す
        return client_config.start_remediation_execution(
          ConfigRuleName = qualifier['configRuleName'],
          ResourceKeys=[
            {'resourceType': qualifier['resourceType'],
             'resourceId':qualifier['resourceId']
            }])

なお、Lambda 関数には以下のようなイベント情報が渡ります。

event.json

{
  "version": "0",
  "id": "...",
  "detail-type": "Config Rules Compliance Change",
  "source": "aws.config",
  "account": "123456789012",
  "time": "2019-04-08T08:48:05Z",
  "region": "eu-central-1",
  "resources": [],
  "detail": {
    "resourceId": "i-1234",
    "awsRegion": "eu-central-1",
    "awsAccountId": "123456789012",
    "configRuleName": "approved-amis-by-id",
    "recordVersion": "1.0",
    "configRuleARN": "arn:aws:config:eu-central-1:123456789012:config-rule/config-rule-ojehlw",
    "messageType": "ComplianceChangeNotification",
    "newEvaluationResult": {
      "evaluationResultIdentifier": {
        "evaluationResultQualifier": {
          "configRuleName": "approved-amis-by-id",
          "resourceType": "AWS::EC2::Instance",
          "resourceId": "i-1234"
        },
        "orderingTimestamp": "2019-04-08T08:47:45.767Z"
      },
      "complianceType": "NON_COMPLIANT",
      "resultRecordedTime": "2019-04-08T08:48:05.184Z",
      "configRuleInvokedTime": "2019-04-08T08:48:04.608Z"
    },
    "notificationCreationTime": "2019-04-08T08:48:05.952Z",
    "resourceType": "AWS::EC2::Instance"
  }
}

修復関数呼び出し時の引数に利用している箇所をハイライトしています。

なお、Lambda のPython ランタイムにインストールされている SDK(boto3)のバージョンが古く、StartRemediationExecution API を利用できなかったため、ソースコードに最新版の boto3 を含めてデプロイしました。

5. CloudWatch Events で AWS Config と Lambda の紐づけ

最後に、AWS CloudWatch Events を利用し、AWS Config のコンプライアンス・ステータスが変更したときには(Event Type : Config Rules Compliance Change)、作成した Lambda をターゲットとして呼び出すようにします。

6. 動作確認:イベントドリブンな修復アクションを実行

有効でない AMI で EC2 インスタンスを利用し、イベント・ドリブンに修復アクションが呼び出されるか確認してください。

EC2 は起動後間もなく強制的に停止され、Config ルールの詳細画面に行くと、修復アクションが実行済み(Action executed successfully)な Noncompliant リソースがあるはずです。(インスタンスは、Terminateしない限り、監査対象です)

Action Status が NA のままだったり(修復アクションが呼び出されていない)、Failed の場合は、設定を見直してください。

修復アクションを使わずに自前実装したい場合

AWS Systems Manager Automation を利用した修復アクションでは要件を満たせないこともあるかと思います。

そのような場合は、以下のブログのように Lambda などで修復アクションを独自実装してください。

最後に

AWS Config の修復アクションを利用し、Config ルールに非準拠なリソースに対して 修復アクションを自動的に実行するソリューションを紹介しました。

Config ルールと修復アクションが一元管理されるようになるため、Config ルールの運用が非常に楽になる、地味ながら素晴らしい機能アップデートと思います。

Lambda を書かなくても、ルール違反時には修復アクションを自動的に呼び出せるようになると、さらに使いやすくなるのではないかと思います。

それでは。

参考