Skip to content

Commit 21b5611

Browse files
committed
Add stretch goals
1 parent 9e6b3c9 commit 21b5611

File tree

1 file changed

+169
-143
lines changed

1 file changed

+169
-143
lines changed

docs/proposals/authentication-filter.md

Lines changed: 169 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -225,38 +225,6 @@ type JWTAuth struct {
225225
//
226226
// +optional
227227
OnFailure *AuthFailureResponse `json:"onFailure,omitempty"`
228-
229-
// Require defines claims that must match exactly (e.g. iss, aud).
230-
// These translate into NGINX maps and auth_jwt_require directives.
231-
// Example directives and maps:
232-
//
233-
// auth_jwt_require $valid_jwt_iss;
234-
// auth_jwt_require $valid_jwt_aud;
235-
//
236-
// map $jwt_claim_iss $valid_jwt_iss {
237-
// "https://issuer.example.com" 1;
238-
// "https://issuer.example1.com" 1;
239-
// default 0;
240-
// }
241-
// map $jwt_claim_aud $valid_jwt_aud {
242-
// "api" 1;
243-
// "cli" 1;
244-
// default 0;
245-
// }
246-
//
247-
// +optional
248-
Require *JWTRequiredClaims `json:"require,omitempty"`
249-
250-
// TokenSource defines where the client presents the token.
251-
// Defaults to reading from Authorization header.
252-
//
253-
// +optional
254-
TokenSource *TokenSource `json:"tokenSource,omitempty"`
255-
256-
// Propagation controls identity header propagation to upstream and header stripping.
257-
//
258-
// +optional
259-
Propagation *JWTPropagation `json:"propagation,omitempty"`
260228
}
261229

262230
// FileKeySource specifies local JWKS key configuration.
@@ -336,66 +304,6 @@ const (
336304
TokenTypeNested TokenType = "nested"
337305
)
338306

339-
// JWTRequiredClaims specifies exact-match requirements for claims.
340-
type JWTRequiredClaims struct {
341-
// Issuer (iss) required exact value.
342-
//
343-
// +optional
344-
Iss *string `json:"iss,omitempty"`
345-
346-
// Audience (aud) required exact value.
347-
//
348-
// +optional
349-
Aud *string `json:"aud,omitempty"`
350-
}
351-
352-
// JWTTokenSourceType selects where the JWT token is read from.
353-
// +kubebuilder:validation:Enum=Header;Cookie;QueryArg
354-
type TokenSourceType string
355-
356-
const (
357-
// Read from Authorization header (Bearer). Default.
358-
TokenSourceModeHeader TokenSourceMode = "Header"
359-
// Read from a cookie named tokenName.
360-
TokenSourceModeCookie TokenSourceMode = "Cookie"
361-
// Read from a query arg named tokenName.
362-
TokenSourceModeQueryArg TokenSourceMode = "QueryArg"
363-
)
364-
365-
// JWTTokenSource specifies where tokens may be read from and the name when required.
366-
type TokenSource struct {
367-
// Mode selects the token source.
368-
// +kubebuilder:default=Header
369-
Type TokenSourceType `json:"mode"`
370-
371-
// TokenName is the cookie or query parameter name when Mode=Cookie or Mode=QueryArg.
372-
// Ignored when Mode=Header.
373-
//
374-
// +optional
375-
// +kubebuilder:default=access_token
376-
TokenName string `json:"tokenName,omitempty"`
377-
}
378-
379-
// HeaderValue defines a header name and a value (may reference NGINX variables).
380-
type HeaderValue struct {
381-
Name string `json:"name"`
382-
ValueFrom string `json:"valueFrom"`
383-
}
384-
385-
// JWTPropagation controls identity header propagation and header stripping.
386-
type JWTPropagation struct {
387-
// AddIdentityHeaders defines headers to add on success with values.
388-
// typically derived from jwt_claim_* variables.
389-
//
390-
// +optional
391-
AddIdentityHeaders []HeaderValue `json:"addIdentityHeaders,omitempty"`
392-
393-
// StripAuthorization removes the incoming Authorization header before proxying.
394-
//
395-
// +optional
396-
StripAuthorization *bool `json:"stripAuthorization,omitempty"`
397-
}
398-
399307
// AuthScheme enumerates supported WWW-Authenticate schemes.
400308
// +kubebuilder:validation:Enum=Basic;Bearer
401309
type AuthScheme string
@@ -847,56 +755,6 @@ http {
847755
}
848756
```
849757

850-
#### Stretch goal - Additional Optional Fields
851-
852-
`require`, `tokenSource` and `propagation` are some additional fields we may choose to include.
853-
These fields are going to be added as stretch goals for the initial implementation.
854-
This is to ensure the minimal required capabilties can be focused on.
855-
856-
```yaml
857-
apiVersion: gateway.nginx.org/v1alpha1
858-
kind: AuthenticationFilter
859-
metadata:
860-
name: jwt-auth
861-
spec:
862-
type: JWT
863-
jwt:
864-
realm: "Restricted"
865-
keys:
866-
mode: Remote
867-
remote:
868-
url: https://issuer.example.com/.well-known/jwks.json
869-
870-
# Required claims (exact matching done via maps in NGINX; see config)
871-
require:
872-
iss:
873-
- "https://issuer.example.com"
874-
- "https://issuer2.example.com"
875-
aud:
876-
- "api"
877-
- "cli"
878-
879-
# Where client presents the token
880-
# By defaults to reading from Authorization header (Bearer)
881-
tokenSource:
882-
type: Header
883-
# Alternative: read from a cookie named tokenName
884-
# type: Cookie
885-
# tokenName: access_token
886-
# Alternative: read from a query arg named tokenName
887-
# type: QueryArg
888-
# tokenName: access_token
889-
890-
# Identity propagation to backend and header stripping
891-
propagation:
892-
addIdentityHeaders:
893-
- name: X-User-Id
894-
valueFrom: "$jwt_claim_sub"
895-
- name: X-User-Email
896-
valueFrom: "$jwt_claim_email"
897-
stripAuthorization: true # Optionally remove client Authorization header before proxy_pass
898-
```
899-
900758
### Caching configuration
901759

902760
Users may also choose to change the caching configuration set by `proxy_cache_path`.
@@ -981,7 +839,7 @@ spec:
981839

982840
If a user attempts to attach a JWT tpye AuthenticationFilter while using NGINX OSS, the rule referncing the filter will be `Rejected`.
983841

984-
This can appear as `UnresolvedRef` to inform the user that the rule has been `Rejected`.
842+
This can use the status `RouteConditionPartiallyInvalid` defined in the Gateway API here: https://github.com/nginx/nginx-gateway-fabric/blob/main/internal/controller/state/conditions/conditions.go#L402
985843

986844
## Testing
987845

@@ -1121,6 +979,174 @@ If implementations choose a strict interpretation of filter ordering, they MUST
1121979
document that behavior.
1122980
```
1123981

