Skip to content

Commit ac860eb

Browse files
authored
Merge branch 'main' into 20240807-ff-doc-fix
2 parents 632e4a6 + 06b9507 commit ac860eb

File tree

15 files changed

+544
-351
lines changed

15 files changed

+544
-351
lines changed

config/crd/bases/k8s.nginx.org_policies.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,12 @@ spec:
159159
type: string
160160
clientSecret:
161161
type: string
162+
endSessionEndpoint:
163+
type: string
162164
jwksURI:
163165
type: string
166+
postLogoutRedirectURI:
167+
type: string
164168
redirectURI:
165169
type: string
166170
scope:

deploy/crds.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -361,8 +361,12 @@ spec:
361361
type: string
362362
clientSecret:
363363
type: string
364+
endSessionEndpoint:
365+
type: string
364366
jwksURI:
365367
type: string
368+
postLogoutRedirectURI:
369+
type: string
366370
redirectURI:
367371
type: string
368372
scope:

docs/content/configuration/policy-resource.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,8 @@ spec:
583583
authEndpoint: https://idp.example.com/openid-connect/auth
584584
tokenEndpoint: https://idp.example.com/openid-connect/token
585585
jwksURI: https://idp.example.com/openid-connect/certs
586+
endSessionEndpoint: https://idp.example.com/openid-connect/logout
587+
postLogoutRedirectURI: /
586588
accessTokenEnable: true
587589
```
588590

@@ -607,7 +609,7 @@ The configuration in the example doesn't enable TLS and the synchronization betw
607609

608610
#### Limitations
609611

610-
The OIDC policy defines a few internal locations that can't be customized: `/_jwks_uri`, `/_token`, `/_refresh`, `/_id_token_validation`, `/logout`, `/_logout`. In addition, as explained below `/_codexch` is the default value for redirect URI, but can be customized. Specifying one of these locations as a route in the VirtualServer or VirtualServerRoute will result in a collision and NGINX Plus will fail to reload.
612+
The OIDC policy defines a few internal locations that can't be customized: `/_jwks_uri`, `/_token`, `/_refresh`, `/_id_token_validation`, `/logout`. In addition, as explained below, `/_codexch` is the default value for redirect URI, and `/_logout` is the default value for post logout redirect URI, both of which can be customized. Specifying one of these locations as a route in the VirtualServer or VirtualServerRoute will result in a collision and NGINX Plus will fail to reload.
611613

612614
{{% table %}}
613615
|Field | Description | Type | Required |
@@ -617,9 +619,11 @@ The OIDC policy defines a few internal locations that can't be customized: `/_jw
617619
|``authEndpoint`` | URL for the authorization endpoint provided by your OpenID Connect provider. | ``string`` | Yes |
618620
|``authExtraArgs`` | A list of extra URL arguments to pass to the authorization endpoint provided by your OpenID Connect provider. Arguments must be URL encoded, multiple arguments may be included in the list, for example ``[ arg1=value1, arg2=value2 ]`` | ``string[]`` | No |
619621
|``tokenEndpoint`` | URL for the token endpoint provided by your OpenID Connect provider. | ``string`` | Yes |
622+
|``endSessionEndpoint`` | URL provided by your OpenID Connect provider to request the end user be logged out. | ``string`` | No |
620623
|``jwksURI`` | URL for the JSON Web Key Set (JWK) document provided by your OpenID Connect provider. | ``string`` | Yes |
621624
|``scope`` | List of OpenID Connect scopes. The scope ``openid`` always needs to be present and others can be added concatenating them with a ``+`` sign, for example ``openid+profile+email``, ``openid+email+userDefinedScope``. The default is ``openid``. | ``string`` | No |
622625
|``redirectURI`` | Allows overriding the default redirect URI. The default is ``/_codexch``. | ``string`` | No |
626+
|``postLogoutRedirectURI`` | URI to redirect to after the logout has been performed. Requires ``endSessionEndpoint``. The default is ``/_logout``. | ``string`` | No |
623627
|``zoneSyncLeeway`` | Specifies the maximum timeout in milliseconds for synchronizing ID/access tokens and shared values between Ingress Controller pods. The default is ``200``. | ``int`` | No |
624628
|``accessTokenEnable`` | Option of whether Bearer token is used to authorize NGINX to access protected backend. | ``boolean`` | No |
625629
{{% /table %}}

examples/custom-resources/oidc/README.md

+16-20
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,7 @@ To set up Keycloak:
8484
kubectl apply -f client-secret.yaml
8585
```
8686

87-
## Step 6 - Deploy the OIDC Policy
88-
89-
Create a policy with the name `oidc-policy` that references the secret from the previous step:
90-
91-
```console
92-
kubectl apply -f oidc.yaml
93-
```
94-
95-
## Step 7 - Configure NGINX Plus Zone Synchronization and Resolver
87+
## Step 6 - Configure NGINX Plus Zone Synchronization and Resolver
9688

9789
In this step we configure:
9890

@@ -110,23 +102,19 @@ Steps:
110102
kubectl apply -f nginx-ingress-headless.yaml
111103
```
112104

