＜初心者向け＞CloudWatch LogsのログをKinesis Data Streams経由でLambdaに連携　チュートリアル①

# はじめに
この記事はAWSを勉強し始めた人を対象としたものです。
私自身は、IT未経験で今の会社に入社し、丁度1年が経とうとしています。
AWSは数ヶ月勉強しており、現在は『AWS 認定 デベロッパー - アソシエイト』の取得を目指しています。
# 前提知識
・[Amazon CloudWatch Logs](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html)
・[ロググループ](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/CloudWatchLogsConcepts.html)
・[サブスクリプションフィルタ](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/CreateSubscriptionFilter.html)
・[Amazon Kinesis Data Streams](https://docs.aws.amazon.com/ja_jp/streams/latest/dev/introduction.html)
・[AWS Lambda](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/welcome.html)
・[AWS Lambda イベントソースマッピング](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/invocation-eventsourcemapping.html)
# 実現したい構成
・サブスクリプションフィルタを使用して、CloudWatch LogsのログをKinesis Data Streamsに配信
・イベントソースマッピングでKinesis Data StreamsとLambdaを連携し、Kinesis Data Streams（イベントソース）からLambda関数を呼び出す

構成図は以下の通りです。
![CloudWatch LogsとLambdaの連携.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604686/8a08b40d-2cfe-14ea-4c98-62d0290337c9.png)
# 手順
以下のコマンドをEC2上で実行します。
※サーバにはコマンドによってサービスを操作するためのIAM権限が必要になります。
今回はIAM Roleで以下のポリシーをアタッチしています。
- AWSLambdaFullAccess
- CloudWatchFullAccess
- AmazonKinesisFullAccess
- CloudWatchLogsFullAccess

#### ①Kinesis Data Streams作成（※シャード数はデフォルト1を使用）
```
$ aws kinesis create-stream --stream-name ＜ストリーム名＞ --shard-count ＜シャード数＞
```
#### ②IAM Role作成（CloudWatch Logsに対しての一時的な権限付与を許可するための設定）
```
$ aws iam create-role --role-name ＜CloudWatch Logs用のIAM Role名＞ --assume-role-policy-document file://＜IAM Role定義ファイルパス＞
```
※IAM Role定義ファイルを事前に作成する必要があります。以下はサンプルです。

```
{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "logs.ap-northeast-1.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```
#### ③IAM Policy作成（①で作成したKinesis Data Streamsにデータを書き込むこと、②で作成したIAM Roleの付与対象をCloudWatchに制限することを許可するための設定）
```
$ aws iam create-policy --policy-name ＜②で作成したIAM RoleにアタッチするIAM Policy名＞ --policy-document file://<IAM Policy定義ファイルパス>
```
※IAM Policy定義ファイルを事前に作成する必要があります。以下はサンプルです。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "kinesis:PutRecord",
            "Resource": "＜①で作成したKinesis Data Streams ARN＞"
        },
        {
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": "＜②で作成したIAM Role ARN＞"
        }
    ]
}
```
※①で作成したKinesis Data Streams ARN 確認コマンド

```
aws kinesis describe-stream --stream-name ＜①で作成したストリーム名＞
```
※②で作成したIAM Role ARN 確認コマンド

```
aws iam get-role --role-name ＜②で作成したIAM Role名＞
```
#### ④IAM PolicyをIAM Roleにアタッチ
```
$ aws iam attach-role-policy  --role-name ＜②で作成したIAM Role名＞  --policy-arn ＜③で作成したIAM Policy ARN＞
```
※③で作成したIAM Policy ARN 確認コマンド

```
aws iam list-policies  | grep ＜③で作成したIAM Policy名＞
```
#### ⑤サブスクリプションフィルタ設定
```
$ aws logs put-subscription-filter --log-group-name ＜連携させたいロググループ名＞ --filter-name ＜フィルタ名＞ --filter-pattern 
＜フィルタパターン＞ --destination-arn ＜①で作成したKinesis Data Streams ARN＞ --role-arn ＜②で作成したIAM Role ARN＞
```
#### ⑥IAM Role作成（Lambdaに対しての一時的な権限付与を許可するための設定）
```
$ aws iam create-role --role-name ＜Lambda用のIAM Role名＞ --assume-role-policy-document file://＜IAM Role定義ファイルパス＞
```
※IAM Role定義ファイルを事前に作成する必要があります。以下はサンプルです。

```
{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```
#### ⑦1つ目のIAM Policy作成（LambdaからKinesisへのポーリングを許可するための設定）
```
$ aws iam create-policy --policy-name ＜⑥で作成したIAM RoleにアタッチするIAM Policy名＞ --policy-document file://<IAM Policy定義ファイルパス>
```
※IAM Policy定義ファイルを事前に作成する必要があります。以下はサンプルです。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "kinesis:DescribeStream",
                "kinesis:DescribeStreamSummary",
                "kinesis:GetRecords",
                "kinesis:GetShardIterator",
                "kinesis:ListShards",
                "kinesis:ListStreams",
                "kinesis:SubscribeToShard",
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        }
    ]
}
```
#### ⑧2つ目のIAM Policy作成（Lambda 関数の呼び出しを許可するための設定）
```
$ aws iam create-policy --policy-name ＜⑥で作成したIAM RoleにアタッチするIAM Policy名＞ --policy-document file://<IAM Policy定義ファイルパス>
```
※IAM Policy定義ファイルを事前に作成する必要があります。以下はサンプルです。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "lambda:InvokeFunction",
            "Resource": "*"
        }
    ]
}
```
#### ⑨3つ目のIAM Policy作成（Lambda自身がENIを作成/削除することを許可するための設定）
```
$ aws iam create-policy --policy-name ＜⑥で作成したIAM RoleにアタッチするIAM Policy名＞ --policy-document file://<IAM Policy定義ファイルパス>
```
※IAM Policy定義ファイルを事前に作成する必要があります。以下はサンプルです。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ec2:CreateNetworkInterface",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DeleteNetworkInterface"
            ],
            "Resource": "*"
        }
    ]
}
```
#### ⑩1つ目のIAM Policy（⑦で作成）をIAM Roleにアタッチ
```
$ aws iam attach-role-policy  --role-name ＜⑥で作成したIAM Role名＞  --policy-arn ＜⑦で作成したIAM Policy ARN＞
```
※⑦で作成したIAM Policy ARN 確認コマンド

