Skip to content

Commit

Permalink
MaxMind Geolocation provider
Browse files Browse the repository at this point in the history
Signed-off-by: Kateryna Nezdolii <nezdolik@spotify.com>
  • Loading branch information
Kateryna Nezdolii committed Jul 19, 2023
1 parent 2311e03 commit aeffe67
Show file tree
Hide file tree
Showing 44 changed files with 1,672 additions and 463 deletions.
2 changes: 2 additions & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,8 @@ extensions/filters/http/oauth2 @derekargueta @mattklein123
/*/extensions/health_check/event_sinks/file @botengyao @yanavlasov
# IP Geolocation
/*/extensions/filters/http/geoip @nezdolik @ravenblackx
# Maxmind geolocation provider
/*/extensions/geoip_providers/maxmind @nezdolik @ravenblackx

/*/extensions/health_checkers/common @zuercher @botengyao

Expand Down
2 changes: 2 additions & 0 deletions api/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ proto_library(
"//envoy/extensions/formatter/cel/v3:pkg",
"//envoy/extensions/formatter/metadata/v3:pkg",
"//envoy/extensions/formatter/req_without_query/v3:pkg",
"//envoy/extensions/geoip_providers/common/v3:pkg",
"//envoy/extensions/geoip_providers/maxmind/v3:pkg",
"//envoy/extensions/health_check/event_sinks/file/v3:pkg",
"//envoy/extensions/health_checkers/redis/v3:pkg",
"//envoy/extensions/health_checkers/thrift/v3:pkg",
Expand Down
55 changes: 5 additions & 50 deletions api/envoy/extensions/filters/http/geoip/v3/geoip.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,52 +21,6 @@ option (xds.annotations.v3.file_status).work_in_progress = true;
// [#extension: envoy.filters.http.geoip]

message Geoip {
// The set of geolocation headers to add to request. If any of the configured headers is present
// in the incoming request, it will be overridden by Geoip filter.
// [#next-free-field: 10]
message GeolocationHeadersToAdd {
// If set, the header will be used to populate the country ISO code associated with the IP address.
string country = 1
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];

// If set, the header will be used to populate the city associated with the IP address.
string city = 2
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];

// If set, the header will be used to populate the region ISO code associated with the IP address.
string region = 3
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];

// If set, the header will be used to populate the ASN associated with the IP address.
string asn = 4
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];

// If set, the IP address will be checked if it belongs to any type of anonymization network (e.g. VPN, public proxy etc)
// and header will be populated with the check result. Header value will be set to either "true" or "false" depending on the check result.
string is_anon = 5
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];

// If set, the IP address will be checked if it belongs to a VPN and header will be populated with the check result.
// Header value will be set to either "true" or "false" depending on the check result.
string anon_vpn = 6
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];

// If set, the IP address will be checked if it belongs to a hosting provider and header will be populated with the check result.
// Header value will be set to either "true" or "false" depending on the check result.
string anon_hosting = 7
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];

// If set, the IP address will be checked if it belongs to a TOR exit node and header will be populated with the check result.
// Header value will be set to either "true" or "false" depending on the check result.
string anon_tor = 8
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];

// If set, the IP address will be checked if it belongs to a public proxy and header will be populated with the check result.
// Header value will be set to either "true" or "false" depending on the check result.
string anon_proxy = 9
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];
}

