RAKUS Developers Blog | ラクス エンジニアブログ

株式会社ラクスのITエンジニアによる技術ブログです。

ログ解析によるアクセスログの可視化で運用を楽にしたい!

はじめまして。rks_mnkiです。
ラクスでひっそりとインフラエンジニアやってます。
特技は、蚊に刺されないことです。

さて今回は、Apacheアクセスログに関するログ解析手法」について、実際に検証を行った一例も踏まえながらご紹介したいと思います。

目次:

1.Apacheアクセスログとは

私たちがホームページやブログサイト(当ブログもそうですけど)にアクセスした際に、コンテンツデータをブラウザに返してくれるのが、「WEBサーバソフトウェア」となります。

このソフトウェアの1つとして、メジャーに利用されているのが"Apache(正式名称:Apache HTTP Server)"です。
オープンソースソフトウェアのため、誰でも無料で利用できる点が大きな特徴となります。

そして、このWEBサーバ(Apache)にアクセスした際の情報が記録されるのが、「アクセスログ」です。

▼サンプル

# tail /var/log/httpd/access_log
xxx.xxx.xxx.xxx - - [20/Dec/2021:09:41:38 +0900] "GET / HTTP/1.1" 200 108 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36"

こちらは、とあるWEBサイトのTOPページにアクセスした際のアクセスログの一部抜粋となります。 ぱっと見では、なんなのかよく分かりませんが、予め定義されたフォーマットに沿って情報が表示されています。

標準で用意されているログフォーマットもありますが、管理者が任意にカスタマイズすることもできます。

2.「ログ解析」の必要性

ITインフラの運用業務においては、このアクセスログを確認するケースが多々あります。
例えば、稼働中のサーバが急激にパフォーマンス高負荷になった場合、

  • WEBアクセスが急増していないか?
  • どのURLにアクセスしているケースが多いか?
  • 不正なアクセスは発生していないか?

などの状況をアクセスログを元に確認し、原因調査を進める事になります。

しかし、ログを眺めているだけでは、「アクセス急増している時間帯はあるか」「海外からの不正アクセスはあるか」といった情報の判別は瞬時にできません。 そのため、特定情報を元に手動で集計するなど工夫しながら調査を行う事になりますが、これがなかなかの手間になります。

アクセス頻度が多く高負荷になりやすい環境であれば、調査頻度も多くなるのでなおさら面倒なことに。。

もちろん、ある程度の知識や慣れも必要となりますので、アクセスログのデータを自動集計して「パッと見て」分かるように可視化できれば、誰でも簡単に確認することができるかなぁ?と考え、とりあえず検証してみる事にしました。

3.確認したい具体的な情報

一般的に「アクセスログ解析」とは、ユーザがいつ・どこからアクセスしたのか・どのページに頻繁にアクセスしているかなど、WEBサイトの利用状況を把握するために、データを集計して分析することを指します。主に、マーケティングで利用するイメージです。

ここでは、インフラ視点に立って以下の要素を実現するために、「ログ解析」の手法を取り入れて検証していきます。

  • WEBアクセス数の推移
  • アクセス元のロケーション情報
  • どのページに頻繁にアクセスされているか
  • 上記の情報をグラフィカルに表示

4.利用するツールの紹介

前述の要件を満たすため、以下のツールを利用します。(よくある組み合わせです)
いずれもElastic社が開発・提供しているソリューションで無償で利用できますが、有償オプションも存在します。

ElasticSearch

あらゆるデータタイプに対応した検索/分析エンジン。

Logstash

サーバサイドデータ処理パイプライン。
あらゆるデータを構造化・整形して、指定された場所にデータ転送。

Kibana

ElasticSearchデータを可視化することができるユーザインターフェイス

▼利用イメージとしては、下記図のとおり。

ELK利用イメージ図

5.実際に導入してみる

WEBサーバの準備

まず、アクセス先となるWEBサーバをAWS環境上に1台構築します。
テスト環境のため、このWEBサーバに対するHTTP通信については制限を設けず公開した状態とします。

EC2インスタンス

すると、デフォルトのWEBページを公開しているだけにも関わらず、どこからともなくアクセスが来ている事が分かります。