113-
1. Get the cluster IP of the KubeDNS service:
105+
1. Apply the ConfigMap `nginx-config.yaml`, which contains a stream snippet that enables zone synchronization and the resolver using the kube-dns service.
114106

115107
```console
116-
kubectl -n kube-system get svc kube-dns
108+
kubectl apply -f nginx-config.yaml
117109
```
118110

119-
```text
120-
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
121-
kube-dns ClusterIP 10.4.0.10 <none> 53/UDP,53/TCP 9d
122-
```
111+
## Step 7 - Deploy the OIDC Policy
123112

124-
1. Edit the ConfigMap `nginx-config.yaml`, replacing the `<kube-dns-ip>` with the IP obtained in the previous step.
125-
1. Apply the ConfigMap:
113+
Create a policy with the name `oidc-policy` that references the secret from the previous step:
126114

127-
```console
128-
kubectl apply -f nginx-config.yaml
129-
```
115+
```console
116+
kubectl apply -f oidc.yaml
117+
```
130118

131119
## Step 8 - Configure Load Balancing
132120

@@ -146,3 +134,11 @@ Note that the VirtualServer references the policy `oidc-policy` created in Step
146134
![keycloak](./keycloak.png)
147135
1. Once logged in, you will be redirected to the web application and get a response from it. Notice the field `User ID`
148136
in the response, this will match the ID for your user in Keycloak. ![webapp](./webapp.png)
137+
138+
## Step 10 - Log Out
139+
140+
1. To log out, navigate to `https://webapp.example.com/logout`. Your session will be terminated, and you will be
141+
redirected to the default post logout URI `https://webapp.example.com/_logout`.
142+
![logout](./logout.png)
143+
1. To confirm that you have been logged out, navigate to `https://webapp.example.com`. You will be redirected to
144+
Keycloak to log in again.

examples/custom-resources/oidc/keycloak_setup.md

+8-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ This guide will help you configure KeyCloak using Keycloak's API:
77

88
**Notes**:
99