message XffConfig {
// The number of additional ingress proxy hops from the right side of the
// :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header to trust when
Expand All @@ -82,9 +36,10 @@ message Geoip {
// [#next-free-field: 2]
XffConfig xff_config = 1;

// Configuration for geolocation headers to add to request.
GeolocationHeadersToAdd geo_headers_to_add = 2 [(validate.rules).message = {required: true}];

// Geolocation provider specific configuration.
// Geoip driver specific configuration which depends on the driver being instantiated.
// See the geoip drivers for examples:
//
// - :ref:`MaxMindConfig <envoy_api_msg_config.geoip.v3.MaxMindConfig>`
// [#extension-category: envoy.geoip_providers]
config.core.v3.TypedExtensionConfig provider = 3 [(validate.rules).message = {required: true}];
}
9 changes: 9 additions & 0 deletions api/envoy/extensions/geoip_providers/common/v3/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py.

load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package")

licenses(["notice"]) # Apache 2

api_proto_package(
deps = ["@com_github_cncf_udpa//udpa/annotations:pkg"],
)
63 changes: 63 additions & 0 deletions api/envoy/extensions/geoip_providers/common/v3/common.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
syntax = "proto3";

package envoy.extensions.geoip_providers.common.v3;

import "udpa/annotations/status.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.extensions.geoip_providers.common.v3";
option java_outer_classname = "CommonProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/geoip_providers/common/v3;commonv3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

message CommonGeoipProviderConfig {
// The set of geolocation headers to add to request. If any of the configured headers is present
// in the incoming request, it will be overridden by Geoip filter.
// [#next-free-field: 10]
message GeolocationHeadersToAdd {
// If set, the header will be used to populate the country ISO code associated with the IP address.
string country = 1
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];

// If set, the header will be used to populate the city associated with the IP address.
string city = 2
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];

// If set, the header will be used to populate the region ISO code associated with the IP address.
string region = 3
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];

// If set, the header will be used to populate the ASN associated with the IP address.
string asn = 4
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];

// If set, the IP address will be checked if it belongs to any type of anonymization network (e.g. VPN, public proxy etc)
// and header will be populated with the check result. Header value will be set to either "true" or "false" depending on the check result.
string is_anon = 5
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];

// If set, the IP address will be checked if it belongs to a VPN and header will be populated with the check result.
// Header value will be set to either "true" or "false" depending on the check result.
string anon_vpn = 6
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];

// If set, the IP address will be checked if it belongs to a hosting provider and header will be populated with the check result.
// Header value will be set to either "true" or "false" depending on the check result.
string anon_hosting = 7
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];

// If set, the IP address will be checked if it belongs to a TOR exit node and header will be populated with the check result.
// Header value will be set to either "true" or "false" depending on the check result.
string anon_tor = 8
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];

// If set, the IP address will be checked if it belongs to a public proxy and header will be populated with the check result.
// Header value will be set to either "true" or "false" depending on the check result.
string anon_proxy = 9
[(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME ignore_empty: true}];
}

// Configuration for geolocation headers to add to request.
GeolocationHeadersToAdd geo_headers_to_add = 1 [(validate.rules).message = {required: true}];
}
13 changes: 13 additions & 0 deletions api/envoy/extensions/geoip_providers/maxmind/v3/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py.

load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package")

licenses(["notice"]) # Apache 2

api_proto_package(
deps = [
"//envoy/extensions/geoip_providers/common/v3:pkg",
"@com_github_cncf_udpa//udpa/annotations:pkg",
"@com_github_cncf_udpa//xds/annotations/v3:pkg",
],
)
32 changes: 32 additions & 0 deletions api/envoy/extensions/geoip_providers/maxmind/v3/maxmind.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
syntax = "proto3";

package envoy.extensions.geoip_providers.maxmind.v3;

import "envoy/extensions/geoip_providers/common/v3/common.proto";

import "xds/annotations/v3/status.proto";

import "udpa/annotations/status.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.extensions.geoip_providers.maxmind.v3";
option java_outer_classname = "MaxmindProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/geoip_providers/maxmind/v3;maxmindv3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;
option (xds.annotations.v3.file_status).work_in_progress = true;

// [#protodoc-title: MaxMind geolocation provider]

// Configuration for the MaxMind geolocation provider.
// [#extension: envoy.geoip_providers.maxmind]
message MaxMindConfig {
string city_db_path = 1;

string isp_db_path = 2;

string anon_db_path = 3;

common.v3.CommonGeoipProviderConfig common_provider_config = 4
[(validate.rules).message = {required: true}];
}
2 changes: 2 additions & 0 deletions api/versioning/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ proto_library(
"//envoy/extensions/formatter/cel/v3:pkg",
"//envoy/extensions/formatter/metadata/v3:pkg",
"//envoy/extensions/formatter/req_without_query/v3:pkg",
"//envoy/extensions/geoip_providers/common/v3:pkg",
"//envoy/extensions/geoip_providers/maxmind/v3:pkg",
"//envoy/extensions/health_check/event_sinks/file/v3:pkg",
"//envoy/extensions/health_checkers/redis/v3:pkg",
"//envoy/extensions/health_checkers/thrift/v3:pkg",
Expand Down
17 changes: 17 additions & 0 deletions bazel/foreign_cc/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -570,3 +570,20 @@ envoy_cmake(
}),
working_directory = "build/cmake",
)

