Merge pull request #5262 from foxdalas/geoip2_isp
Add Maxmind Editions support
This commit is contained in:
commit
84619d7b08
7 changed files with 110 additions and 30 deletions
|
@ -186,6 +186,7 @@ Takes the form "<host>:port". If not provided, no admission controller is starte
|
||||||
|
|
||||||
flags.StringVar(&nginx.MaxmindLicenseKey, "maxmind-license-key", "", `Maxmind license key to download GeoLite2 Databases.
|
flags.StringVar(&nginx.MaxmindLicenseKey, "maxmind-license-key", "", `Maxmind license key to download GeoLite2 Databases.
|
||||||
https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-geolite2-databases`)
|
https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-geolite2-databases`)
|
||||||
|
flags.StringVar(&nginx.MaxmindEditionIDs, "maxmind-edition-ids", "GeoLite2-City,GeoLite2-ASN", `Maxmind edition ids to download GeoLite2 Databases.`)
|
||||||
|
|
||||||
flag.Set("logtostderr", "true")
|
flag.Set("logtostderr", "true")
|
||||||
|
|
||||||
|
@ -310,12 +311,15 @@ https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-g
|
||||||
config.RootCAFile = *rootCAFile
|
config.RootCAFile = *rootCAFile
|
||||||
}
|
}
|
||||||
|
|
||||||
if nginx.MaxmindLicenseKey != "" {
|
if nginx.MaxmindLicenseKey != "" && nginx.MaxmindEditionIDs != "" {
|
||||||
|
if err := nginx.ValidateGeoLite2DBEditions(); err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
klog.Info("downloading maxmind GeoIP2 databases...")
|
klog.Info("downloading maxmind GeoIP2 databases...")
|
||||||
err := nginx.DownloadGeoLite2DB()
|
if err := nginx.DownloadGeoLite2DB(); err != nil {
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("unexpected error downloading GeoIP2 database: %v", err)
|
klog.Errorf("unexpected error downloading GeoIP2 database: %v", err)
|
||||||
}
|
}
|
||||||
|
config.MaxmindEditionFiles = nginx.MaxmindEditionFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, config, nil
|
return false, config, nil
|
||||||
|
|
|
@ -75,3 +75,16 @@ func TestFlagConflict(t *testing.T) {
|
||||||
t.Fatalf("Expected an error parsing flags but none returned")
|
t.Fatalf("Expected an error parsing flags but none returned")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMaxmindEdition(t *testing.T) {
|
||||||
|
resetForTesting(func() { t.Fatal("Parsing failed") })
|
||||||
|
|
||||||
|
oldArgs := os.Args
|
||||||
|
defer func() { os.Args = oldArgs }()
|
||||||
|
os.Args = []string{"cmd", "--publish-service", "namespace/test", "--http-port", "0", "--https-port", "0", "--maxmind-license-key", "0000000", "--maxmind-edition-ids", "GeoLite2-City, TestCheck"}
|
||||||
|
|
||||||
|
_, _, err := parseFlags()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Expected an error parsing flags but none returned")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -826,6 +826,7 @@ type TemplateConfig struct {
|
||||||
ListenPorts *ListenPorts
|
ListenPorts *ListenPorts
|
||||||
PublishService *apiv1.Service
|
PublishService *apiv1.Service
|
||||||
EnableMetrics bool
|
EnableMetrics bool
|
||||||
|
MaxmindEditionFiles []string
|
||||||
|
|
||||||
PID string
|
PID string
|
||||||
StatusPath string
|
StatusPath string
|
||||||
|
|
|
@ -98,7 +98,8 @@ type Configuration struct {
|
||||||
ValidationWebhookCertPath string
|
ValidationWebhookCertPath string
|
||||||
ValidationWebhookKeyPath string
|
ValidationWebhookKeyPath string
|
||||||
|
|
||||||
GlobalExternalAuth *ngx_config.GlobalExternalAuth
|
GlobalExternalAuth *ngx_config.GlobalExternalAuth
|
||||||
|
MaxmindEditionFiles []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPublishService returns the Service used to set the load-balancer status of Ingresses.
|
// GetPublishService returns the Service used to set the load-balancer status of Ingresses.
|
||||||
|
|
|
@ -615,12 +615,12 @@ func (n NGINXController) generateTemplate(cfg ngx_config.Configuration, ingressC
|
||||||
ListenPorts: n.cfg.ListenPorts,
|
ListenPorts: n.cfg.ListenPorts,
|
||||||
PublishService: n.GetPublishService(),
|
PublishService: n.GetPublishService(),
|
||||||
EnableMetrics: n.cfg.EnableMetrics,
|
EnableMetrics: n.cfg.EnableMetrics,
|
||||||
|
MaxmindEditionFiles: n.cfg.MaxmindEditionFiles,
|
||||||
HealthzURI: nginx.HealthPath,
|
HealthzURI: nginx.HealthPath,
|
||||||
PID: nginx.PID,
|
PID: nginx.PID,
|
||||||
StatusPath: nginx.StatusPath,
|
StatusPath: nginx.StatusPath,
|
||||||
StatusPort: nginx.StatusPort,
|
StatusPort: nginx.StatusPort,
|
||||||
StreamPort: nginx.StreamPort,
|
StreamPort: nginx.StreamPort,
|
||||||
}
|
}
|
||||||
|
|
||||||
tc.Cfg.Checksum = ingressCfg.ConfigurationChecksum
|
tc.Cfg.Checksum = ingressCfg.ConfigurationChecksum
|
||||||
|
|
|
@ -30,12 +30,14 @@ import (
|
||||||
// MaxmindLicenseKey maxmind license key to download databases
|
// MaxmindLicenseKey maxmind license key to download databases
|
||||||
var MaxmindLicenseKey = ""
|
var MaxmindLicenseKey = ""
|
||||||
|
|
||||||
|
// MaxmindEditionIDs maxmind editions (GeoLite2-City, GeoLite2-Country, GeoIP2-ISP, etc)
|
||||||
|
var MaxmindEditionIDs = ""
|
||||||
|
|
||||||
|
// MaxmindEditionFiles maxmind databases on disk
|
||||||
|
var MaxmindEditionFiles []string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
geoIPPath = "/etc/nginx/geoip"
|
geoIPPath = "/etc/nginx/geoip"
|
||||||
|
|
||||||
geoLiteCityDB = "GeoLite2-City"
|
|
||||||
geoLiteASNDB = "GeoLite2-ASN"
|
|
||||||
|
|
||||||
dbExtension = ".mmdb"
|
dbExtension = ".mmdb"
|
||||||
|
|
||||||
maxmindURL = "https://download.maxmind.com/app/geoip_download?license_key=%v&edition_id=%v&suffix=tar.gz"
|
maxmindURL = "https://download.maxmind.com/app/geoip_download?license_key=%v&edition_id=%v&suffix=tar.gz"
|
||||||
|
@ -44,12 +46,10 @@ const (
|
||||||
// GeoLite2DBExists checks if the required databases for
|
// GeoLite2DBExists checks if the required databases for
|
||||||
// the GeoIP2 NGINX module are present in the filesystem
|
// the GeoIP2 NGINX module are present in the filesystem
|
||||||
func GeoLite2DBExists() bool {
|
func GeoLite2DBExists() bool {
|
||||||
if !fileExists(path.Join(geoIPPath, geoLiteASNDB+dbExtension)) {
|
for _, dbName := range strings.Split(MaxmindEditionIDs, ",") {
|
||||||
return false
|
if !fileExists(path.Join(geoIPPath, dbName+dbExtension)) {
|
||||||
}
|
return false
|
||||||
|
}
|
||||||
if !fileExists(path.Join(geoIPPath, geoLiteCityDB+dbExtension)) {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@ -58,16 +58,13 @@ func GeoLite2DBExists() bool {
|
||||||
// DownloadGeoLite2DB downloads the required databases by the
|
// DownloadGeoLite2DB downloads the required databases by the
|
||||||
// GeoIP2 NGINX module using a license key from MaxMind.
|
// GeoIP2 NGINX module using a license key from MaxMind.
|
||||||
func DownloadGeoLite2DB() error {
|
func DownloadGeoLite2DB() error {
|
||||||
err := downloadDatabase(geoLiteCityDB)
|
for _, dbName := range strings.Split(MaxmindEditionIDs, ",") {
|
||||||
if err != nil {
|
err := downloadDatabase(dbName)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
MaxmindEditionFiles = append(MaxmindEditionFiles, dbName+dbExtension)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = downloadDatabase(geoLiteASNDB)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +130,29 @@ func downloadDatabase(dbName string) error {
|
||||||
fmt.Sprintf(maxmindURL, "XXXXXXX", dbName), mmdbFile)
|
fmt.Sprintf(maxmindURL, "XXXXXXX", dbName), mmdbFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidateGeoLite2DBEditions check provided Maxmind database editions names
|
||||||
|
func ValidateGeoLite2DBEditions() error {
|
||||||
|
allowedEditions := map[string]bool{
|
||||||
|
"GeoIP2-Anonymous-IP": true,
|
||||||
|
"GeoIP2-Country": true,
|
||||||
|
"GeoIP2-City": true,
|
||||||
|
"GeoIP2-Connection-Type": true,
|
||||||
|
"GeoIP2-Domain": true,
|
||||||
|
"GeoIP2-ISP": true,
|
||||||
|
"GeoIP2-ASN": true,
|
||||||
|
"GeoLite2-ASN": true,
|
||||||
|
"GeoLite2-Country": true,
|
||||||
|
"GeoLite2-City": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, edition := range strings.Split(MaxmindEditionIDs, ",") {
|
||||||
|
if !allowedEditions[edition] {
|
||||||
|
return fmt.Errorf("unknown Maxmind GeoIP2 edition name: '%s'", edition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func fileExists(filePath string) bool {
|
func fileExists(filePath string) bool {
|
||||||
info, err := os.Stat(filePath)
|
info, err := os.Stat(filePath)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
|
|
@ -159,6 +159,8 @@ http {
|
||||||
{{ if $cfg.UseGeoIP2 }}
|
{{ if $cfg.UseGeoIP2 }}
|
||||||
# https://github.com/leev/ngx_http_geoip2_module#example-usage
|
# https://github.com/leev/ngx_http_geoip2_module#example-usage
|
||||||
|
|
||||||
|
{{ range $index, $file := $all.MaxmindEditionFiles }}
|
||||||
|
{{ if eq $file "GeoLite2-City.mmdb" }}
|
||||||
geoip2 /etc/nginx/geoip/GeoLite2-City.mmdb {
|
geoip2 /etc/nginx/geoip/GeoLite2-City.mmdb {
|
||||||
$geoip2_city_country_code source=$remote_addr country iso_code;
|
$geoip2_city_country_code source=$remote_addr country iso_code;
|
||||||
$geoip2_city_country_name source=$remote_addr country names en;
|
$geoip2_city_country_name source=$remote_addr country names en;
|
||||||
|
@ -171,13 +173,52 @@ http {
|
||||||
$geoip2_region_code source=$remote_addr subdivisions 0 iso_code;
|
$geoip2_region_code source=$remote_addr subdivisions 0 iso_code;
|
||||||
$geoip2_region_name source=$remote_addr subdivisions 0 names en;
|
$geoip2_region_name source=$remote_addr subdivisions 0 names en;
|
||||||
}
|
}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if eq $file "GeoIP2-City.mmdb" }}
|
||||||
|
geoip2 /etc/nginx/geoip/GeoIP2-City.mmdb {
|
||||||
|
$geoip2_city_country_code source=$remote_addr country iso_code;
|
||||||
|
$geoip2_city_country_name source=$remote_addr country names en;
|
||||||
|
$geoip2_city source=$remote_addr city names en;
|
||||||
|
$geoip2_postal_code source=$remote_addr postal code;
|
||||||
|
$geoip2_dma_code source=$remote_addr location metro_code;
|
||||||
|
$geoip2_latitude source=$remote_addr location latitude;
|
||||||
|
$geoip2_longitude source=$remote_addr location longitude;
|
||||||
|
$geoip2_time_zone source=$remote_addr location time_zone;
|
||||||
|
$geoip2_region_code source=$remote_addr subdivisions 0 iso_code;
|
||||||
|
$geoip2_region_name source=$remote_addr subdivisions 0 names en;
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if eq $file "GeoLite2-ASN.mmdb" }}
|
||||||
geoip2 /etc/nginx/geoip/GeoLite2-ASN.mmdb {
|
geoip2 /etc/nginx/geoip/GeoLite2-ASN.mmdb {
|
||||||
$geoip2_asn source=$remote_addr autonomous_system_number;
|
$geoip2_asn source=$remote_addr autonomous_system_number;
|
||||||
$geoip2_org source=$remote_addr autonomous_system_organization;
|
$geoip2_org source=$remote_addr autonomous_system_organization;
|
||||||
}
|
}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if eq $file "GeoIP2-ASN.mmdb" }}
|
||||||
|
geoip2 /etc/nginx/geoip/GeoIP2-ASN.mmdb {
|
||||||
|
$geoip2_asn source=$remote_addr autonomous_system_number;
|
||||||
|
$geoip2_org source=$remote_addr autonomous_system_organization;
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if eq $file "GeoIP2-ISP.mmdb" }}
|
||||||
|
geoip2 /etc/nginx/geoip/GeoIP2-ISP.mmdb {
|
||||||
|
$geoip2_isp isp;
|
||||||
|
$geoip2_isp_org organization;
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
{{ if eq $file "GeoIP2-Connection-Type.mmdb" }}
|
||||||
|
geoip2 /etc/nginx/geoip/GeoIP2-Connection-Type.mmdb {
|
||||||
|
$geoip2_connection_type connection_type;
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
aio threads;
|
aio threads;
|
||||||
aio_write on;
|
aio_write on;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue