0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

CloudWatch LogsのKFHサブスクリプションフィルターを理解する

Last updated at Posted at 2021-02-03

AWSのサービスの中には、CloudWatch Logs(以下CWL)にしかログを吐き出せないものが結構ある。
これはこれで使いではあるが、S3にログを集約したい、といった場合は、Kinesis Data Firehose(以下KFH)を用いたサブスクリプションフィルターを設定する必要があり、結構面倒くさい(しかも、Kinesis系のサブスクリプションフィルターだけマネジメントコンソールから設定出来なかったりする)。

面倒くさいステップが少しでも腹落ちするよう、トンネル開通に例えて、一連の方法をまとめておく。
(手順自体は公式に準ずる)。

イメージ

人 --> 入り口 --> ( === トンネル === ) --> 出口

こういうイメージで、

ログレコード --> CWLサブスクリプションフィルター --> ( === KFH === ) --> S3

これを作ります。

ステップバイステップ

1. 入り口と出口を作る

  • 何でもいいのでCWLロググループを一つ選ぶ。

これがトンネルの入り口となる。
量を試したければVPC Flow Logsが使いやすい。
ここでは、ABC順で最初に目に付いたGlueのジョブアウトプット(/aws-glue/jobs/output)を使うことにする。

  • 最終目的地用のS3バケットを作成する。
    これがトンネルの出口となる。
% aws s3api create-bucket --bucket kfhtest2021 --create-bucket-configuration LocationConstraint=ap-northeast-1
{
    "Location": "http://kfhtest2021.s3.amazonaws.com/"
}

2. 施工許可証を作る

  • KFHストリーム用のIAMロールを作成する。

これがトンネルを作るためのいわば施工許可証になる。
マネジメントコンソールだとKFHストリーム作成時に自動作成してくれるが、IAMロール・信頼関係・IAMポリシーの相互関係を改めて整理するのに意外にちょうどよかったので、あえて公式通りCLI方式で書いておく。

まずはKFHがこのロールをAssumeRoleするための信頼関係をJSONファイルで用意する。

~/trust-kfh.json
{
  "Statement": {
    "Effect": "Allow",
    "Principal": { "Service": "firehose.amazonaws.com" },
    "Action": "sts:AssumeRole",
    "Condition": { "StringEquals": { "sts:ExternalId":"AWSアカウントID" } }
  }
}

次にKFHに何の権限が許可されるかを記述したIAMポリシーを同じくJSONファイルで用意する(バケット名はここではkfhtest2021)。余談だが、このIAMポリシーは後続のIAMロール専用の、いわゆるインラインポリシーという位置づけになる。

~/policy-kfh.json
{
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [ 
          "s3:AbortMultipartUpload", 
          "s3:GetBucketLocation", 
          "s3:GetObject", 
          "s3:ListBucket", 
          "s3:ListBucketMultipartUploads", 
          "s3:PutObject" ],
      "Resource": [ 
          "arn:aws:s3:::kfhtest2021", 
          "arn:aws:s3:::kfhtest2021/*" ]
    }
  ]
}

IAMロールを作る。信頼関係はこの時紐付ける。

% aws iam create-role \
    --role-name FirehosetoS3Role \
    --assume-role-policy-document file://~/trust.json
結果
{
    "Role": {
        "Path": "/",
        "RoleName": "FirehosetoS3Role",
        "RoleId": "AROAQH2ZXUWM2YY5UEUHI",
        "Arn": "arn:aws:iam::AWSアカウントID:role/FirehosetoS3Role",
        "CreateDate": "2021-02-03T12:25:39+00:00",
        "AssumeRolePolicyDocument": {
            "Statement": {
                "Effect": "Allow",
                "Principal": {
                    "Service": "firehose.amazonaws.com"
                },
                "Action": "sts:AssumeRole",
                "Condition": {
                    "StringEquals": {
                        "sts:ExternalId": "AWSアカウントID"
                    }
                }
            }
        }
    }
}

作ったIAMロールIAMポリシーを紐付けて完成。

% aws iam put-role-policy --role-name FirehosetoS3Role \
    --policy-name Permissions-Policy-For-Firehose \
    --policy-document file://~/policy-kfh.json

これで、「何ができるか(IAMポリシー)」を表面に、「誰がこの権限を使うことができるか(信頼関係)」を裏面に書いた、"施工許可証"であるところのIAMロールができた。
この後作るKFHストリームにこの施工許可証を渡してやれば、KFHストリームは表面に書かれた権限でもって、出口であるS3バケットに向かって堂々と掘り抜けることができることになる(許可証の利用許可は裏面に書いてある)。

3. トンネルを掘る

  • CWLとS3の間を繋ぐ、KFHストリームを作成する。

これが実際にログストリームが通過するトンネルになる。
一点注意点は、KFHの圧縮オプションを無効にすること。CWLはそれ自身がGZIP圧縮するので、二重に圧縮がかかってしまい後で使う時に無駄に悩む羽目になる。まあ、デフォルトは「圧縮なし」なので、以下の通りやれば特に問題はない。

% aws firehose create-delivery-stream \
    --delivery-stream-name 'my-delivery-stream' \
    --s3-destination-configuration \
    '{"RoleARN": "arn:aws:iam::AWSアカウントID:role/FirehosetoS3Role", "BucketARN": "arn:aws:s3:::kfhtest2021"}'
