RDSのログをKinesis Firehoseを通してS3に保管する方法

# はじめに
技術検証の備忘として残しました。誰かの役に立てば幸いです。
実現したい内容は以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2986198/531d4a25-d962-2a92-8265-1888a144374c.png)
手順は以下の通りです。
➀ RDSとログ保管用のS3を作成
➁ IAMポリシーとロールを作成
➂ Kinesis Data Firehoseの配信ストリームを作成
➃ 特定のロググループに対し、Kinesis Firehoseサブスクリプションフィルターを作成
➄ S3に保管されたログを確認

# 手順
## ➀RDSとログ保管用のS3を作成
今回はRDBMSにPostgreSQLを使用します。
DB識別子は後の手順で登場するので自分がわかりやすい名前にします。今回は`testdb`としています。
RDSインスタンスを作成する画面の`追加設定`で、CloudWatchLogsエクスポートする画面にチェックを入れます。今回は`PostgreSQLログ`を選択してインスタンスを作成します。`PostgreSQLログ`を選択すると自動でCloudWatchにロググループが作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2986198/847987d9-0dd0-aa08-4e2e-21aa96b0c2aa.png)
S3バケット作成手順は省きますが、S3バケット名以外は全てデフォルト設定で構いません。

## ➁IAMポリシーとロールを作成
`Kinesis Data Firehoseの配信ストリーム`で用いるIAMロール、`Kinesis Firehoseサブスクリプションフィルター`で用いるIAMロールを作成します。

### Kinesis Data Firehoseの配信ストリーム用IAMロール
まず配信ストリーム用のIAMポリシーを作成します。内容は以下の通りです。計12か所の`XXXXXXXXXXXX`はご自身のAWSアカウントの番号に書き換えます。また、計2か所の`YYYYYYYYYYYY`はログ保管用に作成したS3バケット名に書き換えます。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "glue:GetTable",
                "glue:GetTableVersion",
                "glue:GetTableVersions"
            ],
            "Resource": [
                "arn:aws:glue:ap-northeast-1:XXXXXXXXXXXX:catalog",
                "arn:aws:glue:ap-northeast-1:XXXXXXXXXXXX:database/%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%",
                "arn:aws:glue:ap-northeast-1:XXXXXXXXXXXX:table/%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%/%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%"
            ]
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "glue:GetSchemaByDefinition"
            ],
            "Resource": [
                "arn:aws:glue:ap-northeast-1:XXXXXXXXXXXX:registry/*",
                "arn:aws:glue:ap-northeast-1:XXXXXXXXXXXX:schema/*"
            ]
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "glue:GetSchemaVersion"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "s3:AbortMultipartUpload",
                "s3:GetBucketLocation",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:ListBucketMultipartUploads",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::YYYYYYYYYYYY",
                "arn:aws:s3:::YYYYYYYYYYYY/*"
            ]
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "lambda:InvokeFunction",
                "lambda:GetFunctionConfiguration"
            ],
            "Resource": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%"
        },
        {
            "Effect": "Allow",
            "Action": [
                "kms:GenerateDataKey",
                "kms:Decrypt"
            ],
            "Resource":"arn:aws:kms:ap-northeast-1:XXXXXXXXXXXX:key/%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%"
            ,
            "Condition": {
                "StringEquals": {
                    "kms:ViaService": "s3.ap-northeast-1.amazonaws.com"
                },
                "StringLike": {
                    "kms:EncryptionContext:aws:s3:arn": [
                        "arn:aws:s3:::%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%/*",
                        "arn:aws:s3:::%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%"
                    ]
                }
            }
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:ap-northeast-1:XXXXXXXXXXXX:log-group:%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%:log-stream:*"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "kinesis:DescribeStream",
                "kinesis:GetShardIterator",
                "kinesis:GetRecords",
                "kinesis:ListShards"
            ],
            "Resource": "arn:aws:kinesis:ap-northeast-1:XXXXXXXXXXXX:stream/%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%"
        },
        {
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt"
            ],
            "Resource":"arn:aws:kms:ap-northeast-1:XXXXXXXXXXXX:key/%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%",
            "Condition": {
                "StringEquals": {
                    "kms:ViaService": "kinesis.ap-northeast-1.amazonaws.com"
                },
                "StringLike": {
                    "kms:EncryptionContext:aws:kinesis:arn": "arn:aws:kinesis:ap-northeast-1:XXXXXXXXXXXX:stream/%FIREHOSE_POLICY_TEMPLATE_PLACEHOLDER%"
                }
            }
        }
    ]
}
```
ロールの信頼ポリシーは以下のように記載します。
```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "firehose.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
```

### Kinesis Firehoseサブスクリプションフィルター用IAMロール
次にKinesis Firehoseサブスクリプションフィルター用のIAMポリシーを作成します。内容は以下の通りです。`XXXXXXXXXXXX`はご自身のAWSアカウントの番号に書き換えます。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "firehose:PutRecord",
                "firehose:PutRecordBatch"
            ],
            "Resource": [
                "arn:aws:firehose:ap-northeast-1:XXXXXXXXXXXX:deliverystream/*"
            ]
        }
    ]
}
```
ロールの信頼ポリシーは以下のように記載します。
```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.ap-northeast-1.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
```

