Amazon-Kinesis-Data-Firehose

Amazon Kinesis Data FirehoseでApacheのアクセスログをJSON形式でS3にアップロードしてみた

はじめに

こんにちは、omkです。

今回はApacheのアクセスログをKinesisエージェントを用いて「Kinesis Data Firehose」経由でS3にアップロードします。
その際にcombined形式のログをKinesisエージェント側でJSONに変換してアップします。
配信前にLambdaでJSON化する方法もあるのですが、こっちの方が簡単なのでエージェントで整形していきます。

Kinesis Data Firehoseの配信ストリームの作成

AWSにサインイン後、Kinesisコンソールを開きます。
画面左のナビゲーションペインから配信ストリームを選択し、配信ストリームを作成します。

適当に名前を設定します。
「Source」には「Direct PUT or other sources」を選択します。Kinesisエージェントで直接ストリームにログを投げるためこの設定となります。
「Destination」はS3を選択します。S3バケットは事前に用意しておくかこの場で作成できます。

あとの設定はそのままで配信ストリームを作成します。

Kinesisエージェントのインストール

次にログを配信したいWEBサーバにKinesisエージェントを入れます。
各OSでのインストール方法は公式ページを参照。
(「Data Streams」と「Data Firehose」は共通のエージェントを使用します)

今回はAmazon Linux2を前提に実施します。

sudo yum install –y aws-kinesis-agent

エージェントがインストールされました。

エージェントの設定

続いてエージェントの設定を行います。
設定方法はこちらを参照。

Kinesisエージェントを用いることで配信前にログを成形することが出来ます。
https://docs.aws.amazon.com/ja_jp/firehose/latest/dev/writing-with-agents.html#pre-processing

自分でパターンを作成したカスタム形式を利用することも可能ですが、公式にサポートされた形式はフォーマットを指定することで自動で変換してくれます。

今回は「LOGTOJSON」オプションを使用してログをJSONに変換します。
「LOGTOJSON」オプションでサポートされているログ形式は「Apache Common Log」「Apache Combined Log」「Apache Error Log」「RFC3164 Syslog」形式です。
このうちの「Apache Combined Log」形式のAccess_logを対象とします。

まずapacheのアクセスログがCombined形式であることを確認します。

$ grep "access_log" /etc/httpd/conf/httpd.conf

# with "/", the value of ServerRoot is prepended -- so 'log/access_log'
# server as '/www/log/access_log', where as '/log/access_log' will be
# interpreted as '/log/access_log'.
    #CustomLog "logs/access_log" common
    CustomLog "logs/access_log" combined

次にエージェント設定の編集を行います。
$ sudo vi /etc/aws-kinesis/agent.json

初期の状態では以下のようになっていると思います。

{
  "cloudwatch.emitMetrics": true,
  "kinesis.endpoint": "",
  "firehose.endpoint": "",

  "flows": [
    {
      "filePattern": "/tmp/app.log*",
      "kinesisStream": "yourkinesisstream",
      "partitionKeyOption": "RANDOM"
    },
    {
      "filePattern": "/tmp/app.log*",
      "deliveryStream": "yourdeliverystream"
    }
  ]
}

各項目の内容はこちらを参照ください。

ApacheのCombined形式のAccess_logをJSONに変換してData Stream にアップする設定は以下のようになります。

{
  "cloudwatch.emitMetrics": false,
  "firehose.endpoint": "https://firehose.ap-northeast-1.amazonaws.com",

  "flows": [
    {
      "filePattern": "/var/log/httpd/access_log",
      "deliveryStream": "**********",
      "dataProcessingOptions": [
        {
           "optionName": "LOGTOJSON",
           "logFormat": "COMBINEDAPACHELOG"
        }
      ]
    }
  ]
}

cloudwatch.emitMetricsはエージェントがCloudWatchにメトリクスを発行するかどうかの設定です。今回は試しにやってみるだけなのでfalseに設定します。
kinesis.endpointは「Kinesis Data Streams」のエンドポイントです。今回は「Kinesis Data Firehose」を利用するのでこの設定は消し、その下にある「firehose.endpoint」に「 https://firehose.{先ほどの配信ストリームを作成したリージョン(例:ap-northeast-1)}.amazonaws.com 」を設定します。