10-
- This guide has been tested with keycloak 19.0.2 and later. If you modify `keycloak.yaml` to use an older version, Keycloak may not start correctly or the commands in this guide may not work as expected. The Keycloak OpenID endpoints `oidc.yaml` might also be different in older versions of Keycloak.
10+
- This guide has been tested with keycloak 19.0.2 and later. If you modify `keycloak.yaml` to use an older version,
11+
Keycloak may not start correctly or the commands in this guide may not work as expected. The Keycloak OpenID
12+
endpoints `oidc.yaml` might also be different in older versions of Keycloak.
1113
- if you changed the admin username and password for Keycloak in `keycloak.yaml`, modify the commands accordingly.
1214
- The instructions use [`jq`](https://stedolan.github.io/jq/).
1315

@@ -26,12 +28,13 @@ Steps:
2628
```
2729

2830
Ensure the request was successful and the token is stored in the shell variable by running:
31+
2932
```console
3033
echo $TOKEN
3134
```
3235

33-
***Note***: The access token lifespan is very short. If it expires between commands, retrieve it again with the
34-
command above.
36+
***Note***: The access token lifespan is very short. If it expires between commands, retrieve it again with the
37+
command above.
3538

3639
1. Create the user `nginx-user`:
3740

@@ -42,10 +45,10 @@ Steps:
4245
1. Create the client `nginx-plus` and retrieve the secret:
4346

4447
```console
45-
SECRET=`curl -sS -k -X POST -d '{ "clientId": "nginx-plus", "redirectUris": ["https://webapp.example.com:443/_codexch"] }' -H "Content-Type:application/json" -H "Authorization: bearer ${TOKEN}" https://${KEYCLOAK_ADDRESS}/realms/master/clients-registrations/default | jq -r .secret`
48+
SECRET=`curl -sS -k -X POST -d '{ "clientId": "nginx-plus", "redirectUris": ["https://webapp.example.com:443/_codexch"], "attributes": {"post.logout.redirect.uris": "https://webapp.example.com:443/*"}}' -H "Content-Type:application/json" -H "Authorization: bearer ${TOKEN}" https://${KEYCLOAK_ADDRESS}/realms/master/clients-registrations/default | jq -r .secret`
4649
```
4750

48-
If everything went well you should have the secret stored in $SECRET. To double check run:
51+
If everything went well you should have the secret stored in $SECRET. To double check run:
4952

5053
```console
5154
echo $SECRET
388 KB
Loading

examples/custom-resources/oidc/nginx-config.yaml

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@ metadata:
55
namespace: nginx-ingress
66
data:
77
stream-snippets: |
8-
resolver <kube-dns-ip> valid=5s;
98
server {
109
listen 12345;
1110
listen [::]:12345;
1211
zone_sync;
1312
zone_sync_server nginx-ingress-headless.nginx-ingress.svc.cluster.local:12345 resolve;
1413
}
15-
resolver-addresses: <kube-dns-ip>
14+
resolver-addresses: kube-dns.kube-system.svc.cluster.local
1615
resolver-valid: 5s

examples/custom-resources/oidc/oidc.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ spec:
99
authEndpoint: https://keycloak.example.com/realms/master/protocol/openid-connect/auth
1010
tokenEndpoint: http://keycloak.default.svc.cluster.local:8080/realms/master/protocol/openid-connect/token
1111
jwksURI: http://keycloak.default.svc.cluster.local:8080/realms/master/protocol/openid-connect/certs
12+
endSessionEndpoint: https://keycloak.example.com/realms/master/protocol/openid-connect/logout
1213
scope: openid+profile+email
1314
accessTokenEnable: true

internal/configs/version2/http.go

+12-10
Original file line numberDiff line numberDiff line change
@@ -127,16 +127,18 @@ type EgressMTLS struct {
127127

128128
// OIDC holds OIDC configuration data.
129129
type OIDC struct {
130-
AuthEndpoint string
131-
ClientID string
132-
ClientSecret string
133-
JwksURI string
134-
Scope string
135-
TokenEndpoint string
136-
RedirectURI string
137-
ZoneSyncLeeway int
138-
AuthExtraArgs string
139-
AccessTokenEnable bool
130+
AuthEndpoint string
131+
ClientID string
132+
ClientSecret string
133+
JwksURI string
134+
Scope string
135+
TokenEndpoint string
136+
EndSessionEndpoint string
137+
RedirectURI string
138+
PostLogoutRedirectURI string
139+
ZoneSyncLeeway int
140+
AuthExtraArgs string
141+
AccessTokenEnable bool
140142
}
141143

142144
// APIKey holds API key configuration.

internal/configs/version2/nginx-plus.virtualserver.tmpl

+2-1
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,14 @@ server {
9090
include oidc/oidc.conf;
9191

9292
set $oidc_pkce_enable 0;
93-
set $oidc_logout_redirect "/_logout";
93+
set $oidc_logout_redirect "{{ $oidc.PostLogoutRedirectURI }}";
9494
set $oidc_hmac_key "{{ $s.VSName }}";
9595
set $zone_sync_leeway {{ $oidc.ZoneSyncLeeway }};
9696

9797
set $oidc_authz_endpoint "{{ $oidc.AuthEndpoint }}";
9898
set $oidc_authz_extra_args "{{ $oidc.AuthExtraArgs }}";
9999
set $oidc_token_endpoint "{{ $oidc.TokenEndpoint }}";
100+
set $oidc_end_session_endpoint "{{ $oidc.EndSessionEndpoint }}";
100101
set $oidc_jwt_keyfile "{{ $oidc.JwksURI }}";
101102
set $oidc_scopes "{{ $oidc.Scope }}";
102103
set $oidc_client "{{ $oidc.ClientID }}";

internal/configs/virtualserver.go

+16-10
Original file line numberDiff line numberDiff line change
@@ -1306,6 +1306,10 @@ func (p *policiesCfg) addOIDCConfig(
13061306
if redirectURI == "" {
13071307
redirectURI = "/_codexch"
13081308
}
1309+
postLogoutRedirectURI := oidc.PostLogoutRedirectURI
1310+
if postLogoutRedirectURI == "" {
1311+
postLogoutRedirectURI = "/_logout"
1312+
}
13091313
scope := oidc.Scope
13101314
if scope == "" {
13111315
scope = "openid"
@@ -1316,16 +1320,18 @@ func (p *policiesCfg) addOIDCConfig(
13161320
}
13171321

13181322
oidcPolCfg.oidc = &version2.OIDC{
1319-
AuthEndpoint: oidc.AuthEndpoint,
1320-
AuthExtraArgs: authExtraArgs,
1321-
TokenEndpoint: oidc.TokenEndpoint,
1322-
JwksURI: oidc.JWKSURI,
1323-
ClientID: oidc.ClientID,
1324-
ClientSecret: string(clientSecret),
1325-
Scope: scope,
1326-
RedirectURI: redirectURI,
1327-
ZoneSyncLeeway: generateIntFromPointer(oidc.ZoneSyncLeeway, 200),
1328-
AccessTokenEnable: oidc.AccessTokenEnable,
1323+
AuthEndpoint: oidc.AuthEndpoint,
1324+
AuthExtraArgs: authExtraArgs,
1325+
TokenEndpoint: oidc.TokenEndpoint,
1326+
JwksURI: oidc.JWKSURI,
1327+
EndSessionEndpoint: oidc.EndSessionEndpoint,
1328+
ClientID: oidc.ClientID,
1329+
ClientSecret: string(clientSecret),
1330+
Scope: scope,
1331+
RedirectURI: redirectURI,
1332+
PostLogoutRedirectURI: postLogoutRedirectURI,
1333+
ZoneSyncLeeway: generateIntFromPointer(oidc.ZoneSyncLeeway, 200),
1334+
AccessTokenEnable: oidc.AccessTokenEnable,
13291335
}
13301336
oidcPolCfg.key = polKey
13311337
}

0 commit comments

Comments
 (0)