traefik_plugin_state_geo

package module
v1.2.0-rc.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 21, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

README

State Geo Block Middleware

State Geo Block is a Traefik HTTP middleware that blocks non-US traffic and selected US subdivisions using a mounted compatible City-schema MMDB. It supports MaxMind GeoLite2-City and GeoIP2-City directly, as well as compact stategeodb compliance artifacts. It also supports trusted Cloudflare and proxy headers, direct connections, IPv4 and IPv6, explicit failure policies, database hot reload, and custom block pages.

CI CodeQL License

What it does

  • resolves clients from trusted CF-Connecting-IP, True-Client-IP, X-Forwarded-For, RFC Forwarded, X-Real-IP, custom headers, or the direct socket peer;
  • parses IPv4, IPv6, mapped IPv4, bracketed IPv6, and forwarding chains;
  • blocks every non-US country when blockNonUS is enabled;
  • blocks configured two-letter US subdivision codes when blockUSStates is enabled;
  • supports exact IPs, CIDRs, exact path bypasses, and segment-safe path-prefix bypasses;
  • shares one in-memory MMDB reader per database path and reloads atomic file replacements without restarting Traefik;
  • provides bounded TTL/LRU decisions, escaped HTML templates, and structured privacy-conscious logs;
  • gives database, lookup, invalid-IP, unknown-country, unknown-subdivision, and private-IP cases independent policies.

Trust boundary

Forwarding headers are ignored unless the immediate RemoteAddr peer matches trustedProxyCIDRs. This prevents an ordinary direct client from selecting its own geography with a forged header.

Traefik also has a separate entry-point setting, forwardedHeaders.trustedIPs, which controls whether it preserves incoming X-Forwarded-* values. Configure both layers. With Kubernetes externalTrafficPolicy: Cluster, the plugin usually sees a node-SNAT address, so the node CIDR must be trusted and upstream header sanitization remains part of the security boundary.

The safe default config trusts no proxy, enables only X-Forwarded-For, rejects malformed trusted headers, and denies unresolved or non-public client addresses. Provider-specific headers are opt-in. See Client IP resolution for the full algorithm and the Traefik-specific X-Real-IP behavior.

Install a versioned plugin

State Geo Block is listed in the Traefik Plugin Catalog. Configure a released tag in Traefik's static configuration; do not use a branch name in production.

experimental:
  plugins:
    stateGeoBlock:
      moduleName: github.com/vikewoods/traefik-plugin-state-geo
      version: v1.2.0-rc.1

The alias stateGeoBlock is operator-selected but must be used consistently in the dynamic Middleware configuration.

Kubernetes quick start

Mount a current City MMDB into every Traefik pod, configure Traefik's entry-point trusted IPs, and then create the Middleware:

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: state-geo-block
  namespace: traefik-system
spec:
  plugin:
    stateGeoBlock:
      dbPath: /data/geolite/GeoLite2-City.mmdb
      databaseReloadInterval: 1m
      cacheSize: 50000
      cacheTTL: 15m
      trustedProxyCIDRs:
        - 10.17.1.0/24
      clientIPHeaders:
        - X-Forwarded-For
      rejectInvalidClientIPHeaders: true
      blockNonUS: true
      blockUSStates: true
      blockedStates: [CA, NY]
      databaseFailurePolicy: deny
      lookupFailurePolicy: deny
      invalidClientIPPolicy: deny
      unknownCountryPolicy: deny
      unknownSubdivisionPolicy: deny
      privateIPPolicy: deny
      logLevel: info
      logClientIP: false
      whitelistedPaths:
        - /health
      whitelistedPathPrefixes:
        - /.well-known

10.17.1.0/24, /data/geolite/GeoLite2-City.mmdb, and the namespace above are specific to the audited cluster and must be changed for other installations. The complete Helm/PVC, Middleware, IngressRoute, standard Ingress, update, and canary instructions are in Kubernetes deployment.

Configuration

Field Default Description
dbPath empty Path inside the Traefik container to a compatible City-schema MMDB.
databaseReloadInterval 1m Minimum interval between request-driven file replacement checks; minimum 1s.
cacheSize 1000 Per-Middleware exact-IP LRU entry bound; 0 disables, maximum 100000. High-cardinality ingress can start near 50000 and tune from memory/hit-rate evidence.
cacheTTL 15m Positive decision TTL when caching is enabled.
clientIPHeaders XFF Ordered trusted client-IP sources. Cloudflare, True Client IP, Forwarded, X-Real-IP, and custom headers are opt-in.
trustedProxyCIDRs empty Immediate peers permitted to supply client-IP headers.
rejectInvalidClientIPHeaders true Send a present-but-invalid trusted header to invalidClientIPPolicy; false warns and tries the next source.
blockNonUS true Deny known non-US countries.
blockUSStates true Apply blockedStates and unknown-subdivision policy to US records.
blockedStates empty Two-letter US subdivision codes to deny, normalized to uppercase.
whitelistedIPs empty Exact IPv4/IPv6 addresses and CIDRs that bypass geography decisions.
whitelistedPaths empty Normalized exact request paths that bypass all other decisions.
whitelistedPathPrefixes empty Normalized, segment-safe path prefixes that bypass all other decisions.
templateHTML built-in Inline escaped HTML template; supports {{STATE}} or {{.State}}.
templatePath empty Mounted HTML template path; mutually exclusive with templateHTML.
databaseFailurePolicy legacy allow, deny, error, or deprecated compatibility mode legacy.
lookupFailurePolicy allow allow or deny when an MMDB lookup returns an error.
invalidClientIPPolicy deny allow or deny when RemoteAddr or a strict trusted header is unusable.
unknownCountryPolicy allow allow or deny when lookup returns no country.
unknownSubdivisionPolicy deny allow or deny for a US record without a subdivision.
privateIPPolicy deny allow, lookup, or deny for private, loopback, link-local, or unspecified clients.
logLevel info off, error, warn, info, or debug; info records deny decisions without client IPs by default.
logClientIP false Include resolved client IPs in structured logs.
failOpen true Deprecated bridge used only by databaseFailurePolicy: legacy.

