OIDC Authentication

This task provides instructions for configuring OpenID Connect (OIDC) authentication. OpenID Connect (OIDC) is an authentication standard built on top of OAuth 2.0. It enables EG to rely on authentication that is performed by an OpenID Connect Provider (OP) to verify the identity of a user.

Envoy Gateway introduces a new CRD called SecurityPolicy that allows the user to configure OIDC authentication. This instantiated resource can be linked to a Gateway and HTTPRoute resource.

Prerequisites

Follow the steps from the Quickstart task to install Envoy Gateway and the example manifest. Before proceeding, you should be able to query the example backend using HTTP.

Verify the Gateway status:

kubectl get gateway/eg -o yaml
egctl x status gateway -v

EG OIDC authentication requires the redirect URL to be HTTPS. Follow the Secure Gateways guide to generate the TLS certificates and update the Gateway configuration to add an HTTPS listener.

Verify the Gateway status:

kubectl get gateway/eg -o yaml

Let’s create an HTTPRoute that represents an application protected by OIDC.

cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: myapp
spec:
  parentRefs:
  - name: eg
  hostnames: ["www.example.com"]
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /myapp
    backendRefs:
    - name: backend
      port: 3000
EOF

Save and apply the following resource to your cluster:

---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: myapp
spec:
  parentRefs:
  - name: eg
  hostnames: ["www.example.com"]
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /myapp
    backendRefs:
    - name: backend
      port: 3000

Verify the HTTPRoute status:

kubectl get httproute/myapp -o yaml

OIDC Authentication for a HTTPRoute

OIDC can be configured at the Gateway level to authenticate all the HTTPRoutes that are associated with the Gateway with the same OIDC configuration, or at the HTTPRoute level to authenticate each HTTPRoute with different OIDC configurations.

This section demonstrates how to configure OIDC authentication for a specific HTTPRoute.

Register an OIDC application

This task uses Google as the OIDC provider to demonstrate the configuration of OIDC. However, EG works with any OIDC providers, including Auth0, Azure AD, Keycloak, Okta, OneLogin, Salesforce, UAA, etc.

Follow the steps in the Google OIDC documentation to register an OIDC application. Please make sure the redirect URL is set to the one you configured in the SecurityPolicy that you will create in the step below. In this example, the redirect URL is https://www.example.com:8443/myapp/oauth2/callback.

After registering the application, you should have the following information:

  • Client ID: The client ID of the OIDC application.
  • Client Secret: The client secret of the OIDC application.

Create a kubernetes secret

Next, create a kubernetes secret with the Client Secret created in the previous step. The secret is an Opaque secret, and the Client Secret must be stored in the key “client-secret”.

Note: please replace the ${CLIENT_SECRET} with the actual Client Secret that you got from the previous step.

kubectl create secret generic my-app-client-secret --from-literal=client-secret=${CLIENT_SECRET}

Create a SecurityPolicy

Please notice that the redirectURL and logoutPath must match the target HTTPRoute. In this example, the target HTTPRoute is configured to match the host www.example.com and the path /myapp, so the redirectURL must be prefixed with https://www.example.com:8443/myapp, and logoutPath must be prefixed with/myapp, otherwise the OIDC authentication will fail because the redirect and logout requests will not match the target HTTPRoute and therefore can’t be processed by the OAuth2 filter on that HTTPRoute.

Note: please replace the ${CLIENT_ID} in the below yaml snippet with the actual Client ID that you got from the OIDC provider.

cat <<EOF | kubectl apply -f -
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: oidc-example
spec:
  targetRefs:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      name: myapp
  oidc:
    provider:
      issuer: "https://accounts.google.com"
    clientID: "${CLIENT_ID}"
    clientSecret:
      name: "my-app-client-secret"
    redirectURL: "https://www.example.com:8443/myapp/oauth2/callback"
    logoutPath: "/myapp/logout"
EOF

Save and apply the following resource to your cluster:

---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: oidc-example
spec:
  targetRefs:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      name: myapp
  oidc:
    provider:
      issuer: "https://accounts.google.com"
    clientID: "${CLIENT_ID}"
    clientSecret:
      name: "my-app-client-secret"
    redirectURL: "https://www.example.com:8443/myapp/oauth2/callback"
    logoutPath: "/myapp/logout"

Verify the SecurityPolicy configuration:

kubectl get securitypolicy/oidc-example -o yaml

Testing

Port forward gateway port to localhost:

export ENVOY_SERVICE=$(kubectl get svc -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=eg -o jsonpath='{.items[0].metadata.name}')

kubectl -n envoy-gateway-system port-forward service/${ENVOY_SERVICE} 8443:443

Put www.example.com in the /etc/hosts file in your test machine, so we can use this host name to access the gateway from a browser:

