CloudWatch Eventsを使ってAWSリソース変更時にメール通知する

2016.05.23

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

CloudWatch Events について

CloudWatch Eventは2016年1月に発表された比較的新しいサービスで、AWSリソースの変更情報をタイムリーにストリーム伝達します。

CloudWatch Events はイベントソースとして AWS API に対応しています。

AWS のリソースを変更する

  • AWS マネージメントコンソール
  • AWS CLI
  • AWS SDK

といった手段はいずれも API を呼び出しているだけのため、AWS API をイベントソースに指定すると、変更手段によらずAWSリソースを変更するイベント全般をフックすることができます

cloudwatch events overview

Route 53 リソースと連携させてみる

AWSにはAmazon Route 53というDNSサービスがあります。

一般的にDNS設定を変更する頻度は多くないものの、オペミスなどにより誤って設定変更すると、サービスへの影響が甚大です。 更新した時には即座に通知(周知)したいこともあるかと思います。

そこで CloudWatch Events を活用して、Route 53 のリソース変更に対してイベント発火する方法を紹介します。

アーキテクチャー

cloudwatch events overview

 

 イベントのトリガー

今回は、Route 53 に対する更新系 API 操作をトリガーにします。

イベントの発火先

トリガーの発火先として、今回は Amazon SNS を利用します。

発火先には Amazon SNS 以外にも

  • AWS Lambda
  • Amazon SQS
  • Amazon Kinesis Stream
  • Bullet-in ターゲット

などに対応しています。

発火先には複数のターゲットを指定できます。

やってみた

Route 53 の API 呼び出しと CloudWatch Events/SNS を連携させましょう。

以下の順で作業します。

  1. CloudTrail の有効化
  2. SNS トピックの作成
  3. CloudWatch Eventsの作成

重要な点として、 Route 53 は API のエンドポイントが N. Virginia(us-east-1) リージョンのため、CloudTrail や SNS の操作は同リージョンで行います。

1. CloudTrail の有効化

今回は API 呼び出しをトリガーにするため、API 呼び出しが記録されるように AWS CloudTrail を有効にします。 CloudWatch Events を利用する・しないにかかわらず、API のログを残しておかないと、障害発生時の問題解決が困難になります。

AWS CloudTrailが無効だった場合は、今回を機に有効にしましょう。

Route 53 は API のエンドポイントが N. Virginia リージョンのため、少なくとも同リージョンで Cloud Trail を有効にします。

2. SNS トピックの作成

イベントの通知先 SNS トピックを作成します。

今回はトピック名を「cloudwatch-events-test」としました。 このトピックに対して確認のしやすさを優先してプロトコル「Email-JSON」でサブスクライブします。

cw-evens-sns

運用にあわせて、プロトコル/エンドポイントは変更してください。

プロトコル「Email-JSON」の場合は疎通確認のEmailが届きます。 メールに記載されたリンクをクリックして疎通確認します。

3. AWS CloudWatch Eventsの作成

最後にメインとなる AWS CloudWatch Events を作成します。

管理画面の CloudWatch から Events -> Rules と選択し、ルールの作成画面に遷移します。

イベントのインプットとして

  • 種類は「AWS API call」
  • Service name は「Route 53」

を選択します。

イベントの発火先ターゲットとしてとして

  • 種類は「SNS topic」
  • トピック名は先程作成した「cloudwatch-events-test」
  • Configure Input は「Matched event」

を選択します。

ルールの定義が完了すると、次のようになります。

cw-events-rules

動作確認

それでは、Route 53 の更新系 API を呼び出してみましょう。

AWS マネージメントコンソールから A レコードを変更した時

route53 の管理画面から A レコードを変更します。

変更すると以下のようなメールが通知されます。

cw-events-sns-confirm

Message キーが肝なため、Message キーの値を見やすく加工したのが以下です。

{
  "version": "0",
  "id": "47399003-f31a-49f0-b1a6-a5976673bb0b",
  "detail-type": "AWS API Call via CloudTrail",
  "source": "aws.route53",
  "account": "123456789012",
  "time": "2016-05-21T16:30:51Z",
  "region": "us-east-1",
  "resources": [],
  "detail": {
    "eventVersion": "1.04",
    "userIdentity": {
      "type": "IAMUser",
      "principalId": "DUMMY",
      "arn": "arn:aws:iam::123456789012:user/cm-jane.doe",
      "accountId": "123456789012",
      "accessKeyId": "DUMMY",
      "userName": "cm-jane.doe",
      "sessionContext": {
        "attributes": {
          "mfaAuthenticated": "true",
          "creationDate": "2016-05-21T05:46:38Z"
        }
      },
      "invokedBy": "signin.amazonaws.com"
    },
    "eventTime": "2016-05-21T16:30:51Z",
    "eventSource": "route53.amazonaws.com",
    "eventName": "ChangeResourceRecordSets",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "1.2.3.4",
    "userAgent": "signin.amazonaws.com",
    "requestParameters": {
      "changeBatch": {
        "changes": [
          {
            "action": "CREATE",
            "resourceRecordSet": {
              "type": "A",
              "name": "www.dummy.com.",
              "resourceRecords": [
                {
                  "value": "192.0.2.235"
                }
              ],
              "tTL": 300
            }
          }
        ]
      },
      "hostedZoneId": "Z27S25GZV7IGA9"
    },
    "responseElements": {
      "changeInfo": {
        "submittedAt": "May 21, 2016 4:30:51 PM",
        "status": "PENDING",
        "id": "/change/C2ROIRXW3Y2VIN"
      }
    },
    "additionalEventData": {
      "Note": "Do not use to reconstruct hosted zone"
    },
    "requestID": "61f6368c-1f71-11e6-beec-215485e52783",
    "eventID": "812ced6d-4d54-4ba9-870e-2df73b494648",
    "eventType": "AwsApiCall",
    "apiVersion": "2013-04-01"
  }
}