```
aws iam list-policies  | grep ＜⑦で作成したIAM Policy名＞
```
#### ⑪2つ目のIAM Policy（⑧で作成）をIAM Roleにアタッチ
```
$ aws iam attach-role-policy  --role-name ＜⑥で作成したIAM Role名＞  --policy-arn ＜⑧で作成したIAM Policy ARN＞
```
※⑧で作成したIAM Policy ARN 確認コマンド

```
aws iam list-policies  | grep ＜⑧で作成したIAM Policy名＞
```
#### ⑫3つ目のIAM Policy（⑨で作成）をIAM Roleにアタッチ
```
$ aws iam attach-role-policy  --role-name ＜⑥で作成したIAM Role名＞  --policy-arn ＜⑨で作成したIAM Policy ARN＞
```
※⑨で作成したIAM Policy ARN 確認コマンド

```
aws iam list-policies  | grep ＜⑨で作成したIAM Policy名＞
```
#### ⑬Lambda関数作成（※VPCに所属させている）
```
$ aws lambda create-function --function-name ＜ログの連携先となるLambda 関数名＞ --runtime ＜ランタイム＞ --role ＜⑥で作成したIAM Role ARN＞ --handler ＜handler名＞ --timeout ＜タイムアウト値＞ --memory-size ＜メモリサイズ＞ --no-publish --vpc-config SubnetIds=＜サブネットID＞,SecurityGroupIds=＜セキュリティグループID＞ --zip-file ＜アップロードするコードのzipファイルへのパス＞
```
※⑥で作成したIAM Role ARN 確認コマンド

```
aws iam get-role --role-name ＜⑥で作成したIAM Role名＞
```
#### ⑭イベントソースマッピング作成
```
$ aws lambda create-event-source-mapping --function-name ＜⑬で作成したLambda 関数名＞ --event-source  ＜①で作成したKinesis Data Streams ARN＞ --batch-size ＜バッチサイズ＞ --starting-position ＜読み取りを開始するストリーム内の位置＞
```
※①で作成したKinesis Data Streams ARN 確認コマンド

```
aws kinesis describe-stream --stream-name ＜①で作成したストリーム名＞
```
# ポイント
今回の作業を実施する上でのポイントを4つ挙げました。参考程度に読んでいただければと思います。
・特に記載はしませんでしたが、明記したコマンド（リソースの作成、確認）以外にも、不要なリソースを削除するコマンドを使用しました。実施したい作業を、どのAWS CLIコマンドで実現できるのか調べることで、自然とAWS CLIコマンドについて学べます。
・大体は「describe」、「get」、「list」の3つが結果を表示するコマンドだと思います。例えば、Kinesis Data Streamsの内容（設定）を確認するコマンドは、AWS CLIで「aws kinesis describe-stream --streams-name ＜ストリーム名＞」であるのですが、もしコマンドが分からないのであれば、「get stream aws cli」や、「list stream aws cli」などの文字列で検索してみるとよいです。
・サブスクリプションフィルタとイベントソースマッピングの役割を理解することがポイントだと思います。それぞれの役割を理解してください。
・ポリシードキュメント（IAM Role定義ファイル、IAM Policy定義ファイル）では "Action" が定義されています。リソースに対して許可（拒否）する操作をActionに定義するのですが、その "Action" の内容を理解することだけでも、大分勉強になると思います。
# あとがき
今回はLambdaの中身までは説明しておりませんでした。

実はLogsから直接Lambdaと連携することもできます。
ただ、まれにLambdaが起動しない場合があるようで、Kinesisを挟むことで信頼性を向上したい意図です。
※CloudWatch Logsのログを確実に後続サービスで処理したい場合に有効な構成だと思っています。

次回、Lambdaで処理をする部分について説明させていただければと思っています。