# tail /var/log/httpd/access_log
135.125.246.110 - - [21/Dec/2021:09:18:02 +0900] "POST / HTTP/1.1" 200 108 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
3.239.174.91 - - [21/Dec/2021:10:24:27 +0900] "POST / HTTP/1.1" 200 108 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
209.17.96.250 - - [21/Dec/2021:10:31:58 +0900] "\x16\x03\x01" 400 226 "-" "-"
130.211.54.158 - - [21/Dec/2021:11:03:24 +0900] "GET / HTTP/1.1" 200 108 "-" "python-requests/2.26.0"

このアクセスは、主に海外などからボットを使った不正アクセスと思われます。

dockerコンテナによるログ解析環境を構築

それでは、いよいよこのアクセスログを解析するための環境を構築します。 今回はGithubで公開されている、ElasticSearch+Logstash+KibanaがパッケージングされたDockerイメージを使います。 (利用バージョンは、7.15.2) また、docoker-composeにより各サービスのコンテナを立ち上げてログ解析環境として稼働させます。

docoker-compose構成イメージ

※KibanaへのアクセスをNginxでリバースプロキシするために、Nginxのdockerイメージも利用。特に必須ではありません。

各種設定

Dockerに関する説明は、今回は省略致します。 ここでは、主にLogstashとKibanaに関する設定内容についてご紹介致します。

Logstashの設定ファイルは、インプット/フィルター/アウトプットで構成されます。

  • インプット
input {
  file {
    path => "/var/log/httpd/access_log-*"
    sincedb_path => "/dev/null"
    type => "apache"
    start_position => "beginning"
  }
}

読み取り対象となるファイルのpathを指定しています。 その他パラメータとして、start_position => "beginning"ではLogstashを起動した際に、ログファイルを先頭から読み取るように指定しています。

  • フィルター
filter {
  grok {
    match => { "message" => "%{COMBINEDAPACHELOG}" }
    break_on_match => false
    tag_on_failure => ["_message_parse_failure"]
  }

  date {
    match => ["timestamp", "dd/MMM/YYYY:HH:mm:ss Z"]
    locale => en
  }

  geoip {
    source => ["clientip"]
  }
}

grokセクションで Apacheアクセスログを各フィールドに分割します。今回対象のログは、combinedフォーマットとなっているため、予め用意されている"%{COMBINEDAPACHELOG}"にmatchさせています。
dateセクションでは、アクセスログが記録された日時をtimestampとして書き換えます。(デフォルトでLogstashで読み込んだ日時がtimestampとして記録されるため)
また、どこの国からのアクセスか判別させるために、geoipセクションでは「アクセス元IPアドレス」から国名や緯度経度などの情報を付与します。
これらのフィルタ処理を施すことで、以下のようなフィールド構造に変換されます。

{
  "type": "apache",
  "clientip": "212.107.231.174",
  "ident": "-",
  "message": "212.107.231.174 - - [01/Dec/2021:16:23:41 +0900] \"GET / HTTP/1.1\" 200 108 \"-\" \"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36\"",
  "host": "1c3067174f38",
  "geoip": {
    "longitude": 84.8328,
    "postal_code": "636019",
    "continent_code": "EU",
    "country_code2": "RU",
    "latitude": 56.6133,
    "location": {
      "lat": 56.6133,
      "lon": 84.8328
    },
    "country_code3": "RU",
    "region_name": "Tomsk Oblast",
    "timezone": "Asia/Tomsk",
    "country_name": "Russia",
    "ip": "212.107.231.174",
    "city_name": "Seversk",
    "region_code": "TOM"
  },
  "@timestamp": "2021-12-01T07:23:41.000Z",
  "timestamp": "01/Dec/2021:16:23:41 +0900",
  "request": "/",
  "bytes": "108",
  "referrer": "\"-\"",
  "auth": "-",
  "agent": "\"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36\"",
  "@version": "1",
  "httpversion": "1.1",
  "response": "200",
  "path": "/var/log/httpd/access_log",
  "verb": "GET"
}
  • アウトプット

ElasticSearchに対してデータを投入する設定を記述。

output {
  elasticsearch {
    hosts => "elasticsearch"
    index => "test-apache-%{+YYYY.MM.dd}"
    user => "elastic"
    password => "*****"
  }
}

データ投入

