Elasticsearch:使用 GeoIP 丰富来自内部专用 IP 地址

对于公共 IP,可以创建表来指定 IP 属于哪个城市的特定范围。但是,互联网的很大一部分是不同的。在世界上每个国家都有公司专用网络,其 IP 地址的格式为 10.0.0.0/8、172.16.0.0/12 或 192.168.0.0/16。这些 IP 地址往往没有有关地理位置的真实信息。因此,Elasticsearch 和 Logstash 中内置的 geoip 过滤器/处理器不适用于这些私有 IP。

ElasticsearchLogstash 可以选择指定要使用的特定数据库文件(database / database_file),因此从理论上讲,可以自定义构建。但是,这可能会很耗时,而且维护成本很高,更不用说你可能必须学习一套新工具来仅构建这些 .mmdb 文件(这个在以后的话题中讲)。

可以使用 Elasticsearch 中已经内置的另一个工具(enrich processor)来实现一种更简单的方法,该工具可以(非常令人惊讶地)用我们想要的任何种类的数据(包括地理数据)丰富我们的文档。让我们来看一个这样做的例子。

 

示例:通过大陆,国家/地区和城市来丰富私有 IP

在本例中,我将只讲到任意选择的国家/地区中的城市,但是很容易看出如何将其精确化到村庄或甚至是特定建筑物的水平,或者只精确到国家或地区。 这仅取决于特定用例需求。

我们首先来创建一个 private_geoips 的索引:

PUT private_geoips 
{ 
  "mappings": { 
    "properties": { 
      "city_name": { 
        "type": "keyword" 
      }, 
      "continent_name": { 
        "type": "keyword" 
      }, 
      "country_iso_code": { 
        "type": "keyword" 
      }, 
      "country_name": { 
        "type": "keyword" 
      }, 
      "location": { 
        "type": "geo_point" 
      }, 
      "source.ip": { 
        "type": "ip" 
      } 
    } 
  } 
}

要实现这样的功能,我们需要控制在办公室的哪些位置使用哪些私有 IP。 考虑到专用网络的性质,总是有发生重叠的机会。 对于这个小例子,我们将想象我们可以控制不同办公室的某些子网,而我将其分配如下:

10.4.0.0/16  -  Pretoria South Africa (比勒陀利亚南非)
10.5.0.0/16  -  Toronto Canada(加拿大多伦多)
10.6.0.0/16  -  Berlin Germany(柏林德国)
10.7.0.0/16 -   Tokyo Japan(日本东京)

我们接下来导入如下的数据到索引 private_geoips 中:

POST private_geoips/_bulk 
{"index":{"_id":"pretoria-south-africa"}} 
{"city_name":"Pretoria","continent_name":"Africa","country_iso_code":"SA","country_name":"South Africa","location":[28.21837,-25.73134],"source.ip":["10.4.54.6","10.4.54.7","10.4.54.8"]} 
{"index":{"_id":"toronto-canada"}} 
{"city_name":"Toronto","continent_name":"North America","country_iso_code":"CA","country_name":"Canada","location":[-79.347015,43.65107],"source.ip":["10.5.231.89","10.5.231.90","10.5.231.91"]} 
{"index":{"_id":"berlin-germany"}} 
{"city_name":"Berlin","continent_name":"Europe","country_iso_code":"DE","location":[13.404954,52.520008],"country_name":"Germany","region_name":"","source.ip":["10.6.132.43","10.6.132.44"]} 
{"index":{"_id":"tokyo-japan"}} 
{"city_name":"Tokyo","continent_name":"Asia","country_iso_code":"JP","country_name":"Japan","location":[139.839478,35.652832],"source.ip":["10.7.1.76"]}

我们存储在索引 private_geoips 中的所有文档都必须具有策略 (policy)内 enrich_fields 数组中提到的所有字段。

PUT _enrich/policy/private_geoips_policy
{
  "match": {
    "indices": "private_geoips",
    "match_field": "source.ip",
    "enrich_fields": [
      "city_name",
      "continent_name",
      "country_iso_code",
      "country_name",
      "location"
    ]
  }
}

对于 enrich processor 还是不太了解的开发者来说,你可以参阅我之前的文章 “Elasticsearch:如何使用 Elasticsearch ingest 节点来丰富日志和指标”。其基本意思是当一个文档的 source.ip 字段和 private_geoips 索引中的 source.ip 中的一个比对成功的话,那么在 private_geoips 中的其它字段 "city_name", "continent_name", "country_iso_code", "country_name", "location" 将会被丰富到文档中。

当我们第一次创建策略或更改索引时,我们需要重新执行策略。

POST /_enrich/policy/private_geoips_policy/_execute

让我们创建我们的 ingest pipeline:

PUT /_ingest/pipeline/private_geoips 
{ 
  "description": "_description", 
  "processors": [ 
    { 
      "dot_expander": { 
        "field": "source.ip" 
      } 
    }, 
    { 
      "enrich": { 
        "policy_name": "private_geoips_policy", 
        "field": "source.ip", 
        "target_field": "geo", 
        "max_matches": "1" 
      } 
    }, 
    { 
      "script": { 
        "lang": "painless", 
        "source": "ctx.geo.remove('source.ip')" 
      } 
    } 
  ] 
}

最后,我们来测试 ingest pipeline:

POST /_ingest/pipeline/private_geoips/_simulate 
{ 
  "docs": [ 
    { 
      "_source": { 
        "source.ip": "10.7.1.76" 
      } 
    }, 
    { 
      "_source": { 
        "source.ip": "10.4.54.7" 
      } 
    } 
  ] 
}

运行上面的测试,我们可以看到如下的结果:

{
  "docs" : [
    {
      "doc" : {
        "_index" : "_index",
        "_type" : "_doc",
        "_id" : "_id",
        "_source" : {
          "geo" : {
            "continent_name" : "Asia",
            "country_name" : "Japan",
            "city_name" : "Tokyo",
            "location" : [
              139.839478,
              35.652832
            ],
            "country_iso_code" : "JP"
          },
          "source" : {
            "ip" : "10.7.1.76"
          }
        },
        "_ingest" : {
          "timestamp" : "2020-09-16T01:16:55.901889Z"
        }
      }
    },
    {
      "doc" : {
        "_index" : "_index",
        "_type" : "_doc",
        "_id" : "_id",
        "_source" : {
          "geo" : {
            "continent_name" : "Africa",
            "country_name" : "South Africa",
            "city_name" : "Pretoria",
            "location" : [
              28.21837,
              -25.73134
            ],
            "country_iso_code" : "SA"
          },
          "source" : {
            "ip" : "10.4.54.7"
          }
        },
        "_ingest" : {
          "timestamp" : "2020-09-16T01:16:55.901897Z"
        }
      }
    }
  ]
}

就是这样! 现在,您的私有 IP 地址已充实了 private_geoips 索引中存储的地理位置数据。 现在,您需要做的就是维护该查找索引。