結果
{
    "DeliveryStreamARN": "arn:aws:firehose:ap-northeast-1:AWSアカウントID:deliverystream/my-delivery-stream"
}

ここまででトンネルは完成。出口にも繋がっている。
最後に、"トンネル利用許可証"を用意した上で、入口を開通させる作業が残っている。

4. トンネル利用許可証を作る

  • CWLがKFHを使うためのIAMロールを作成する。

先程作った建築許可証はKFHストリームがS3という"出口"に掘り抜けるためのものだが、今回作るのは入り口であるCWLロググループがKFHストリームという"トンネル"を使っていいよという、いわばトンネル利用許可証である。

やることはほぼ同じ。
まずは信頼関係

trust-cwl.json
{
  "Statement": {
    "Effect": "Allow",
    "Principal": { "Service": "logs.ap-northeast-1.amazonaws.com" },
    "Action": "sts:AssumeRole"
  }
}

次いでIAMポリシー

policy-cwl.json
{
    "Statement":[
      {
        "Effect":"Allow",
        "Action":["firehose:*"],
        "Resource":["arn:aws:firehose:ap-northeast-1:AWSアカウントID:*"]
      }
    ]
}

IAMロール作成。

% aws iam create-role \
    --role-name CWLtoKinesisFirehoseRole \
    --assume-role-policy-document file://~/trust-cwl.json
結果
{
    "Role": {
        "Path": "/",
        "RoleName": "CWLtoKinesisFirehoseRole",
        "RoleId": "AROAQH2ZXUWM6SCQSYNSV",
        "Arn": "arn:aws:iam::AWSアカウントID:role/CWLtoKinesisFirehoseRole",
        "CreateDate": "2021-02-03T13:29:15+00:00",
        "AssumeRolePolicyDocument": {
            "Statement": {
                "Effect": "Allow",
                "Principal": {
                    "Service": "logs.ap-northeast-1.amazonaws.com"
                },
                "Action": "sts:AssumeRole"
            }
        }
    }
}

最後にIAMロールIAMポリシーを紐付けて完成。

% aws iam put-role-policy --role-name CWLtoKinesisFirehoseRole \
    --policy-name Permissions-Policy-For-CWL \
    --policy-document file://~/policy-cwl.json

利用許可証ができ、CWLがトンネルであるところのKFHストリームに接続する準備ができた。

5. 入り口とトンネルを繋ぐ

  • 準備したKFHストリームを指定して、CWLロググループのサブスクリプションフィルターを作成する。

これで、入り口 -> トンネル -> 出口が繋がり、ログがS3バケットに出力され始める。

まず、先程作ったトンネル(KFHストリーム)の識別名であるところのARNを取得する。

% aws firehose describe-delivery-stream --delivery-stream-name "my-delivery-stream" --query 'DeliveryStreamDescription.DeliveryStreamARN'
結果
"arn:aws:firehose:ap-northeast-1:AWSアカウントID:deliverystream/my-delivery-stream"

トンネル利用許可証(IAMロール)の識別名であるARNも取得。

% aws iam get-role --role-name CWLtoKinesisFirehoseRole --query 'Role.Arn'
結果
"arn:aws:iam::AWSアカウントID:role/CWLtoKinesisFirehoseRole"

最後に、これらの情報をかき集めてサブスクリプションフィルターを作る。
フィルターパターンはログによりまちまちだが、ここでは全件出力するので""で指定。

% aws logs put-subscription-filter \
    --log-group-name "/aws-glue/jobs/output" \
    --filter-name "Destination" \
    --filter-pattern "" \
    --destination-arn "arn:aws:firehose:ap-northeast-1:AWSアカウントID:deliverystream/my-delivery-stream" \
    --role-arn "arn:aws:iam::AWSアカウントID:role/CWLtoKinesisFirehoseRole"

ようやく、目指すサブスクリプションフィルターが作成された。

スクリーンショット 2021-02-03 午後10.59.31.png

6. 動確

  • あとはログを出力させ、S3に吐き出されることを確認するだけ。

今回はGlueジョブのOutputログなので、Output出力の設定をしたジョブを適当に走らせてみる。

% aws glue start-job-run --job-name job_orcl2s3

待つことしばし。
KFHストリーム経由でS3バケットにログ出力されたことが分かる。
スクリーンショット 2021-02-03 午後11.25.15.png

せっかくなので、S3 Selectでクエリーしてみる。
CWLのログはJSONフォーマット、GZIP圧縮なので、以下の通り指定する。

大項目 小項目
入力設定 形式 JSON
圧縮 GZIP
出力設定 形式 JSON

スクリーンショット 2021-02-03 午後11.37.31.png

...複数行が結合されているように見えるが、いったんそれは措くとして、とりあえず"トンネル"は無事開通したようだ。

余談

2020年のアップデートで、これまで1つだった、ロググループあたりのサブスクリプションフィルター数が「2」に増えた。
KFH経由でS3に送りつつ、Elasticsearch Serviceにも送る、みたいなことが、fluentdのようなログルーターを介さずともCWL単体でできるようになったことになる。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?