一通りの設定が完了したのち、dockerコンテナを立ち上げて各種サービスを起動させます。
そして、テスト用WEBサーバからアクセスログを取得し、Logstashに投入します。(所定のディレクトリに配置)

すると、ElasticSearch上で以下のようにインデックスが作成されている事が確認できます。

▼インデックス確認結果の抜粋

# curl -u elastic:*** http://127.0.0.1:9200/_cat/indices?v | grep "test-apache"

yellow open   test-apache-2021.12.19            OfhZz8QCQlWYsM5_huC51Q   1   1        124            0    154.4kb        154.4kb
yellow open   test-apache-2021.12.13            eNHowDZkRx-Xv_Bv1_Hxxg   1   1        204            0    167.2kb        167.2kb
yellow open   test-apache-2021.12.14            13nhNv_lRa6_81j4EvuLlg   1   1        148            0    135.9kb        135.9kb

それでは、いよいよKibanaにログインします。 [Discover]の画面を開くと、以下のように各フィールドに分離されたパラメータがタグ付きで格納されている事が分かります。

格納データの中身

このデータをもとに、必要となるグラフやマップ設定を行い、ダッシュボード画面を整理していきます。

[Visualize Library]の画面で『Create visualization』のボタンを押すと、以下のようにグラフを生成することができます。様々な種類のグラフから選択することができるので、自分の表現したい形に合わせてセットアップします。

Kibanaの設定画面一例

6.結果と考察

まず、アクセス元の情報を国別にまとめたMapが以下となります。
色のついた国の枠内に表示されている数字がアクセス回数となり、赤色に塗られている国がアクセス数が多いことを示します。

ロケーションMap情報

次に、アクセス数の推移やリクエスト先URL情報などをまとめたグラフです。

その他、グラフ情報

アクセス数の増加タイミングや、アクセス頻度が多いリクエストURL、または送信元IPアドレスの情報を一目見て確認することができます。 さらには、ダッシュボード画面に可視化された情報を集約することで、より見やすくなりました。

こうやって視覚的に判別しやすい可視化された情報として出力することで、当初思い描いていた形を実現できたと思います。

また、同じフォーマットのアクセスログであれば、今回構築したログ解析環境に投入していくだけで、同様の解析結果を得ることができるため、運用オペレーションコストの削減にも繋がると考えます。

なお、今回解析した情報を詳しく見てみると、テスト用に構築したWEBサーバを約20日間放置しているだけで、回数は少ないものの世界中からアクセスされている事が分かります。恐らくは(というかほぼ確実に)、悪意を持った不正アクセスによる影響と考えられますので、セキュリティ対策の必要性を改めて実感しました。

※ロケーション情報については利用するMapデータベースに依存するため、正確ではない部分もあるかもしれませんが、今回は「日本以外からのアクセスがある」という事が分かれば十分なので、そこまで吟味しておりません。

7.まとめ

ここまで、ツールを使ったApacheのログ解析と可視化についてご紹介しました。
直接ログを見たほうが分かりやすい・効率的といったケースもあるかもしれませんが、素早く傾向を把握したいケースにおいて、有効活用できそうと感じました。

また、可視化することでメンバー間での情報共有もスムーズになり、より調査効率の向上も期待できそうです。

今回は、シンプルにApacheアクセスログのみ解析対象としましたが、インフラ部門ではOSやメールソフト、データベースなど各種ログを対象に調査する事もありますので、今後も解析対象の範囲を拡大していきたいと考えています。

さらには、【ログの取得】→【解析環境への投入】を自動化できる仕組みも構築していきたいと妄想しています。

以上です。最後までお読みいただき有難うございました。

備考

Apacheアクセスログの標準的なフォーマット設定

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

このフォーマットに沿って、アクセスログが出力されます。カスタマイズも可能です。

フォーマット文字列 説明
%h リモートホスト
%l リモートログ名
%u リモートユーザ
%t リクエストを受付けた時刻
\"%r\" リクエストの最初の行
%>s 最後のステータスコード
%b レスポンスのバイト数。HTTPヘッダは除く。
\%{Referer}i\ リファラー(参照元
\%{User-Agent}i\ ユーザエージェント

参考文献


◆TECH PLAY
techplay.jp

◆connpass
rakus.connpass.com

Copyright © RAKUS Co., Ltd. All rights reserved.