...
127.0.0.1 www.example.com

Open a browser and navigate to the https://www.example.com:8443/myapp address. You should be redirected to the Google login page. After you successfully login, you should see the response from the backend service.

Clean the cookies in the browser and try to access https://www.example.com:8443/foo address. You should be able to see this page since the path /foo is not protected by the OIDC policy.

OIDC Authentication for a Gateway

OIDC can be configured at the Gateway level to authenticate all the HTTPRoutes that are associated with the Gateway with the same OIDC configuration, or at the HTTPRoute level to authenticate each HTTPRoute with different OIDC configurations.

This section demonstrates how to configure OIDC authentication for a Gateway.

Register an OIDC application

If you haven’t registered an OIDC application, follow the steps in the previous section to register an OIDC application.

Create a kubernetes secret

If you haven’t created a kubernetes secret, follow the steps in the previous section to create a kubernetes secret.

Create an HTTPRoute with a different subdomain

Let’s create another HTTPRoute in the same Gateway, but with a different subdomain.

cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: foo
spec:
  parentRefs:
  - name: eg
  hostnames: ["foo.example.com"]
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: backend
      port: 3000
EOF

Save and apply the following resource to your cluster:

---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: foo
spec:
  parentRefs:
  - name: eg
  hostnames: ["foo.example.com"]
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /foo
    backendRefs:
    - name: backend
      port: 3000

Verify the HTTPRoute status:

kubectl get httproute/foo -o yaml

Create a SecurityPolicy

Create or update the SecurityPolicy to target the Gateway instead of the HTTPRoute. Please notice that the redirectURL and logoutPath must match one of the HTTPRoutes associated with the Gateway. In this example, the target Gateway has three HTTPRoutes associated with it, one with the host www.example.com and the path /myapp, one with the host www.example.com and the path /, and one with the host foo.example.com and the path /. Any of these HTTPRoutes can be used to match the redirectURL and logoutPath.

By default, the access token and ID token cookies are set to the host of the request, excluding subdomains. To allow the token cookies to be shared across subdomains and prevent users from having to log in again when switching between subdomains, the cookieDomain field needs to be set to the root domain. In this example, the root domain is example.com.

cat <<EOF | kubectl apply -f -
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: oidc-example
spec:
  targetRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: eg
  oidc:
    provider:
      issuer: "https://accounts.google.com"
    clientID: "${CLIENT_ID}"
    clientSecret:
      name: "my-app-client-secret"
    redirectURL: "https://www.example.com:8443/myapp/oauth2/callback"
    logoutPath: "/myapp/logout"
    cookieDomain: "example.com"
EOF

Save and apply the following resource to your cluster:

---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: oidc-example
spec:
  targetRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: eg
  oidc:
    provider:
      issuer: "https://accounts.google.com"
    clientID: "${CLIENT_ID}"
    clientSecret:
      name: "my-app-client-secret"
    redirectURL: "https://www.example.com:8443/myapp/oauth2/callback"
    logoutPath: "/myapp/logout"
    cookieDomain: "example.com"

Verify the SecurityPolicy configuration:

kubectl get securitypolicy/oidc-example -o yaml

Update the Listener TLS certificate to support multiple subdomains

Create a multi-domain wildcard certificate for *.example.com.

openssl req -out wildcard.csr -newkey rsa:2048 -nodes -keyout wildcard.key -subj "/CN=*.example.com/O=example organization"
openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in wildcard.csr -out wildcard.crt

Replace the TLS certificate of the Gateway with the wildcard certificate.

kubectl delete secret example-cert
kubectl create secret tls example-cert --key=wildcard.key --cert=wildcard.crt

Testing

If you haven’t done so, follow the steps in the previous section to port forward gateway port to localhost and put www.example.com in the /etc/hosts file in your test machine.

Also, put foo.example.com in the /etc/hosts file in your test machine.

...
127.0.0.1 foo.example.com

Open a browser and navigate to the https://www.example.com:8443/myapp address. You should be redirected to the Google login page. After you successfully login, you should see the response from the backend service.

You can also try to access https://foo.example.com:8443 and https://www.example.com:8443/bar addresses. You should be able to see the response from the backend service since these HTTPRoutes are also protected by the same OIDC config, and the cookies are shared across subdomains.

Clean-Up

Follow the steps from the Quickstart to uninstall Envoy Gateway and the example manifest.

Delete the SecurityPolicy, the secret and the HTTPRoute:

kubectl delete securitypolicy/oidc-example
kubectl delete secret/my-app-client-secret
kubectl delete httproute/myapp
kubectl delete httproute/foo

Next Steps

Checkout the Developer Guide to get involved in the project.