S3更新時にCloudFrontのInvalidationを実施する・改


SPINFさんの [AWS LambdaでS3更新時にCloudFrontのInvalidationを実施する](http://www.supinf.co.jp/tech/2014/12/05/s3-invalidate/) を東京リージョンで実現する方法です。

Classmethodさんの [異なるリージョンのAWS Lambdaを利用する](http://dev.classmethod.jp/cloud/trigger-lambda-on-other-regions/) を見て、SNSからは任意のリージョンの Lambda が呼べるので、東京リージョンのS3 bucketでも自動的にInvalidationが出来そうだという事でやってみました。

## 通知メッセージの形式

S3のObject Creationイベントを、SNS Notification 経由で Lambda に飛ばしてみると、

```JSON
{
    "Records": [
        {
            "EventSource": "aws:sns",
            "EventVersion": "1.0",
            "EventSubscriptionArn": "arn:aws:sns:ap-northeast-1:000000000000:invalidation:fe80205a-f446-48ac-b536-ab553f8c076f",
            "Sns": {
                "Type": "Notification",
                "MessageId": "d14fcdeb-eb34-5982-9abd-8055cf10fb40",
                "TopicArn": "arn:aws:sns:ap-northeast-1:000000000000:invalidation",
                "Subject": "Amazon S3 Notification",
                "Message": "{\"Records\":[{\"eventVersion\":\"2.0\",\"eventSource\":\"aws:s3\",\"awsRegion\":\"ap-northeast-1\",\"eventTime\":\"2015-05-02T01:01:24.116Z\",\"eventName\":\"ObjectCreated:Put\",\"userIdentity\":{\"principalId\":\"A000000000000\"},\"requestParameters\":{\"sourceIPAddress\":\"1.2.3.4\"},\"responseElements\":{\"x-amz-request-id\":\"83F249C38C9573DC\",\"x-amz-id-2\":\"se8ASGX/20Lpw7LxK191kRxDJeAaXgh29Yugf6LAysthLNa8OFWB+tjEo/B5L6NUHejDJ1kA9TY=\"},\"s3\":{\"s3SchemaVersion\":\"1.0\",\"configurationId\":\"invalidation\",\"bucket\":{\"name\":\"j3tm0t0-test\",\"ownerIdentity\":{\"principalId\":\"A000000000000\"},\"arn\":\"arn:aws:s3:::j3tm0t0-test\"},\"object\":{\"key\":\"dummy\",\"size\":6,\"eTag\":\"f02e326f800ee26f04df7961adbf7c0a\"}}}]}",
                "Timestamp": "2015-05-02T01:01:24.256Z",
                "SignatureVersion": "1",
                "Signature": "XfA0EUOD0sYjwRpkjF36byAJFRrIg0cWeBbb/EyFQbm3MK4JlZFvxbdel6z3H+6b2HVd8TKigkMt2TdWFmXS+q/KdiUgiTKARb8C03VB3VTc/Ihulnrp4/oXsmdaa/Q9Ak1uarQYPsry3EPQQvTqytsVfdg38mriPjCTGxFoAPySXcCAcX8sMPohhq4AnMjIYYVlFpx3MdeXzkvQll4qo1H/ebZf2eYok5CF9K1tBH2r0ZndaK5hEmgm0rtwNeUpGoMixPHw5eq8fHJIUgvpcw8y5bY8p2sRwAGqKxhtIwKSFqHTpSKrmHxZEwFo2WfYzoZz7DHx3982k1u8GEMAVg==",
                "SigningCertUrl": "https://sns.ap-northeast-1.amazonaws.com/SimpleNotificationService-d6d679a1d18e95c2f9ffcf11f4f9e198.pem",
                "UnsubscribeUrl": "https://sns.ap-northeast-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:ap-northeast-1:000000000000:invalidation:fe80205a-f446-48ac-b536-ab553f8c076f",
                "MessageAttributes": {}
            }
        }
    ]
}
```

のような event が実行されます。この中の Records[0].Sns.Message を取り出すと

```JSON
{
    "Records": [
        {
            "eventVersion": "2.0",
            "eventSource": "aws:s3",
            "awsRegion": "ap-northeast-1",
            "eventTime": "2015-05-02T01:01:24.116Z",
            "eventName": "ObjectCreated:Put",
            "userIdentity": {
                "principalId": "A000000000000"
            },
            "requestParameters": {
                "sourceIPAddress": "1.2.3.4"
            },
            "responseElements": {
                "x-amz-request-id": "83F249C38C9573DC",
                "x-amz-id-2": "se8ASGX/20Lpw7LxK191kRxDJeAaXgh29Yugf6LAysthLNa8OFWB+tjEo/B5L6NUHejDJ1kA9TY="
            },
            "s3": {
                "s3SchemaVersion": "1.0",
                "configurationId": "invalidation",
                "bucket": {
                    "name": "j3tm0t0-test",
                    "ownerIdentity": {
                        "principalId": "A000000000000"
                    },
                    "arn": "arn:aws:s3:::j3tm0t0-test"
                },
                "object": {
                    "key": "dummy",
                    "size": 6,
                    "eTag": "f02e326f800ee26f04df7961adbf7c0a"
                }
            }
        }
    ]
}
```
のようなデータになってます。これはS3からダイレクトにLambdaを呼んだ時の構造と同じです。
イベントソースがSNSだった際には、中から取り出して実行してあげれば良さそうですね。

## 実装
[SPINFさんのスクリプト](https://gist.github.com/SUPINF/e66fd36f9228a8701706#file-s3-invalidation-js)の冒頭に下記のようなコードを付け加えます(フルのコードは[こちら](https://gist.github.com/j3tm0t0/fa6b2bf23cbf454d26e8#file-s3-invalidation-js))。

```
  if (event.Records[0].EventSource == "aws:sns")
  {
    if(event.Records[0].Sns.Subject == "Amazon S3 Notification")
    { // overwrite S3 event object from payload
      event=JSON.parse(event.Records[0].Sns.Message);
    }
  }
```

## テスト
東京リージョンのBucketにダミーファイルをアップしてみます。

```
~$ aws s3 cp dummy s3://j3tm0t0-test/
upload: ./dummy to s3://j3tm0t0-test/dummy
```

![screenshot](http://g.s3w.jp/aabbd90c)
Invalidation が実行されました！