Skip to content

Commit 24966b8

Browse files
committed
Update API and Security Considerations for ReferenceGrant integration
1 parent 40b8224 commit 24966b8

File tree

1 file changed

+116
-9
lines changed

1 file changed

+116
-9
lines changed

docs/proposals/authentication-filter.md

Lines changed: 116 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,12 @@ type BasicAuth struct {
143143
// Key is the key within the Secret that contains the htpasswd data.
144144
Key string `json:"key,omitempty"`
145145

146+
// SecretRef allows referencing a Secret in the same or another namespace.
147+
// When namespace is set and differs from the filter's namespace, a ReferenceGrant in the target namespace is required.
148+
//
149+
// +optional
150+
SecretRef *NamespacedSecretKeyReference `json:"secretRef,omitempty"`
151+
146152
// Realm used by NGINX `auth_basic`.
147153
// Configures "realm="<realm_value>" in WWW-Authenticate header in error page location.
148154
//
@@ -267,13 +273,13 @@ type JWTFileKeySource struct {
267273
// Exactly one of ConfigMapRef or SecretRef must be set.
268274
//
269275
// +optional
270-
ConfigMapRef *LocalObjectReference `json:"configMapRef,omitempty"`
276+
ConfigMapRef *NamespacedObjectReference `json:"configMapRef,omitempty"`
271277

272278
// SecretRef references a Secret containing the JWKS (with optional key).
273279
// Exactly one of ConfigMapRef or SecretRef must be set.
274280
//
275281
// +optional
276-
SecretRef *SecretKeyReference `json:"secretRef,omitempty"`
282+
SecretRef *NamespacedSecretKeyReference `json:"secretRef,omitempty"`
277283

278284
// MountPath is the path where NGF will mount the data into the NGINX container.
279285
// Used in `auth_jwt_key_file` directive.
@@ -324,16 +330,16 @@ type JWKSCache struct {
324330
// +optional
325331
KeysZoneName *string `json:"keysZoneName,omitempty"`
326332

327-
// KeysZoneSize is the size of the cache keys zone (e.g., "10m").
333+
// KeysZoneSize is the size of the cache keys zone (e.g. "10m").
328334
// This is required to avoid unbounded allocations.
329335
KeysZoneSize string `json:"keysZoneSize"`
330336

331-
// MaxSize limits the total size of the cache (e.g., "50m").
337+
// MaxSize limits the total size of the cache (e.g. "50m").
332338
//
333339
// +optional
334340
MaxSize *string `json:"maxSize,omitempty"`
335341

336-
// Inactive defines the inactivity timeout before cached items are evicted (e.g., "10m").
342+
// Inactive defines the inactivity timeout before cached items are evicted (e.g. "10m").
337343
//
338344
// +optional
339345
Inactive *string `json:"inactive,omitempty"`
@@ -469,14 +475,32 @@ type LocalObjectReference struct {
469475
Name string `json:"name"`
470476
}
471477

472-
// SecretKeyReference references a Secret and an optional key.
478+
// SecretKeyReference references a Secret and an optional key.
473479
type SecretKeyReference struct {
474480
Name string `json:"name"`
475481

476-
// Key within the Secret data. If omitted, controller defaults apply (e.g., "jwks.json").
482+
// Key within the Secret data. If omitted, controller defaults apply (e.g. "jwks.json").
477483
Key string `json:"key,omitempty"`
478484
}
479485

486+
// NamespacedObjectReference references an object by name with an optional namespace.
487+
// If namespace is omitted, it defaults to the AuthenticationFilter's namespace.
488+
type NamespacedObjectReference struct {
489+
// +optional
490+
Namespace *string `json:"namespace,omitempty"`
491+
Name string `json:"name"`
492+
}
493+
494+
// NamespacedSecretKeyReference references a Secret and optional key, with an optional namespace.
495+
// If namespace differs from the filter's, a ReferenceGrant in the target namespace is required.
496+
type NamespacedSecretKeyReference struct {
497+
// +optional
498+
Namespace *string `json:"namespace,omitempty"`
499+
Name string `json:"name"`
500+
// +optional
501+
Key *string `json:"key,omitempty"`
502+
}
503+
480504
// AuthenticationFilterStatus defines the state of AuthenticationFilter.
481505
type AuthenticationFilterStatus struct {
482506
// Controllers is a list of Gateway API controllers that processed the AuthenticationFilter
@@ -1056,9 +1080,93 @@ Users that attach an `AuthenticaitonFilter` to a HTTPRoute/GRPCRoute should be a
10561080

10571081
Any exmaple configurations and deployments for the `AuthenticationFilter` should enable HTTPS at the Gateway level by default.
10581082

1059-
The `mountPath` for local JWKS should be mounted to a fixed location (e.g., /etc/nginx/keys).
1083+
The `mountPath` for local JWKS should be mounted to a fixed location (e.g. /etc/nginx/keys).
10601084
The `fileName` for a local JWKS should be sanatized to a pattern of [A-Za-z0-9._-].
10611085

1086+
### Namespace isolataion and cross-namespace references
1087+
Both Auth and Local JWKS should only have access to Secrets and ConfigMaps in the same namespace by default.
1088+
1089+
Cross-namespace references are allowed only when authorized via a Gateway API ReferenceGrant in the target namespace.
1090+
1091+
Controller behavior:
1092+
- Same-namespace references are permitted without a grant.
1093+
- For cross-namespace references, the controller MUST verify a ReferenceGrant exists in the target namespace:
1094+
- from: group=gateway.nginx.org, kind=AuthenticationFilter, namespace=<filter-namespace>
1095+
- to: group="", kind=(Secret|ConfigMap), name=<target-name>
1096+
- If no valid grant is found, the filter status should update the status to `Accepted=False` with `reason=RefNotPermitted` and a clear message. We should avoid rendering any NGINX configuration in this scenario.
1097+
1098+
Example: Grant BasicAuth in app-ns to read a Secret in security-ns
1099+
```yaml
1100+
apiVersion: gateway.networking.k8s.io/v1
1101+
kind: ReferenceGrant
1102+
metadata:
1103+
name: allow-basic-auth-secret
1104+
namespace: security-ns # target namespace where the Secret lives
1105+
spec:
1106+
from:
1107+
- group: gateway.nginx.org
1108+
kind: AuthenticationFilter
1109+
namespace: app-ns
1110+
to:
1111+
- group: "" # core API group
1112+
kind: Secret
1113+
name: basic-auth-users
1114+
```
1115+
1116+
AuthenticationFilter referencing the cross-namespace Secret
1117+
```yaml
1118+
apiVersion: gateway.nginx.org/v1alpha1
1119+
kind: AuthenticationFilter
1120+
metadata:
1121+
name: basic-auth
1122+
namespace: app-ns
1123+
spec:
1124+
type: Basic
1125+
basic:
1126+
secretRef:
1127+
namespace: security-ns
1128+
name: basic-auth-users
1129+
key: htpasswd
1130+
realm: "Restricted"
1131+
```
1132+
1133+
Example: Grant JWT file-based JWKS in keys-ns to filter in app-ns
1134+
```yaml
1135+
apiVersion: gateway.networking.k8s.io/v1
1136+
kind: ReferenceGrant
1137+
metadata:
1138+
name: allow-jwks-configmap
1139+
namespace: keys-ns
1140+
spec:
1141+
from:
1142+
- group: gateway.nginx.org
1143+
kind: AuthenticationFilter
1144+
namespace: app-ns
1145+
to:
1146+
- group: "" # core API group
1147+
kind: ConfigMap
1148+
name: jwt-keys
1149+
```
1150+
1151+
AuthenticationFilter referencing cross-namespace JWKS ConfigMap
1152+
```yaml
1153+
apiVersion: gateway.nginx.org/v1alpha1
1154+
kind: AuthenticationFilter
1155+
metadata:
1156+
name: jwt-auth
1157+
namespace: app-ns
1158+
spec:
1159+
type: JWT
1160+
jwt:
1161+
mode: File
1162+
file:
1163+
configMapRef:
1164+
namespace: keys-ns
1165+
name: jwt-keys
1166+
mountPath: /etc/nginx/keys
1167+
fileName: jwks.json
1168+
```
1169+
10621170
### Remote JWKS
10631171

10641172
Proxy cache TTL should be configurable and set to a resonable default, reducing periods of stale cached JWKs.
@@ -1099,7 +1207,6 @@ Detailed header breakdown:
10991207
- Pragma: "no-cache"
11001208
- This header is commonly paired with `Cache-Control: "no-store"` for broad coverage. It acts as an additional signal for older intermediaries that do not honor Cache-Control.
11011209
1102-
11031210
### Validation
11041211
11051212
When referencing an `AuthenticationFilter` in either a HTTPRoute or GRPCRoute, it is important that we ensure all configurable fields are validated, and that the resulting NGINX configuration is correct and secure

0 commit comments

Comments
 (0)