Gateway Authorization Rule Actions (ALLOW, DENY, AUDIT)
Gateway HTTP servers can carry local authorization rules under
spec.http[].authorization.local.rules. Each rule decides whether a request may
reach the backend, based on the caller's JWT claims, the request path and method,
and other attributes of the request.
Every rule carries an action that says what happens when the rule matches:
ALLOW, DENY or AUDIT. action defaults to ALLOW, so rules written before
this field existed keep their previous behaviour.
Rule actions apply to local authorization rules on ingress, tier-1 and
application gateway servers. Egress gateway authorization
(spec.egressAuthorization) does not support rule actions.
Rule actions
| Action | Effect when the rule matches |
|---|---|
ALLOW | The request is permitted. ALLOW rules form an allow list: once a server has at least one ALLOW rule, any request that no ALLOW rule permits is refused. This is the default. |
DENY | The request is refused, whatever the ALLOW rules say. Refusals are evaluated before the allow list. |
AUDIT | The request is recorded and the decision is left to the other rules. An AUDIT rule never permits or refuses anything, so naming a path in an audit rule does not make that path reachable. |
A few consequences worth keeping in mind:
- A server only becomes an allow list when it has an
ALLOWrule of its own. A server whose rules are allAUDIT(or allDENY) keeps whatever access it would have had with no rules at all, so adding an audit rule never takes a server offline. - A rule that states none of
from,toorwhenmatches every request the server handles. That is how anAUDITrule records a whole server, or aDENYrule closes one. AnALLOWrule must say what it permits. DENYrules are evaluated beforeAUDITrules, so a request that is refused by aDENYrule is still recorded by a matchingAUDITrule.
Matching conditions
Each rule matches on any combination of the following. All parts that are set must match.
| Field | Matches |
|---|---|
from | The caller — for example a JWT iss, sub or claim. |
to.paths / to.methods | The request path and HTTP method. Paths support exact match, prefix match with a trailing * (/api*), suffix match with a leading * (*.js), and a single * for any path. |
to.notPaths / to.notMethods | Paths and methods that must not match for the rule to apply. Same path matching as to.paths. |
when | An attribute of the request — see below. |
A when condition has a key, naming the attribute, and values /
notValues:
when:
- key: "request.auth.claims[group]" # holds when the claim is "eng" or "sre"
values: ["eng", "sre"]
- key: "request.headers[authorization]" # holds when the header is absent
notValues: ["*"]
Common keys include request.auth.claims[<name>], request.headers[<name>],
connection.sni and source.ip. HTTP/2 pseudo-headers are addressable, so
request.headers[:authority] and request.headers[:path] work; unlike
to.paths, request.headers[:path] includes the query string. values uses
the same exact / prefix / suffix / * matching as to.paths. A single * in
values requires the attribute to be present; in notValues it requires the
attribute to be absent.
when conditions are scoped to their serverEach rule is scoped to the server that declares it, by adding that server's host
and port. A when condition can narrow a rule within its server but cannot
widen it to other servers. This matters for conditions on
request.headers[:authority] and destination.port: on a server with a
specific hostname, a condition naming a different host never matches. On a
server whose hostname is *, such a condition works as written.
Example
The following ingress gateway server permits engineering callers to /api,
refuses contractors outright, and records every write that arrives without an
Authorization header — without making those writes reachable.
apiVersion: gateway.tsb.tetrate.io/v2
kind: Gateway
metadata:
name: bookinfo-gw-ingress
group: bookinfo-gw
workspace: bookinfo-ws
tenant: tetrate
spec:
workloadSelector:
namespace: bookinfo
labels:
app: tsb-gateway-bookinfo
http:
- name: bookinfo
port: 8443
hostname: bookinfo.tetrate.com
tls:
mode: SIMPLE
secretName: bookinfo-certs
authentication:
jwt:
issuer: issuer1.example
audiences: ["tetrateapp"]
jwksUri: https://issuer1.example/.well-known/jwks.json
authorization:
local:
rules:
- name: eng-only # action defaults to ALLOW
from:
- jwt:
iss: issuer1.example
to:
- paths: ["/api*"]
when:
- key: "request.auth.claims[group]"
values: ["eng"]
- name: block-contractors
action: DENY
when:
- key: "request.auth.claims[employment]"
values: ["contractor"]
- name: audit-anonymous-writes
action: AUDIT
to:
- methods: ["POST", "PUT", "PATCH", "DELETE"]
notPaths: ["/health"]
when:
- key: "request.headers[authorization]"
notValues: ["*"]
routing:
rules:
- route:
serviceDestination:
host: 'bookinfo/productpage.bookinfo.svc.cluster.local'
Rule evaluation order
For a request that reaches the server, rules are evaluated in this order:
DENYrules — if any matches, the request is refused.AUDITrules — every matching rule records the request. No allow or deny decision is made here.ALLOWrules — if the server has anyALLOWrule, the request must match one of them or it is refused. If the server has noALLOWrule, the request keeps the access it would have had with no rules.
Where AUDIT (and DENY) matches are recorded
An AUDIT rule takes no part in the allow/deny decision. Its only effect is to
mark the request so that it is recorded.
For DENY and AUDIT rules, the gateway proxy reports the rule's name as the
effective authorization policy ID. That name appears in the proxy's access log
record for the request, so the record shows which rule matched. Give an
AUDIT rule a name that describes what it watches (for example
audit-anonymous-writes above), because that name is what you will search for in
the logs.
Those access-log records are emitted by the gateway's Envoy proxy alongside its normal request access logs, and are forwarded to the TSB telemetry store where access logging to it is enabled.
Records for requests that a DENY rule refused are already surfaced as access
denials. Distinct handling of AUDIT records for requests that were permitted
is still being completed on the telemetry backend; until then, the marker and
rule name are present in the raw access log record but are not yet a dedicated
queryable field.
Rule name uniqueness
Rule names must be unique within a server. For DENY and AUDIT rules they must
also be unique across servers that share a filter chain, among rules with the
same action. Plaintext servers on the same port share a filter chain, because
Istio serves them from one listener.