「flows」では配信するファイルの指定や配信先のストリームを指定します。
デフォルトで設定されている2つのフローのうち、上のフローは「Kinesis Data Streams」用のフローなので消します。

「filePattern」では配信するファイルを指定します。今回はApacheのアクセスログ(標準設定のまま)なので「/var/log/httpd/access_log」を指定します。
「deliveryStream」には先ほど作成した配信ストリームの名前を入力します。

次に配信前にJSON形式に変換する設定を入れます。
「deliveryStream」の下に以下を追記しています。

"dataProcessingOptions": [
        {
           "optionName": "LOGTOJSON",
           "logFormat": "COMBINEDAPACHELOG"
        }
]

「dataProcessingOptions」が事前にレコードを処理する設定です。
ApacheのCombined形式からJSONに変換するので、「LOGTOJSON」オプションを指定して元のフォーマットを「COMBINEDAPACHELOG」で指定します。

以上が内容の説明となります。

これで設定は完了ですので保存してエディタを閉じます。

IAMロールの設定

先ほどのエージェント設定にシークレットキーなどを入力してエージェントを動かすことも可能ですが、IAMロールで権限を設定する方がよりセキュアとされます。
今回はKinesisFullAccessのIAMポリシーからロールを作成しますが、本来は最適な権限に絞って設定することが望まれます。

IAMコンソールから「ロールの作成」を選択し、ユースケースを「EC2」、ポリシーに「AmazonKinesisFullAccess」を設定します。任意の名前を付けてロールを作成します。

次に作成したIAMロールをEC2に設定します。
EC2コンソールで対象を選択し、アクション>セキュリティ>IAMロールを変更、で先程のロールを付けます。

ちなみに配信ストリームのIAMロールに関してはストリーム作成時に良い感じに作成されています。

サービスの起動

Kinesisエージェントの操作はこちらを参照します。

Amazon Linux2ではsystemctlも使用できます。

サービスの起動

$ sudo systemctl start aws-kinesis-agent

サービスの状態確認

$ sudo systemctl status aws-kinesis-agent

エージェントの実行ログは
/var/log/aws-kinesis-agent/aws-kinesis-agent.log
に表示されます。
設定ミスで正常に動作しない場合などもこちらで確認できます。

WEBからアクセスしてみてApacheにアクセスログを吐かせましょう。

以下のように表示されているとログを取得して正常にストリームへ配信されています。
*** records sent successfully to destinations.

良くあるミスとしてエージェント設定の文法が間違っている、ログの読み込み権限がない、AWSサービスへの権限がないなどが挙げられます。

S3バケットを確認

正常に配信されている場合、配信ストリームで指定したS3にログが保存されています。
デフォルトでは5分か5MBに達するまでバッファされ、まとまったかたちでS3にアップされます。

しばらく待ってみた上でS3のバケットを確認してみましょう。

ログがJSON形式になって出力されていました。

{"host":"***.***.***.***","ident":null,"authuser":null,"datetime":"15/Feb/2021:08:05:59 +0000","request":"GET / HTTP/1.1","response":"403","bytes":"3630","referer":null,"agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36"}
{"host":"***.***.***.***","ident":null,"authuser":null,"datetime":"15/Feb/2021:08:05:59 +0000","request":"GET / HTTP/1.1","response":"403","bytes":"3630","referer":null,"agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36"}
{"host":"***.***.***.***","ident":null,"authuser":null,"datetime":"15/Feb/2021:08:05:59 +0000","request":"GET / HTTP/1.1","response":"403","bytes":"3630","referer":null,"agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36"}
{"host":"***.***.***.***","ident":null,"authuser":null,"datetime":"15/Feb/2021:08:05:59 +0000","request":"GET / HTTP/1.1","response":"403","bytes":"3630","referer":null,"agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36"}

まとめ

これでApacheのログを「Kinesis Data Firehose」を用いてJSON形式でS3にアップすることが出来ました。
特に整形部分はややこしい設定もなくスムーズにCombined形式のログをJSON形式に変換することが出来ました。
Lambdaで整形する場合もApacheに限らずSyslogなども色々と設計図が用意されているので興味あれば是非探してみてください。
以上、お付き合いありがとうございました。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA