

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# ACM での Amazon EventBridge を使用してアクションを開始
<a name="example-actions"></a>

これらのイベントに基づいて Amazon EventBridge ルールを作成し、Amazon EventBridge コンソールを使用して、イベントが検出されたときに実行されるアクションを設定できます。このセクションでは、Amazon EventBridge ルールを設定するためのサンプル手順と、その結果生じるアクションについて説明します。

**Topics**
+ [Amazon SNS でのイベントへの応答](event-sns-response.md)
+ [Lambda 関数を使用したイベントへの応答](event-lambda-response.md)

# Amazon SNS でのイベントへの応答
<a name="event-sns-response"></a>

このセクションでは、ACM が正常性イベントを生成するときはいつでもテキスト通知を送信するように Amazon SNS を設定する方法について説明します。

レスポンスを設定するには、次の手順を実行します。

**Amazon EventBridge ルールを作成してアクションをトリガーするには**

1. Amazon EventBridge ルールを作成します。詳細については、「[イベントに反応する Amazon EventBridge ルールの作成](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-rule.html)」を参照してください。

   1. Amazon EventBridge コンソール ([https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/events/)) で、[**イベント**] > [**ルール**] ページに移動し、[**ルールの作成**] を選択します。

   1. [**ルールの作成**] ページで、[**イベントパターン**] を選択します。

   1. [**サービス名**] では、メニューから [**Health**] を選択します。

   1. [**イベントタイプ**] では、[**特定の正常性イベント**] を選択します。

   1. [**特定のサービス**] を選択し、メニューから [**ACM**] を選択します。

   1. [**特定のイベントタイプカテゴリ**] を選択し、[**accountNotification**] を選択します。

   1. [**任意のイベントタイプコード**] を選択します。

   1. [**任意のリソース**] を選択します。

   1. [**イベントパターンのプレビュー**] エディタで、イベントによって放出される JSON パターンを貼り付けます。この例では、[AWS ヘルスイベント](supported-events.md#health-event) セクションからパターンを使用します。

   ```
   {
      "source":[
         "aws.health"
      ],
      "detail-type":[
         "AWS Health Event"
      ],
      "detail":{
         "service":[
            "ACM"
         ],
         "eventTypeCategory":[
            "scheduledChange"
         ],
         "eventTypeCode":[
            "AWS_ACM_RENEWAL_STATE_CHANGE"
         ]
      }
   }
   ```

1. アクションを設定します。

   **ターゲット**セクションでは、Amazon Simple Notification Service (SNS) など、イベントをすぐに消費できる多くのサービスから選択するか、カスタマイズした実行可能コードにイベントを渡すために、**Lambda 関数**を選択することができます。 AWS Lambda 実装の例については、「[Lambda 関数を使用したイベントへの応答](event-lambda-response.md)」を参照してください。

# Lambda 関数を使用したイベントへの応答
<a name="event-lambda-response"></a>

この手順では、 AWS Lambda を使用して Amazon EventBridge をリッスンし、Amazon Simple Notification Service (SNS) で通知を作成し、検出結果を に発行して AWS Security Hub CSPM、管理者とセキュリティチームに可視性を提供する方法を示します。<a name="lambda-setup"></a>

**Lambda 関数と IAM ロールを設定するには**

1. まず AWS Identity and Access Management (IAM) ロールを設定し、Lambda 関数に必要なアクセス許可を定義します。このセキュリティのベストプラクティスにより、関数を呼び出す権限を持つユーザーを指定したり、そのユーザーに付与される権限を制限したりする柔軟性が得られます。ほとんどの AWS オペレーションをユーザーアカウントで直接実行することはお勧めしません。特に管理者アカウントで実行することはお勧めしません。

   IAM コンソール ([https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)) を開きます。

1. JSON ポリシーエディタを使用して、以下のテンプレートで定義したポリシーを作成します。独自のリージョンと AWS アカウントの詳細を入力します。詳細については、「[JSON タブでのポリシーの作成](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_create-console.html#access_policies_create-json-editor)」 を参照してください。

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Sid": "LambdaCertificateExpiryPolicy1",
               "Effect": "Allow",
               "Action": "logs:CreateLogGroup",
               "Resource": "arn:aws:logs:us-east-1:123456789012:*"
           },
           {
               "Sid": "LambdaCertificateExpiryPolicy2",
               "Effect": "Allow",
               "Action": [
                   "logs:CreateLogStream",
                   "logs:PutLogEvents"
               ],
               "Resource": [
                   "arn:aws:logs:us-east-1:123456789012:log-group:/aws/lambda/handle-expiring-certificates:*"
               ]
           },
           {
               "Sid": "LambdaCertificateExpiryPolicy3",
               "Effect": "Allow",
               "Action": [
                   "acm:DescribeCertificate",
                   "acm:GetCertificate",
                   "acm:ListCertificates",
                   "acm:ListTagsForCertificate"
               ],
               "Resource": "*"
           },
           {
               "Sid": "LambdaCertificateExpiryPolicy4",
               "Effect": "Allow",
               "Action": "SNS:Publish",
               "Resource": "*"
           },
           {
               "Sid": "LambdaCertificateExpiryPolicy5",
               "Effect": "Allow",
               "Action": [
                   "SecurityHub:BatchImportFindings",
                   "SecurityHub:BatchUpdateFindings",
                   "SecurityHub:DescribeHub"
               ],
               "Resource": "*"
           },
           {
               "Sid": "LambdaCertificateExpiryPolicy6",
               "Effect": "Allow",
               "Action": "cloudwatch:ListMetrics",
               "Resource": "*"
           }
       ]
   }
   ```

------

1. IAM ロールを作成して、それに新しいポリシーをアタッチします。IAM ロールの作成とポリシーのアタッチについては、[「 AWS サービスのロールの作成 (コンソール)](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-service.html#roles-creatingrole-service-console)」を参照してください。

1. [https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/) で AWS Lambda コンソールを開きます。

1. Lambda 関数を作成する 詳細については、「[コンソールで Lambda 関数を作成する](https://docs.aws.amazon.com/lambda/latest/dg/getting-started-create-function.html)」を参照してください。以下のステップを実行します。

   1. [**Create function**] ページで、[**Author from scratch**] を選択します。

   1. 「ハンドル有効期限証明書」などの名前を [**関数名**] フィールドで指定します。

   1. [**Runtime (ランタイム)**] リストで、[Python 3.8] を選択します。

   1. [**デフォルト実行ロールの変更**] を拡張し、[**既存のロールを使用する**] を選択します。

   1. [**既存のロール**] リストで、以前作成したロールを選択します。

   1. [**関数の作成**] を選択してください。

   1. [**関数コード**] に次のコードを挿入します。

      ```
      # Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
      # SPDX-License-Identifier: MIT-0
      #
      # Permission is hereby granted, free of charge, to any person obtaining a copy of this
      # software and associated documentation files (the "Software"), to deal in the Software
      # without restriction, including without limitation the rights to use, copy, modify,
      # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
      # permit persons to whom the Software is furnished to do so.
      #
      # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
      # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
      # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
      # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
      # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      
      import json
      import boto3
      import os
      from datetime import datetime, timedelta, timezone
      # -------------------------------------------
      # setup global data
      # -------------------------------------------
      utc = timezone.utc
      # make today timezone aware
      today = datetime.now().replace(tzinfo=utc)
      # set up time window for alert - default to 45 if its missing
      if os.environ.get('EXPIRY_DAYS') is None:
          expiry_days = 45
      else:
          expiry_days = int(os.environ['EXPIRY_DAYS'])
      expiry_window = today + timedelta(days = expiry_days)
      def lambda_handler(event, context):
          # if this is coming from the ACM event, its for a single certificate
          if (event['detail-type'] == "ACM Certificate Approaching Expiration"):
              response = handle_single_cert(event, context.invoked_function_arn)
          return {
              'statusCode': 200,
              'body': response 
          }
      def handle_single_cert(event, context_arn):
          cert_client = boto3.client('acm')
          cert_details = cert_client.describe_certificate(CertificateArn=event['resources'][0])
          result = 'The following certificate is expiring within ' + str(expiry_days) + ' days: ' + cert_details['Certificate']['DomainName']
          # check the expiry window before logging to Security Hub and sending an SNS
          if cert_details['Certificate']['NotAfter'] < expiry_window:
              # This call is the text going into the SNS notification
              result = result + ' (' + cert_details['Certificate']['CertificateArn'] + ') '
              # this call is publishing to SH
              result = result + ' - ' + log_finding_to_sh(event, cert_details, context_arn)
              # if there's an SNS topic, publish a notification to it
              if os.environ.get('SNS_TOPIC_ARN') is None:
                  response = result
              else:
                  sns_client = boto3.client('sns')
                  response = sns_client.publish(TopicArn=os.environ['SNS_TOPIC_ARN'], Message=result, Subject='Certificate Expiration Notification')
          return result
      def log_finding_to_sh(event, cert_details, context_arn):
          # setup for security hub
          sh_region = get_sh_region(event['region'])
          sh_hub_arn = "arn:aws:securityhub:{0}:{1}:hub/default".format(sh_region, event['account'])
          sh_product_arn = "arn:aws:securityhub:{0}:{1}:product/{1}/default".format(sh_region, event['account'])
          # check if security hub is enabled, and if the hub arn exists
          sh_client = boto3.client('securityhub', region_name = sh_region)
          try:
              sh_enabled = sh_client.describe_hub(HubArn = sh_hub_arn)
          # the previous command throws an error indicating the hub doesn't exist or lambda doesn't have rights to it so we'll stop attempting to use it
          except Exception as error:
              sh_enabled = None
              print ('Default Security Hub product doesn\'t exist')
              response = 'Security Hub disabled'
          # This is used to generate the URL to the cert in the Security Hub Findings to link directly to it
          cert_id = right(cert_details['Certificate']['CertificateArn'], 36)
          if sh_enabled:
              # set up a new findings list
              new_findings = []
                  # add expiring certificate to the new findings list
              new_findings.append({
                  "SchemaVersion": "2018-10-08",
                  "Id": cert_id,
                  "ProductArn": sh_product_arn,
                  "GeneratorId": context_arn,
                  "AwsAccountId": event['account'],
                  "Types": [
                      "Software and Configuration Checks/AWS Config Analysis"
                  ],
                  "CreatedAt": event['time'],
                  "UpdatedAt": event['time'],
                  "Severity": {
                      "Original": '89.0',
                      "Label": 'HIGH'
                  },
                  "Title": 'Certificate expiration',
                  "Description": 'cert expiry',
                  'Remediation': {
                      'Recommendation': {
                          'Text': 'A new certificate for ' + cert_details['Certificate']['DomainName'] + ' should be imported to replace the existing imported certificate before expiration',
                          'Url': "https://console.aws.amazon.com/acm/home?region=" + event['region'] + "#/?id=" + cert_id
                      }
                  },
                  'Resources': [
                      {
                          'Id': event['id'],
                          'Type': 'ACM Certificate',
                          'Partition': 'aws',
                          'Region': event['region']
                      }
                  ],
                  'Compliance': {'Status': 'WARNING'}
              })
              # push any new findings to security hub
              if new_findings:
                  try:
                      response = sh_client.batch_import_findings(Findings=new_findings)
                      if response['FailedCount'] > 0:
                          print("Failed to import {} findings".format(response['FailedCount']))
                  except Exception as error:
                      print("Error: ", error)
                      raise
          return json.dumps(response)
      # function to setup the sh region    
      def get_sh_region(event_region):
          # security hub findings may need to go to a different region so set that here
          if os.environ.get('SECURITY_HUB_REGION') is None:
              sh_region_local = event_region
          else:
              sh_region_local = os.environ['SECURITY_HUB_REGION']
          return sh_region_local
      # quick function to trim off right side of a string
      def right(value, count):
          # To get right part of string, use negative first index in slice.
          return value[-count:]
      ```

   1. [**環境変数**] で、[**編集**] を選択し、オプションで次の変数を追加します。
      + (オプション) EXPIRY\$1DAYS

        証明書の有効期限切れの通知が送信されるまでのリードタイムを日数で指定します。この関数のデフォルトは 45 日ですが、カスタム値を指定できます。
      + (オプション) SNS\$1TOPIC\$1ARN

        Amazon SNS の ARN を指定します。arn:aws:sns:*<region>*:*<account-number>*:*<topic-name>* の形式で完全な ARN を指定します。
      + (オプション) SECURITY\$1HUB\$1REGION

        別のリージョン AWS Security Hub CSPM の を指定します。これを指定しない場合、実行中の Lambda 関数のリージョンが使用されます。関数が複数のリージョンで実行されている場合、すべての証明書メッセージを 1 つのリージョンの Security Hub CSPM に送信することをお勧めします。

   1. [**基本設定**] で、 [**タイムアウト**] を 30 秒に設定します。

   1. ページの上部で、[**デプロイ**] を選択します。

このソリューションの使用を開始するには、以下の手順のタスクを実行します。

**有効期限切れの E メール通知を自動化するには**

この例では、Amazon EventBridge を通じてイベントが発生した時点で、有効期限が切れる証明書ごとに 1 通の E メールが送信されます。デフォルトでは、ACM は有効期限切れより 45 日以下の証明書に対してイベントを毎日発生させます。(この期間は、ACM API の [PutAccountConfiguration](https://docs.aws.amazon.com/acm/latest/APIReference/API_PutAccountConfiguration.html) オペレーションを使用してカスタマイズできます。) これらの各イベントは、次の自動アクションのカスケードをトリガーします。

```
ACM raises Amazon EventBridge event → 
>>>>>>> events

          Event matches Amazon EventBridge rule → 

                    Rule calls Lambda function → 

                              Function sends SNS email and logs a Finding in Security Hub CSPM