## ➂Kinesis Data Firehoseの配信ストリームを作成
Kinesisのコンソール画面から`配信ストリームを作成`を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2986198/d3775d01-6942-0623-a155-15bc101d5a41.png)
配信ストリームの値は以下のように設定します。特に記載のないものはデフォルトの値でOKです。
|項目 | 値 |
|:-----------|:------------|
| ソース       | Direct PUT        |
| 送信先     | Amazon S3      |
| 配信ストリーム名       | 自由記入       |
| S3バケット     | 自身が作成したS3バケットを選択      |
| サービスアクセス   | 既存のIAMロールを選択し、上で作成したKinesis Data Firehoseの配信ストリーム用IAMロールを選択  |

設定後は`配信ストリームを作成`を選択します。

## ➃特定のロググループに対し、Kinesis Firehoseサブスクリプションフィルターを作成
Kinesis Firehoseサブスクリプションフィルターを作成します。
CloudWatchのコンソール画面に移動して、左メニューから`ロググループ`を選択します。自身が選択したロググループを選択します。（たとえば作成したDBインスタンス識別子が`testdb`なら`/aws/rds/instance/testdb/postgresql`というロググループが作成されているはずです）
遷移先の画面で`サブスクリプションフィルター`、`作成`、`Kinesis Firehoseサブスクリプションフィルターを作成`を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2986198/d1f226e5-2c8e-6084-567e-5c9792f43db6.png)

Kinesis Firehoseサブスクリプションフィルターで設定する値は以下の通りです。特に記載のないものはデフォルトの値でOKです。
|項目 | 値 |
|:-----------|:------------|
| Destination account      |現在のアカウント      |
| Kinesis Firehose delivery stream  | ➂で作成したKinesis Data Firehoseの配信ストリームを選択|
| 既存のロールを選択     | ➁で作成したFirehoseサブスクリプションフィルター用IAMロールを選択     |
| サブスクリプションフィルター名    | 自由記入    |

設定後は`ストリーミングを開始`を選択します。

## ➄S3に保管されたログを確認
5分ほど時間を置くと、下の画面のようにS3バケットにログが保存されますのでダウンロードして中身を見てみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2986198/af3340c7-a95e-9505-c8b7-2bbfc5d090aa.png)
デフォルトで圧縮されているので展開して中身を見てみると下記のように出力されていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2986198/adb06cd8-2407-7730-cb35-6ad57719ead2.png)
手順は以上です。

# 最後に
RDSのログをKinesis Firehoseを通じてS3に保管する方法とその手順について述べました。振り返ってみると手順自体は結構単純ですね。ここまでお読みいただきありがとうございました。