detail キーの以下のキー

  • "eventSource": "route53.amazonaws.com",
  • "eventName": "ChangeResourceRecordSets",
  • "awsRegion": "us-east-1",

から Route 53 の ChangeResourceRecordSets API が us-east-1 リージョンに向けて呼ばれたことがわかります。

API のリクエストパラメーターは "requestParameters" キーにあります。

    "requestParameters": {
      "changeBatch": {
        "changes": [
          {
            "action": "CREATE",
            "resourceRecordSet": {
              "type": "A",
              "name": "www.dummy.com.",
              "resourceRecords": [
                {
                  "value": "192.0.2.235"
                }
              ],
              "tTL": 300
            }
          }
        ]
      },
      "hostedZoneId": "Z27S25GZV7IGA9"
    },

detail -> userIdentity -> invokedBy が "signin.amazonaws.com" であることから AWS マネージメントコンソール 経由で実行されたこともわかります。

CLI からヘルスチェックを追加した時

{
  "Port": 80,
  "Type": "HTTP",
  "ResourcePath": "/foo",
  "FullyQualifiedDomainName": "www.example.com",
  "RequestInterval": 10,
  "FailureThreshold": 1
}

というような JSON ファイル(test.json)を用意して CLI から Route 53 の API を叩いてみます。

$ aws route53 create-health-check --caller-reference 2014-04-01-18:47 --health-check-config file://test.json
A client error (HealthCheckAlreadyExists) occurred when calling the CreateHealthCheck operation: A different health check has already been created with the specified caller reference.

create-helth-check API はエラーが起きたので実際には更新されませんが、CloudWatch Events のイベントは発火します。

先ほどと同じく、SNS 経由で送信された Email-JSON 形式のメールから重要な Message キーのバリューを見やすく加工したのが以下です。

{
  "version": "0",
  "id": "a6b7cea4-2c4f-4589-b29f-b6396c8c75bd",
  "detail-type": "AWS API Call via CloudTrail",
  "source": "aws.route53",
  "account": "123456789012",
  "time": "2016-05-21T16:44:25Z",
  "region": "us-east-1",
  "resources": [],
  "detail": {
    "eventVersion": "1.04",
    "userIdentity": {
      "type": "IAMUser",
      "principalId": "DUMMY",
      "arn": "arn:aws:iam::123456789012:user/cm-jane.doe",
      "accountId": "123456789012",
      "accessKeyId": "DUMMY",
      "userName": "cm-jane.doe"
    },
    "eventTime": "2016-05-21T16:44:25Z",
    "eventSource": "route53.amazonaws.com",
    "eventName": "CreateHealthCheck",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "1.2.3.4",
    "userAgent": "aws-cli/1.10.32 Python/2.7.11 Darwin/15.4.0 botocore/1.4.22",
    "errorCode": "HealthCheckAlreadyExists",
    "errorMessage": "A different health check has already been created with the specified caller reference.",
    "requestParameters": {
      "healthCheckConfig": {
        "fullyQualifiedDomainName": "www.example.com",
        "failureThreshold": 1,
        "requestInterval": 10,
        "resourcePath": "/foo",
        "port": 80,
        "type": "HTTP"
      },
      "callerReference": "2014-04-01-18:47"
    },
    "responseElements": null,
    "requestID": "47467ad5-1f73-11e6-a791-6756bc02631c",
    "eventID": "5518a3f5-70c8-4a95-8d6f-c6f076179c45",
    "eventType": "AwsApiCall",
    "apiVersion": "2013-04-01"
  }
}

detail -> userAgent が AWS CLI のもの("aws-cli/1.10.32 Python/2.7.11 Darwin/15.4.0 botocore/1.4.22")なので CLI 経由で呼び出されたことがわかります。

detail -> errorCode/errorMessage には AWS サーバーの返したエラーメッセージが含まれています。

  • "errorCode": "HealthCheckAlreadyExists",
  • "errorMessage": "A different health check has already been created with the specified caller reference.",

注意点

CloudWatch Events も万能ではありません。

List/Get/Describe 系のリードオンリーAPIには対応していません。 あくまで更新系 API が呼び出された場合のみイベントが発火されます。

また、更新系 API に利用したリクエストパラメーターはイベントメッセージに含まれますが、リソースが更新前にどういう状態だったかについては、知るすべがありません。

まとめ

今回は CloudWatch Events を使い、API 更新操作時にメール通知する方法を紹介しました。

CloudWatch Events を活用して安心・安定したサービス運用を目指しましょう。

参考リンク