IPアドレスをKibana+Elasticsearchでプロットするメモ


目的

いろんなサーバを運用しているのですが、どこの国からアクセスされてるかをプロットしたい!
(Elasticsearch + Kibana + Python3で)
でもLogstashは使わない(事情があって使えない)・・・という時のメモ(普通ない)

環境

ubuntu 18.04
Elasticsearch 7.4
Kibana 7.4
※Elasticsearchについてはいろいろ情報があるので、9200ポートで動いてるのが前提で書いてます。
 同じくKibanaは5601で動作中

使用するモジュールのインストール

sudo pip3 install python-geohash
sudo pip3 install geoip2
sudo pip3 install elasticsearch
sudo pip3 install pytz

geoip2用のマップをダウンロード

MAXMINDのページから「GeoLite2 City (MAXMIND DB版)」をダウンロード
MAXMIND
※Countryバージョンだと緯度経度が取得できないためCityバージョンを

Elasticsearchへの投げ込み

ログファイルの例

DATE,IP,SRC_PORT,DST_PORT,SIZE,DATA
2019/11/05 19:00:00,1.2.3.4,44455,80,180,474554202F20485454502F312E31・・・
2019/11/05 19:00:00,2.3.4.5,44456,80,180,474554202F20485454502F312E31・・・
・・・

このIPを位置情報としてKibanaにプロットしたい・・・

Indexの作成

Kibana上で位置情報と認識させるには、geohashはタイプを「"type": "geo_point"」として指定する必要があります。
KibanaへアクセスしてDevTool画面で次のクエリを実行します。


PUT geoip_map
{
  "mappings": {
    "properties": {
      "add_time": {
        "type": "date",
        "format": "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
      },
      "data": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "geohash": {
        "type": "geo_point"
      },
      "ip": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "latitude": {
        "type": "float"
      },
      "longitude": {
        "type": "float"
      },
      "src_port": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "dst_port": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "size": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      }
    }
  }
}

以上で入れ物は出来上がりました。

データの投入


import pytz
import geoip2.database
import geohash
from datetime import *
from elasticsearch import Elasticsearch

ELASTIC_HOST = "127.0.0.1"

elasticobj = Elasticsearch(ELASTIC_HOST + ":9200")

with open("logfile.txt","r") as f:
    logdata = f.read()
    loglst = logdata.replace('\r','').split('\n')

reader = geoip2.database.Reader('GeoLite2-City.mmdb')

for line in loglst:
    cols = line.split(',')

    #geoip2を使用して緯度経度等の情報をセット
    resp = reader.city(cols[1])

    #geohashを計算 精度はデフォルトで
    str_geohash = geohash.encode(resp.location.latitude,resp.location.longitude)

    #Elasticsearchへ登録 不要ですがこのコードでは緯度経度も生データを保存してます
    #実際には実際のログデータに合わせてこれらの値は変更して下さい
    elasticobj.index(index="geoip_map",doc_type="_doc",body={"geohash":str_geohash,"latitude":resp.location.latitude,"longitude":resp.location.longitude,"add_time":cols [0].replace("-"," "),"ip":cols [1],"src_port":cols [2],"dst_port":cols [3],"size":cols [4],"data":cols [5]}) 

Kibanaでの描画

Kibanaでgeoip_mapを見れるようにする手順等はさらっと・・・

indexパターンの作成

Management⇒index patternなどと書かれているところに「geoip*」などと書いてCreateボタンをクリック

日時情報のフィールドが自動的に検出されていると思いますので、add_timeを選択しCreateボタンをクリック

以上で、Discover画面でデータが見れる状態になっています。

Visualizationの作成

次の画面でMapsをクリック(RegionMapやCoodinateMapでも同じようなことができます)

Add layerを押して、既にKibana上にあるIndexを使用することが書かれている項目を選択し、
Select Index Patternと書かれているところで、「geoip*」などで作成したパターンを選択。
(位置情報のフィールドを指定する必要がある場合は、geohashフィールドを選択。)

こんな感じでプロットができる。

とりあえずは完成!
もっとカッコイイ地図を使ったりもできるらしいので後でやってみよう。