This episode covers policy-based access control for the gateway, JWT authentication and external auth integration, and mutual TLS and certificate validation to secure routes end to end.

How tightly do you control who is allowed to call your APIs? Episode 12 covers security policies and access control in Multigress: restricting access with declarative authorization mechanisms, validating JWT and integrating external auth, and securing the gateway path with mutual TLS and certificate validation. An open route without a policy is an invitation for anyone. After this episode, every endpoint will have a clear answer: who may enter, how identity is proven, and whether communication is encrypted from gateway to backend.
Multigress provides an authorization mechanism similar to the AuthorizationPolicy in Istio, but it attaches directly to Gateway API objects. The pattern is simple: declare rules in a SecurityPolicy, then attach it to an HTTPRoute via targetRefs.
apiVersion: gateway.multigress.io/v1
kind: SecurityPolicy
metadata:
name: api-authorization
namespace: platform
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: api-route
authorization:
rules:
- when:
- key: request.headers.authorization
values: ["Bearer *"]
action: ALLOW
- action: DENYThe policy above applies a default deny: only requests with a Bearer-type Authorization header are allowed, everything else is rejected. The first rule with action: ALLOW matches the Bearer * pattern, then the final rule with action: DENY closes off everything that doesn't match.
Rules are evaluated in order from the top. The first matching rule determines the final result, so arrange rules from most specific to most general. Closing the list with action: DENY means a configuration mistake can't turn into a security gap.
kubectl apply -f security-policy.yaml
kubectl get securitypolicy -n platformThe kubectl apply -f security-policy.yaml command applies the policy, then kubectl get securitypolicy verifies it's recorded. When an Authorization header doesn't match any rule, the response is 403 Forbidden.
Validating JWT at the gateway means tokens are checked before the request reaches the application. Issuer and JWKS configuration are set up in the authentication policy.
apiVersion: gateway.multigress.io/v1
kind: SecurityPolicy
metadata:
name: api-jwt-policy
namespace: platform
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: api-route
jwt:
providers:
- name: keycloak
issuer: https://auth.example.com/realms/platform
jwksUri: https://auth.example.com/realms/platform/protocol/openid-connect/certs
defaultProvider: keycloakWith the configuration above, every request must carry a JWT signed by the Keycloak realm. Signature and expiry are verified at the gateway, not in the application, so the application doesn't need to implement token validation.
There are times when JWT validation alone isn't enough, for example when authorization must check business data. Multigress can delegate the decision to an external service through the external auth mechanism, such as an Open Policy Agent server.
apiVersion: gateway.multigress.io/v1
kind: SecurityPolicy
metadata:
name: api-ext-auth
namespace: platform
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: api-route
extAuth:
service: authz.opa.svc.cluster.local
port: 8181
path: /v1/data/platform/allowThis policy sends request metadata to the OPA service before forwarding to the backend. If the external auth service answers with a deny decision, the request is aborted at the gateway and the backend never receives it.
apiVersion: gateway.multigress.io/v1
kind: SecurityPolicy
metadata:
name: api-jwt-policy
namespace: platform
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: api-route
jwt:
providers:
- name: keycloak
issuer: https://auth.example.com/realms/platform
jwksUri: https://auth.example.com/realms/platform/protocol/openid-connect/certs
claimToHeaders:
- claim: email
header: X-User-EmailThe email claim is moved to the X-User-Email header, so the application just reads the header without re-parsing the token. This pattern also hides token details from internal services.
JWT protects the client side, while mutual TLS secures the path between the gateway and the backend. Both sides present certificates, so the backend is confident that only the gateway can reach it.
apiVersion: gateway.multigress.io/v1
kind: BackendTrafficPolicy
metadata:
name: backend-mtls
namespace: platform
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: api-route
tls:
mode: Mutate
caCertificates:
- name: ca-bundle
clientCertificate:
name: gateway-client-certThis policy configures TLS mutation: the connection to the backend is encrypted and verified with the CA bundle, while the gateway presents its own client certificate. Mutate mode means the original connection from the client is forwarded as a new TLS connection to the backend.
On certain listeners, you can require a client certificate during HTTPS termination. Clients that don't present a valid certificate are rejected at the handshake stage.
openssl s_client -connect api.example.com:443 \
-cert client.crt -key client.key \
-CAfile ca.pem -stateThe openssl s_client -connect api.example.com:443 -cert client.crt command tests the TLS handshake with a client certificate. Look for the line Verify return code: 0 in the output to confirm the certificate was accepted by the CA.
Warning
Mutual TLS adds certificate management overhead. Make sure CA and client certificate rotation runs on a schedule before rolling out mTLS widely.
Episode 12 completed the identity and access security side: authorization policies define who may pass, JWT and external auth validate credentials, and mTLS secures the path to the backend with certificate validation.
The key takeaways:
In the next episode 13 we'll discuss egress & service-to-service routing — directing outbound traffic through an egress gateway, managing external service access, and applying NetworkPolicy. The security policies you built will be extended outward from the cluster.