Allow and block client IPs in NGINX Gateway Fabric with AccessPolicy

—

by

in , ,

AccessPolicy in NGINX Gateway Fabric lets you allow or block client IP addresses and CIDR ranges on a Gateway or on individual routes. If you already use NGINX Gateway Fabric to manage traffic into your cluster, you can now control which clients reach your apps in the same place, with a policy attached to the Gateways and routes you already have. AccessPolicy is new in NGINX Gateway Fabric 2.8.0. Its API version is v1alpha1, so fields might change in later releases.

How AccessPolicy works

An AccessPolicy is a list of rules, where each rule is a client IP or a CIDR range. One field, action, decides what the list means. Set it to Deny and you have a denylist. Set it to Allow and you have an allowlist.

You attach a policy to a Gateway, an HTTPRoute, or a GRPCRoute in the same namespace. It’s an inherited policy, so a Gateway policy applies to every route attached to it, and a route policy applies only to that route. This post uses both, because how they combine is the main thing to understand.

The examples use a Gateway named gateway and an HTTPRoute named coffee that sends cafe.example.com/coffee to a demo app. The AccessPolicy guide has the manifests for these resources.

Note: The examples in this post are illustrative. For full instructions, see the AccessPolicy guide.

Keeping a range out at the Gateway

A rule that should apply to every app goes on the Gateway. This denylist has two rules, one for the 198.51.100.0/24 range and one for the single address 203.0.113.7:

kubectl apply -f - <<EOF
apiVersion: gateway.nginx.org/v1alpha1
kind: AccessPolicy
metadata:
  name: gateway-denylist
spec:
  targetRefs:
  - group: gateway.networking.k8s.io
    kind: Gateway
    name: gateway
  action: Deny
  rules:
  - name: blocked-range
    source:
      type: IPAddress
      ipAddress:
        address: 198.51.100.0/24
  - name: blocked-client
    source:
      type: IPAddress
      ipAddress:
        address: 203.0.113.7
EOF

To confirm the policy is accepted, run kubectl describe accesspolicies.gateway.nginx.org gateway-denylist and check that the Accepted condition is True. The Gateway also gets an AccessPolicyAffected condition when a valid AccessPolicy targets it.

Making the coffee route office-only

A rule for a single app goes on its route. This allowlist limits the coffee route to an IPv4 and an IPv6 office range:

kubectl apply -f - <<EOF
apiVersion: gateway.nginx.org/v1alpha1
kind: AccessPolicy
metadata:
  name: coffee-allowlist
spec:
  targetRefs:
  - group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: coffee
  action: Allow
  rules:
  - name: office-network
    source:
      type: IPAddress
      ipAddress:
        address: 192.0.2.0/24
  - name: office-network-ipv6
    source:
      type: IPAddress
      ipAddress:
        address: 2001:db8::/32
EOF

Check the policy status the same way. The Accepted condition should be True, and the coffee route gets an AccessPolicyAffected condition.

Client IPs behind a load balancer

Traffic usually reaches the Gateway through a load balancer or proxy. NGINX matches AccessPolicy rules against the client IP it receives, which in that setup is the proxy’s address. To match rules against the original client IP, configure rewriteClientIP on the NginxProxy resource. The PROXY protocol and RewriteClientIP guide has the steps.

Testing the policies

The requests below simulate clients from specific addresses with an X-Forwarded-For header. This only works when rewriteClientIP is configured on the NginxProxy resource, described above. If you have real clients in these ranges, test with those instead. GW_IP and GW_PORT are your Gateway’s address and port.

A client from the blocked range:

curl --resolve cafe.example.com:$GW_PORT:$GW_IP -H "X-Forwarded-For: 198.51.100.25" http://cafe.example.com:$GW_PORT/coffee

NGINX returns 403 Forbidden. The address is also outside the coffee allowlist, but the Gateway Deny rule matches first, so NGINX blocks the request without checking the allowlist.

A client from the office:

curl --resolve cafe.example.com:$GW_PORT:$GW_IP -H "X-Forwarded-For: 192.0.2.10" http://cafe.example.com:$GW_PORT/coffee
Server address: 10.244.0.22:8080
Server name: coffee-654ddf664b-6mwtb
Date: 09/Oct/2026:12:00:00 +0000
URI: /coffee
Request ID: abc123def456ghi789jkl012

This one reaches the coffee Pod.

How Gateway and route policies combine

NGINX Gateway Fabric turns each AccessPolicy into NGINX allow and deny directives. NGINX checks them in order and stops at the first match. When both the Gateway and a route have a policy, NGINX Gateway Fabric merges them for that route. A route without a policy uses the Gateway’s rules. If neither has a policy, the route accepts all clients.

Deny rules are checked first and add up across levels. A route can’t unblock an address the Gateway denies, even if a route Allow rule lists the same address. Allow rules narrow across levels. A route can restrict the Gateway’s allowlist but can’t widen it.

GatewayRouteWhat the route ends up with
DenyDenyBoth sets of Deny rules
DenyAllowGateway denies first, then the route’s allowlist
AllowDenyRoute denies first, then the Gateway’s allowlist
AllownoneThe Gateway’s allowlist as is
noneAllowThe route’s allowlist as is
AllowAllowOnly addresses that are in both lists

In the Allow and Allow case, NGINX Gateway Fabric programs only the overlap between the two lists. If the lists partly overlap, the route policy gets a Programmed condition with the reason PartiallyProgrammed. If the lists don’t overlap at all, NGINX Gateway Fabric programs no allow directives for the route, so NGINX blocks all of its traffic. The Programmed condition is then False with the reason Overridden. In both cases, the condition message names the Gateway Allow policy.

Each AccessPolicy has a single action. You can attach several policies to one resource, and NGINX Gateway Fabric evaluates them together. Deny rules are additive, so every Deny policy applies. If the policies overlap in a way that can’t be programmed, such as a route Allow range outside the Gateway’s allowlist, NGINX Gateway Fabric reports it in the policy’s status conditions.

Common issues

A route allowlist blocks all traffic. Check the Gateway’s allowlist. The route policy’s Programmed condition has the reason Overridden, and the message names the Gateway Allow policy. If the route’s addresses don’t fall within the Gateway’s allowlist, nothing is programmed for the route. If the Gateway has no Allow policy, the route’s addresses apply as they are.

The policy status is Invalid. Accepted is False with reason Invalid, and the message says the value “must be a valid IPv4/IPv6 address or CIDR range”. It names the field, such as spec.rules[0].source.ipAddress.address. The target doesn’t get AccessPolicyAffected from that policy. Fix the address and apply the policy again.

What’s next

The full AccessPolicy guide has the demo manifests and every field. From there, the custom policies overview shows how AccessPolicy fits with NGINX Gateway Fabric’s other policies, and the AccessPolicy API reference has the complete spec.

To report a bug or share feedback, open an issue or start a discussion on the NGINX Gateway Fabric GitHub repo. For more NGINX Gateway Fabric materials, check the links below:

NGINX Community Forum