Invalid state, IP/CIDR, path, duration, policy, template, and header configuration fails Middleware construction instead of being silently skipped. See Failure policies, Database lifecycle, and Middleware hardening for exact behavior.

Database requirements

The repository does not ship a production database. Operators may mount a MaxMind GeoLite2-City or GeoIP2-City database, or a compact stategeodb compliance artifact. The compact format supplies country data globally and the first subdivision only for US records, matching this middleware's country-first, US-state-only policy inputs; all allow, deny, unknown-data, and failure behavior still comes entirely from plugin configuration.

Mount the selected artifact read-only into Traefik and replace it atomically. The plugin detects a size or modification-time change, validates the replacement, retains the last known-good reader if reload fails, and invalidates cached decisions after a successful swap. See MMDB compatibility and Database lifecycle for the exact schema, validation evidence, cache generation behavior, and memory model. GeoLite2 users remain responsible for the MaxMind GeoLite terms.

Upgrade and development

Published v1.1 configurations require migration because trusted headers, path prefixes, invalid rules, failure policies, and bundled data behavior changed. The release candidate also hardens defaults from the withdrawn v2 prereleases. Read Migration from v1 before upgrading.

go test ./...
go test -race ./...
go vet ./...
golangci-lint run ./...
govulncheck ./...
gosec -quiet ./...
./scripts/traefik-smoke-test.sh

The smoke test loads the source through Traefik v3.7.1 and v3.7.6 interpreted local-plugin runtimes and verifies real IPv4/IPv6 decisions. See Contributing and the release checklist.

License

State Geo Block is licensed under the Apache License 2.0. Third-party fixture and dependency licenses are documented in THIRD_PARTY_NOTICES.md.

Documentation

Overview

Package traefik_plugin_state_geo provides a Traefik HTTP middleware that makes allow or deny decisions from a MaxMind city database.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func New

func New(ctx context.Context, next http.Handler, config *Config, name string) (http.Handler, error)

New constructs a State Geo Block middleware instance.

Types

type Config

type Config struct {
	BlockedStates                []string `json:"blockedStates,omitempty"`
	WhitelistedIPs               []string `json:"whitelistedIPs,omitempty"`
	WhitelistedPaths             []string `json:"whitelistedPaths,omitempty"`
	WhitelistedPathPrefixes      []string `json:"whitelistedPathPrefixes,omitempty"`
	ClientIPHeaders              []string `json:"clientIPHeaders,omitempty"`
	TrustedProxyCIDRs            []string `json:"trustedProxyCIDRs,omitempty"`
	RejectInvalidClientIPHeaders bool     `json:"rejectInvalidClientIPHeaders,omitempty"`
	DBPath                       string   `json:"dbPath,omitempty"`
	DatabaseReloadInterval       string   `json:"databaseReloadInterval,omitempty"`
	CacheSize                    int      `json:"cacheSize,omitempty"`
	CacheTTL                     string   `json:"cacheTTL,omitempty"`
	TemplatePath                 string   `json:"templatePath,omitempty"`
	TemplateHTML                 string   `json:"templateHTML,omitempty"`
	DatabaseFailurePolicy        string   `json:"databaseFailurePolicy,omitempty"`
	LookupFailurePolicy          string   `json:"lookupFailurePolicy,omitempty"`
	InvalidClientIPPolicy        string   `json:"invalidClientIPPolicy,omitempty"`
	UnknownCountryPolicy         string   `json:"unknownCountryPolicy,omitempty"`
	UnknownSubdivisionPolicy     string   `json:"unknownSubdivisionPolicy,omitempty"`
	PrivateIPPolicy              string   `json:"privateIPPolicy,omitempty"`
	LogLevel                     string   `json:"logLevel,omitempty"`
	LogClientIP                  bool     `json:"logClientIP,omitempty"`
	FailOpen                     bool     `json:"failOpen,omitempty"` // Deprecated: use DatabaseFailurePolicy.
	BlockNonUS                   bool     `json:"blockNonUS,omitempty"`
	BlockUSStates                bool     `json:"blockUSStates,omitempty"`
}

Config defines the State Geo Block middleware configuration.

func CreateConfig

func CreateConfig() *Config

CreateConfig returns the middleware's documented default configuration.

Directories

Path Synopsis
internal
manifestcheck command
Command manifestcheck constructs the middleware from manifest testData JSON.
Command manifestcheck constructs the middleware from manifest testData JSON.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL