Notice:
This is the "latest" release of Envoy Gateway, which contains the most recent commits from the main branch.
This release might not be stable.
Please refer to the /docs documentation for the most current information.

GeoIP Authorization

This task provides instructions for configuring GeoIP-based authorization with Envoy Gateway.

GeoIP authorization uses geolocation data derived from the client IP address to determine whether a request should be allowed or denied before it is forwarded to the backend service.

Envoy Gateway introduces a new CRD called SecurityPolicy that allows the user to configure GeoIP-based authorization. This instantiated resource can be linked to a Gateway, HTTPRoute, or GRPCRoute resource.

GeoIP authorization is configured through SecurityPolicy.spec.authorization.rules[].principal.clientIPGeoLocations.

GeoIP authorization requires:

Prerequisites

Follow the steps below to install Envoy Gateway and the example manifest. Before proceeding, you should be able to query the example backend using HTTP.

Expand for instructions
  1. Install the Gateway API CRDs and Envoy Gateway using Helm:

    helm install eg oci://docker.io/envoyproxy/gateway-helm --version v0.0.0-latest -n envoy-gateway-system --create-namespace
    
  2. Install the GatewayClass, Gateway, HTTPRoute and example app:

    kubectl apply -f https://github.com/envoyproxy/gateway/releases/download/latest/quickstart.yaml -n default
    
  3. Verify Connectivity:

    Get the External IP of the Gateway:

    export GATEWAY_HOST=$(kubectl get gateway/eg -o jsonpath='{.status.addresses[0].value}')
       

    Curl the example app through Envoy proxy:

    curl --verbose --header "Host: www.example.com" http://$GATEWAY_HOST/get
       

    The above command should succeed with status code 200.

    Get the name of the Envoy service created the by the example Gateway:

    export ENVOY_SERVICE=$(kubectl get svc -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=eg -o jsonpath='{.items[0].metadata.name}')
       

    Get the deployment of the Envoy service created the by the example Gateway:

    export ENVOY_DEPLOYMENT=$(kubectl get deploy -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=eg -o jsonpath='{.items[0].metadata.name}')
       

    Port forward to the Envoy service:

    kubectl -n envoy-gateway-system port-forward service/${ENVOY_SERVICE} 8888:80 &
       

    Curl the example app through Envoy proxy:

    curl --verbose --header "Host: www.example.com" http://localhost:8888/get
       

    The above command should succeed with status code 200.

Configuration

Prepare the GeoIP database

Envoy reads GeoIP data from a local MaxMind .mmdb database file mounted into the proxy container.

This task uses a public MaxMind anonymous-IP test database. Apply the example manifest before continuing:

kubectl apply -f https://raw.githubusercontent.com/envoyproxy/gateway/latest/examples/kubernetes/geoip-anonymous-ip-db.yaml

To keep this guide readable, the full base64-encoded ConfigMap is not repeated here.

For production deployments, mount your own supported MaxMind database and update the file path in the EnvoyProxy resource accordingly.

Configure the Gateway and EnvoyProxy

The following resources create a dedicated Gateway, mount the anonymous-IP database into the Envoy proxy, and configure EnvoyProxy.spec.geoIP.provider.maxMind.anonymousIpDbSource to read it.

cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: geoip-authz-gateway
spec:
  gatewayClassName: eg
  infrastructure:
    parametersRef:
      group: gateway.envoyproxy.io
      kind: EnvoyProxy
      name: geoip-authz-proxy
  listeners:
  - name: http
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
        from: Same
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
  name: geoip-authz-proxy
spec:
  provider:
    type: Kubernetes
    kubernetes:
      envoyDeployment:
        pod:
          volumes:
          - name: geoip-db
            configMap:
              name: geoip-anonymous-ip-db
              items:
              - key: GeoIP2-Anonymous-IP-Test.mmdb
                path: GeoIP2-Anonymous-IP-Test.mmdb
        container:
          volumeMounts:
          - name: geoip-db
            mountPath: /etc/envoy/geoip
            readOnly: true
  geoIP:
    provider:
      type: MaxMind
      maxMind:
        anonymousIpDbSource:
          local:
            path: /etc/envoy/geoip/GeoIP2-Anonymous-IP-Test.mmdb
EOF

Save and apply the following resources to your cluster:

---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: geoip-authz-gateway
spec:
  gatewayClassName: eg
  infrastructure:
    parametersRef:
      group: gateway.envoyproxy.io
      kind: EnvoyProxy
      name: geoip-authz-proxy
  listeners:
  - name: http
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
        from: Same
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
  name: geoip-authz-proxy
spec:
  provider:
    type: Kubernetes
    kubernetes:
      envoyDeployment:
        pod:
          volumes:
          - name: geoip-db
            configMap:
              name: geoip-anonymous-ip-db
              items:
              - key: GeoIP2-Anonymous-IP-Test.mmdb
                path: GeoIP2-Anonymous-IP-Test.mmdb
        container:
          volumeMounts:
          - name: geoip-db
            mountPath: /etc/envoy/geoip
            readOnly: true
  geoIP:
    provider:
      type: MaxMind
      maxMind:
        anonymousIpDbSource:
          local:
            path: /etc/envoy/geoip/GeoIP2-Anonymous-IP-Test.mmdb

Create the route and SecurityPolicy

The following resources create an HTTPRoute for /geo-anonymous and attach a SecurityPolicy that denies requests identified as anonymous networks while allowing other traffic.

cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http-with-authorization-geoip-anonymous
spec:
  parentRefs:
  - name: geoip-authz-gateway
  rules:
  - matches:
    - path:
        type: Exact
        value: /geo-anonymous
    backendRefs:
    - name: backend
      port: 3000
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: authorization-geoip-anonymous
spec:
  targetRefs:
  - group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: http-with-authorization-geoip-anonymous
  authorization:
    defaultAction: Allow
    rules:
    - action: Deny
      principal:
        clientIPGeoLocations:
        - anonymous:
            isAnonymous: true
EOF

Save and apply the following resources to your cluster:

---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http-with-authorization-geoip-anonymous
spec:
  parentRefs:
  - name: geoip-authz-gateway
  rules:
  - matches:
    - path:
        type: Exact
        value: /geo-anonymous
    backendRefs:
    - name: backend
      port: 3000
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: authorization-geoip-anonymous
spec:
  targetRefs:
  - group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: http-with-authorization-geoip-anonymous
  authorization:
    defaultAction: Allow
    rules:
    - action: Deny
      principal:
        clientIPGeoLocations:
        - anonymous:
            isAnonymous: true

Verify the SecurityPolicy configuration:

kubectl get securitypolicy/authorization-geoip-anonymous -o yaml

Enable client IP detection

GeoIP authorization depends on Envoy Gateway correctly detecting the client IP address. Without ClientTrafficPolicy.spec.clientIPDetection, the clientIPGeoLocations match will not work as intended.

The following ClientTrafficPolicy tells Envoy Gateway to use the X-Forwarded-For header and trust one upstream hop:

cat <<EOF | kubectl apply -f -
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ClientTrafficPolicy
metadata:
  name: enable-client-ip-detection-geoip
spec:
  clientIPDetection:
    xForwardedFor:
      numTrustedHops: 1
  targetRefs:
  - group: gateway.networking.k8s.io
    kind: Gateway
    name: geoip-authz-gateway
EOF

Save and apply the following resource to your cluster:

---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ClientTrafficPolicy
metadata:
  name: enable-client-ip-detection-geoip
spec:
  clientIPDetection:
    xForwardedFor:
      numTrustedHops: 1
  targetRefs:
  - group: gateway.networking.k8s.io
    kind: Gateway
    name: geoip-authz-gateway

Verify the ClientTrafficPolicy configuration:

kubectl get clienttrafficpolicy/enable-client-ip-detection-geoip -o yaml

Testing

Ensure the GATEWAY_HOST environment variable from the Quickstart is set. If not, follow the Quickstart instructions to set the variable.

echo $GATEWAY_HOST

Send a request with a regular client IP that is not flagged as anonymous by the test database:

curl -v -H "Host: www.example.com" -H "X-Forwarded-For: 8.8.8.8" "http://${GATEWAY_HOST}/geo-anonymous"

The request should be allowed and return 200 OK.

Send a request with an IP that the anonymous-IP test database marks as anonymous:

curl -v -H "Host: www.example.com" -H "X-Forwarded-For: 6.1.0.3" "http://${GATEWAY_HOST}/geo-anonymous"

The request should be denied and return 403 Forbidden.

Clean-Up

Remove the resources created in this task:

kubectl delete clienttrafficpolicy/enable-client-ip-detection-geoip
kubectl delete securitypolicy/authorization-geoip-anonymous
kubectl delete httproute/http-with-authorization-geoip-anonymous
kubectl delete gateway/geoip-authz-gateway
kubectl delete envoyproxy/geoip-authz-proxy

If you applied the test GeoIP database ConfigMap, remove it as well:

kubectl delete configmap/geoip-anonymous-ip-db

Next Steps

Checkout the following related guides:


Last modified March 29, 2026: geoip docs (#8585) (945fe9f)