982+
## Stretch Goals
983+
984+
### Cross namespace acess
985+
986+
When referencing secrets for Basic Auth and JWT Auth, the initial implementation will use `LocalObjectReference`.
987+
988+
Future updates to this will use the `NamespacedSecretKeyReference` in conjunction with `ReferenceGrants` to support access to secrets in different namespace`
989+
990+
Struct for `NamespacedSecretKeyReference`:
991+
992+
```go
993+
// NamespacedSecretKeyReference references a Secret and optional key, with an optional namespace.
994+
// If namespace differs from the filter's, a ReferenceGrant in the target namespace is required.
995+
type NamespacedSecretKeyReference struct {
996+
// +optional
997+
Namespace *string `json:"namespace,omitempty"`
998+
Name string `json:"name"`
999+
// +optional
1000+
Key *string `json:"key,omitempty"`
1001+
}
1002+
```
1003+
1004+
### Additional Fields for JWT
1005+
1006+
`require`, `tokenSource` and `propagation` are some additional fields that may be incldued in future updates to the API.
1007+
These fields allow for more customization of how the JWT auth behavtes, but aren't required for the minial delivery of JWT Auth.
1008+
1009+
Example of what implementation of these fields might look like:
1010+
```yaml
1011+
apiVersion: gateway.nginx.org/v1alpha1
1012+
kind: AuthenticationFilter
1013+
metadata:
1014+
name: jwt-auth
1015+
spec:
1016+
type: JWT
1017+
jwt:
1018+
realm: "Restricted"
1019+
keys:
1020+
mode: Remote
1021+
remote:
1022+
url: https://issuer.example.com/.well-known/jwks.json
1023+
1024+
# Required claims (exact matching done via maps in NGINX; see config)
1025+
require:
1026+
iss:
1027+
- "https://issuer.example.com"
1028+
- "https://issuer2.example.com"
1029+
aud:
1030+
- "api"
1031+
- "cli"
1032+
1033+
# Where client presents the token
1034+
# By defaults to reading from Authorization header (Bearer)
1035+
tokenSource:
1036+
type: Header
1037+
# Alternative: read from a cookie named tokenName
1038+
# type: Cookie
1039+
# tokenName: access_token
1040+
# Alternative: read from a query arg named tokenName
1041+
# type: QueryArg
1042+
# tokenName: access_token
1043+
1044+
# Identity propagation to backend and header stripping
1045+
propagation:
1046+
addIdentityHeaders:
1047+
- name: X-User-Id
1048+
valueFrom: "$jwt_claim_sub"
1049+
- name: X-User-Email
1050+
valueFrom: "$jwt_claim_email"
1051+
stripAuthorization: true # Optionally remove client Authorization header before proxy_pass
1052+
```
1053+
1054+
Example GoLang API changes:
1055+
```go
1056+
type JWTAuth struct {
1057+
// Require defines claims that must match exactly (e.g. iss, aud).
1058+
// These translate into NGINX maps and auth_jwt_require directives.
1059+
// Example directives and maps:
1060+
//
1061+
// auth_jwt_require $valid_jwt_iss;
1062+
// auth_jwt_require $valid_jwt_aud;
1063+
//
1064+
// map $jwt_claim_iss $valid_jwt_iss {
1065+
// "https://issuer.example.com" 1;
1066+
// "https://issuer.example1.com" 1;
1067+
// default 0;
1068+
// }
1069+
// map $jwt_claim_aud $valid_jwt_aud {
1070+
// "api" 1;
1071+
// "cli" 1;
1072+
// default 0;
1073+
// }
1074+
//
1075+
// +optional
1076+
Require *JWTRequiredClaims `json:"require,omitempty"`
1077+
1078+
// TokenSource defines where the client presents the token.
1079+
// Defaults to reading from Authorization header.
1080+
//
1081+
// +optional
1082+
TokenSource *TokenSource `json:"tokenSource,omitempty"`
1083+
1084+
// Propagation controls identity header propagation to upstream and header stripping.
1085+
//
1086+
// +optional
1087+
Propagation *JWTPropagation `json:"propagation,omitempty"`
1088+
}
1089+
1090+
// JWTRequiredClaims specifies exact-match requirements for claims.
1091+
type JWTRequiredClaims struct {
1092+
// Issuer (iss) required exact value.
1093+
//
1094+
// +optional
1095+
Iss *string `json:"iss,omitempty"`
1096+
1097+
// Audience (aud) required exact value.
1098+
//
1099+
// +optional
1100+
Aud *string `json:"aud,omitempty"`
1101+
}
1102+
1103+
// JWTTokenSourceType selects where the JWT token is read from.
1104+
// +kubebuilder:validation:Enum=Header;Cookie;QueryArg
1105+
type TokenSourceType string
1106+
1107+
const (
1108+
// Read from Authorization header (Bearer). Default.
1109+
TokenSourceModeHeader TokenSourceMode = "Header"
1110+
// Read from a cookie named tokenName.
1111+
TokenSourceModeCookie TokenSourceMode = "Cookie"
1112+
// Read from a query arg named tokenName.
1113+
TokenSourceModeQueryArg TokenSourceMode = "QueryArg"
1114+
)
1115+
1116+
// JWTTokenSource specifies where tokens may be read from and the name when required.
1117+
type TokenSource struct {
1118+
// Mode selects the token source.
1119+
// +kubebuilder:default=Header
1120+
Type TokenSourceType `json:"mode"`
1121+
1122+
// TokenName is the cookie or query parameter name when Mode=Cookie or Mode=QueryArg.
1123+
// Ignored when Mode=Header.
1124+
//
1125+
// +optional
1126+
// +kubebuilder:default=access_token
1127+
TokenName string `json:"tokenName,omitempty"`
1128+
}
1129+
// JWTPropagation controls identity header propagation and header stripping.
1130+
type JWTPropagation struct {
1131+
// AddIdentityHeaders defines headers to add on success with values.
1132+
// typically derived from jwt_claim_* variables.
1133+
//
1134+
// +optional
1135+
AddIdentityHeaders []HeaderValue `json:"addIdentityHeaders,omitempty"`
1136+
1137+
// StripAuthorization removes the incoming Authorization header before proxying.
1138+
//
1139+
// +optional
1140+
StripAuthorization *bool `json:"stripAuthorization,omitempty"`
1141+
}
1142+
1143+
// HeaderValue defines a header name and a value (may reference NGINX variables).
1144+
type HeaderValue struct {
1145+
Name string `json:"name"`
1146+
ValueFrom string `json:"valueFrom"`
1147+
}
1148+
```
1149+
11241150
## References
11251151

11261152
- [Gateway API ExternalAuthFilter GEP]((https://gateway-api.sigs.k8s.io/geps/gep-1494/))

0 commit comments

Comments
 (0)