CloudWatch EventsでS3への特定オブジェクトのアップロードを検知する

S3への特定オブジェクトのアップロードをトリガーに、CloudWatch Eventsを起動するやり方の備忘録を残します。


はじめに

f:id:BioErrorLog:20201017193156p:plain
S3への特定オブジェクトのアップロードをトリガーに、CloudWatch Eventsを起動する
S3への特定オブジェクトのアップロードをトリガーにCloudWatch Eventsを起動するやり方について、細かいところで理解が曖昧なところがありました。

今回はこの手順について、ステップ毎に細かく確認していきます。


CloudWatch Eventsのイベントソースを調べる

まず、CloudWatch Eventsがサポートしているイベントソースを、ドキュメントから調べます。

CloudWatch Events Event Examples From Supported Services - Amazon CloudWatch Events

これを見るに、S3イベントはCloudWatch Eventsの直接的なイベントソースとしてサポートされていません。 よって、CloudTrailを介したCloudWatch Eventsルールを作成することになります。

Events Delivered Via CloudTrail - Amazon CloudWatch Events

また、S3側の設定としてeventを通知する仕組みも用意されていますが、ここでサポートされているevent通知先はSNS/SQS/Lambdaの3つであり、CloudWatch Eventsは直接のサポートはありません。

Configuring Amazon S3 event notifications - Amazon Simple Storage Service


以上から、S3トリガーでCloudWatch Eventsを起動するには、CloudTrailを介したやり方がふさわしそうです。


S3トリガーで起動するCloudWatch Eventsを作成する

それでは、S3トリガーで起動するCloudWatch Eventsを作成していきます。 手順としては、CodePipelineのドキュメントに記載されていたものを参考にします。

Create a CloudWatch Events rule for an Amazon S3 source (console) - AWS CodePipeline


CloudTrail証跡を作成する

CloudTrailを経由してCloudWatch Eventsを起動する流れになるので、CloudTrailのTrail (証跡)を作成していない場合は以下の手順で作成します。

  1. AWS CloudTrail コンソールを開きます。
  2. ナビゲーションペインで、[Trails] を選択します。
  3. [Create Trail (証跡の作成)] を選択します。[Trail name] に、証跡の名前を入力します。
  4. [Apply trail to all regions (すべてのリージョンで証跡を適用)] では [No] を選択します。
  5. [Data events (データイベント)] で [S3] が選択されていることを確認します。フォルダ内のすべてのオブジェクトのデータイベントをログ記録するために、Amazon S3 バケットおよびオブジェクトプレフィックス (フォルダ名) を指定します。証跡ごとに、最大 250 個の Amazon S3 オブジェクトを追加できます。
  6. [Read/Write events (読み取り/書き込みイベント)] で [なし] を選択します。
  7. [Write (書き込み)] を選択します。証跡では、指定したバケットとプレフィックスの Amazon S3 オブジェクトレベルの API アクティビティ (GetObject や PutObject など) が記録されます。
  8. [保存場所] でログファイルを保存するために使用するバケットを作成あるいは指定します。デフォルトでは、Amazon S3 バケットとオブジェクトはプライベートです。リソース所有者 (バケットを作成した AWS アカウント) のみが、バケットとそのオブジェクトにアクセスできます。バケットには、バケット内のオブジェクトにアクセスできる AWS CloudTrail 権限を付与するリソースポリシーがある必要があります。
  9. 証跡が適切であることを確認したら、[作成] を選択します。

これで下準備はOKです。


CloudWatch Eventsルールを作成する

次はCloudWatch Eventsを作成します。

CloudWatchコンソールのサイドバーから イベント>ルール を開き、ルールの作成 をクリックし、CloudWatch Eventsルールを作成します。

今回は以下のようにして、S3バケットcloudwatch-events-trigger-testに対するPutObjectを検知するようにしました。

f:id:BioErrorLog:20201017175155p:plain
特定のS3バケットへのPutObjectを検知するように設定する

しかしこれだけでは、CloudWatch Eventsのトリガー元をS3バケットに絞ることが出来ても、オブジェクトレベルでは絞れていません。 オブジェクトレベルで絞るには、イベントパターンを編集する必要があります。

以下のように、イベントパターンのrequestParameterskeyを追加して指定することで、オブジェクトを指定することが出来ます。