envoy_cmake(
name = "maxmind",
cache_entries = {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_INSTALL_LIBDIR": "lib",
"CMAKE_CXX_COMPILER_FORCED": "on",
"BUILD_SHARED_LIBS": "no",
"BUILD_TESTING": "no",
},
defines = ["MAXMIND_STATICLIB"],
lib_source = "@com_github_maxmind_libmaxminddb//:all",
out_static_libs = select({
"//bazel:windows_x86_64": ["libmaxminddb.lib"],
"//conditions:default": ["libmaxminddb.a"],
}),
)
11 changes: 11 additions & 0 deletions bazel/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ def envoy_dependencies(skip_targets = []):
external_http_archive("bazel_toolchains")
external_http_archive("bazel_compdb")
external_http_archive("envoy_build_tools")
_com_github_maxmind_libmaxminddb()

# TODO(keith): Remove patch when we update rules_pkg
external_http_archive(
Expand Down Expand Up @@ -1373,3 +1374,13 @@ def _is_linux_s390x(ctxt):

def _is_linux_x86_64(ctxt):
return _is_linux(ctxt) and _is_arch(ctxt, "x86_64")

def _com_github_maxmind_libmaxminddb():
external_http_archive(
name = "com_github_maxmind_libmaxminddb",
build_file_content = BUILD_ALL_CONTENT,
)
native.bind(
name = "maxmind",
actual = "@envoy//bazel/foreign_cc:maxmind",
)
15 changes: 15 additions & 0 deletions bazel/repository_locations.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -1448,6 +1448,21 @@ REPOSITORY_LOCATIONS_SPEC = dict(
license = "MIT",
license_url = "https://github.com/protocolbuffers/utf8_range/blob/{version}/LICENSE",
),
com_github_maxmind_libmaxminddb = dict(
project_name = "maxmind_libmaxminddb",
project_desc = "C library for reading MaxMind DB files",
project_url = "https://github.com/maxmind/libmaxminddb",
version = "1.7.1",
sha256 = "e8414f0dedcecbc1f6c31cb65cd81650952ab0677a4d8c49cab603b3b8fb083e",
strip_prefix = "libmaxminddb-{version}",
urls = ["https://github.com/maxmind/libmaxminddb/releases/download/{version}/libmaxminddb-{version}.tar.gz"],
use_category = ["dataplane_ext"],
extensions = ["envoy.geoip_providers.maxmind"],
release_date = "2022-09-30",
cpe = "N/A",
license = "Apache-2.0",
license_url = "https://github.com/maxmind/libmaxminddb/blob/{version}/LICENSE",
),
)

def _compiled_protoc_deps(locations, versions):
Expand Down
1 change: 1 addition & 0 deletions docs/root/configuration/http/http_filters/geoip_filter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Filter uses client address to lookup information (eg client's city, country) in
Upon a successful lookup request will be enriched with the configured geolocation header and value from the database.
In case the configured geolocation headers are present in the incoming request, they will be overriden by the filter.
Geolocation filter emits stats for the number of successful lookups and the number of total lookups.
As for now, only `Maxmind <https://www.maxmind.com/en/geoip2-services-and-databases>` geolocation provider is supported.

Configuration
-------------
Expand Down
31 changes: 31 additions & 0 deletions envoy/geoip/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_extension",
"envoy_extension_package",
"envoy_package",
)

licenses(["notice"]) # Apache 2

envoy_package()

# HTTP L7 filter that decorates request with geolocation data
# Public docs: https://envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/geoip_filter

envoy_extension_package()

#todo(nezdolik) may need to split into interface and impl
envoy_cc_extension(
name = "geoip_provider_driver_interface",
hdrs = [
"geoip_provider_driver.h",
],
deps = [
"//envoy/config:typed_config_interface",
"//envoy/network:address_interface",
"//envoy/protobuf:message_validator_interface",
"//envoy/server:factory_context_interface",
"//source/common/common:hash_lib",
"//source/common/protobuf:utility_lib",
],
)
Loading

0 comments on commit aeffe67

Please sign in to comment.