```

1. Lambda 関数を作成し、アクセス許可を設定します。(すでに完了しています。「[Lambda 関数と IAM ロールを設定するには](#lambda-setup)」を参照してください)。

1. Lambda 関数の*標準* SNS トピックを作成して、通知の送信に使用します。詳細については、「[Amazon SNS トピックの作成](https://docs.aws.amazon.com/sns/latest/dg/sns-create-topic.html)」を参照してください。

1. 新しい SNS トピックに利害関係者を登録します。詳細については、「[Amazon SNS トピックにサブスクライブする](https://docs.aws.amazon.com/sns/latest/dg/sns-create-subscribe-endpoint-to-topic.html)」を参照してください。

1. Lambda 関数をトリガーする Amazon EventBridge ルールの作成 詳細については、「[イベントに反応する Amazon EventBridge ルールの作成](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-rule.html)」を参照してください。

   Amazon EventBridge コンソール ([https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/events/)) で、[**イベント**] > [**ルール**] ページに移動し、[**ルールの作成**] を選択します。[**サービス名**]、[**イベントタイプ**]、および [**Lambda 関数**] を指定します。[**イベントパターンのプレビュー**] エディタで、次のコードを貼り付けます。

   ```
   {
     "source": [
       "aws.acm"
     ],
     "detail-type": [
       "ACM Certificate Approaching Expiration"
     ]
   }
   ```

   Lambda が受け取るようなイベントが [**サンプルイベントを表示**] の下に表示されます。

   ```
   {
     "version": "0",
     "id": "9c95e8e4-96a4-ef3f-b739-b6aa5b193afb",
     "detail-type": "ACM Certificate Approaching Expiration",
     "source": "aws.acm",
     "account": "123456789012",
     "time": "2020-09-30T06:51:08Z",
     "region": "us-east-1",
     "resources": [
       "arn:aws:acm:us-east-1:123456789012:certificate/61f50cd4-45b9-4259-b049-d0a53682fa4b"
     ],
     "detail": {
       "DaysToExpiry": 31,
       "CommonName": "My Awesome Service"
     }
   }
   ```

**次をクリーンアップするには：**

設定例や設定が不要になったら、セキュリティ上の問題や将来の予想外の料金を避けるために、すべてのトレースを削除することがベストプラクティスです。
+ IAM ポリシーおよびロール
+ Lambda function
+ CloudWatch Events ルール
+ Lambda に関連付けられた CloudWatch Logs
+ SNS トピック