{
  "source": [
    "aws.s3"
  ],
  "detail-type": [
    "AWS API Call via CloudTrail"
  ],
  "detail": {
    "eventSource": [
      "s3.amazonaws.com"
    ],
    "eventName": [
      "PutObject"
    ],
    "requestParameters": {
      "bucketName": [
        "cloudwatch-events-trigger-test"
      ],
      "key": [
        "target/object"
      ]
    }
  }
}

上の例では、S3バケットcloudwatch-events-trigger-testに、オブジェクトtarget/objectPutObjectされたときに、このCloudWatch Eventsが起動することになります。

ここまでイベントソースを指定したら、今度はCloudWatch Eventsのターゲットを指定します。 今回は検証としてCloudWatch Evetnsが起動したことが分かればよいので、CloudWatch ロググループをターゲットとして指定しました。

CloudWatch Eventsルールの作成は以上です。


CloudWatch Eventsの動作確認

それでは、S3に該当オブジェクトをアップロードして、CloudWatch Eventsが起動されることを確認します。 今回は、ターゲットとしたCloudWatchロググループを確認して、CloudWatch Eventsが起動されたかどうかを見ました。

まず、S3バケットcloudwatch-events-trigger-testに、オブジェクトtarget/objectをアップロードします。 CloudWatch Eventsが1回起動されることが予想されます。

f:id:BioErrorLog:20201017185210p:plain
S3バケット`cloudwatch-events-trigger-test`に、オブジェクト`target/object`をアップロード

想定通り、CloudWatch Eventsが起動されました。


つぎは、S3バケットcloudwatch-events-trigger-testに、オブジェクトtarget/object-dummyをアップロードします。 CloudWatch Eventsが起動されない(= ログは1つのまま)ことが予想されます。

f:id:BioErrorLog:20201017185420p:plain
S3バケット`cloudwatch-events-trigger-test`に、オブジェクト`target/object-dummy`をアップロード

想定通り、CloudWatch Eventsは起動されませんでした。

以上、S3への特定オブジェクトのアップロードをトリガーに、CloudWatch Eventsを起動する方法を見ました。


補足: ワイルドカードの使用

補足として、オブジェクト名の指定にワイルドカードが使用できるのか、を調べました。

CloudWatch Eventsルールの定義としてkeyの値にワイルドカードを使用し、特定パス下にオブジェクトが配置された際にCloudWatch Eventsを起動することが出来るか、が気になったためです。

CloudWatch Eventsルールのイベントパターンを編集し、keyの値をtarget/*とします。

{
  "source": [
    "aws.s3"
  ],
  "detail-type": [
    "AWS API Call via CloudTrail"
  ],
  "detail": {
    "eventSource": [
      "s3.amazonaws.com"
    ],
    "eventName": [
      "PutObject"
    ],
    "requestParameters": {
      "bucketName": [
        "cloudwatch-events-trigger-test"
      ],
      "key": [
        "target/*"
      ]
    }
  }
}

これで、target/パス下に任意のオブジェクトが配置されたときにCloudWatch Eventsが呼び出されるか、を調べました。

結果、CloudWatch Eventsは呼び出されませんでした。

keyの値にワイルドカードを使用することは、今のところはできないようです。

ドキュメントをあたってみても、登録されていないフィールドには "": "" ワイルドカードが補完される、という記述はあるものの、値の指定にワイルドカードを使用することについては記載が見当たりませんでした。

Event Patterns in CloudWatch Events - Amazon CloudWatch Events


おわりに

今回は、CloudWatch EventsでS3への特定オブジェクトのアップロードを検知する方法を書きました。

CloudWatch Eventsの特性上、できるんだろうなとは思っていました。 が、いざ手を動かしてやってみると、CloudTrail証跡を介在して起動していたり、ワイルドカードが使用できなかったりと、意外と理解の抜けていた部分が判明しました。

なお、最近ではCloudWatch EventsよりもEventBridgeの使用が推奨されている雰囲気を感じます。 いずれはEventBridgeの理解も深めていきたいと思っています。


関連記事

Biogenの事例から、AWSマルチアカウントにおけるログ集約のアーキテクチャを学びました。 www.bioerrorlog.work

NextGenの事例から、高い制御の求められるデプロイパイプラインのアーキテクチャを学びました。 www.bioerrorlog.work


参考

What Is Amazon CloudWatch? - Amazon CloudWatch

CloudWatch Events Event Examples From Supported Services - Amazon CloudWatch Events

Configuring Amazon S3 event notifications - Amazon Simple Storage Service

Event Patterns in CloudWatch Events - Amazon CloudWatch Events