Light Dark Auto

Enable OIDC Authentication on the Edge

Using the OIDC filter to authenticate users with Keycloak

GSL Operator

Introduction

OpenID Connect (OIDC) is a battle-tested and modern solution for handling user authentication. Greymatter makes integrating it into any tenant deployment straightforward with the GSL #OIDCPipelineFilter filter definition. The filter redirects unauthenticated users to an OIDC provider’s login page and handles token exchange and refresh afterwards.

This guide will show you how to enable this filter on a tenant edge and configure it properly. By the end of this guide, you will have a fully guarded edge with OIDC.

Although this guide specifically references enabling OIDC on an application edge node, the process and configuration for any tenant service proxy remains the same.

Prerequisites

  • A deployed tenant edge
  • A deployed Keycloak instance

You need a few items from Keycloak:

  • A realm
  • A client ID for the edge
  • The client secret for the client ID

Finally, you need to add a URL pointing to your edge into the ‘Valid Redirect URIs’ list for the client. It must conform to this format: https://{EXTERNAL_IP_OR_DNS_HOSTNAME}:{PORT}/oauth.

If you have access to the Keycloak instance, please refer to the mesh admin version under the ‘Operator’ tab to set and collect the appropriate values. Otherwise, contact your Keycloak administrator.

1. Add the OIDC Pipeline Filter

Open the GSL configuration file for your project’s edge. Select the listener that should execute the OIDC flow. Inside the listener’s filter array (add one if its not already present), insert the gsl.#OIDCPipelineFilter definition like this:

"myListener": {
    ...
    filters: [
        gsl.#OIDCPipelineFilter
    ]
}

2. Configure the OIDC Pipeline Filter

The OIDC pipeline filter requires a few configuration values to function. Since it is a filter, GSL expects configuration to get passed into the #options property. Use the & operator like this:

...
gsl.#OIDCPipelineFilter & {
    #options: {
     // Values go inside this block
    }
}
...

The basic set of values the filter needs to work are:

  • provider_host - the URL of the OIDC provider (includes the protocol, domain, and port components)
  • clientId - the id of the client registered by the OIDC provider (this is not the user’s id)
  • clientSecret - the corresponding secret for the client name inputted above (this is not the user’s password)
  • serviceURL - the URL that the user gets redirected to after successfully authenticating (matches the Valid Redirect URI in Keycloak and should )
  • realm - name of the OIDC realm

Additionally you have the choice to perform remote or local verification on the returned JSON Web Tokens (JWT) using JSON Web Key Sets (JWKS). That process is covered in the next sections.

Set the basic required values like this:

...
gsl.#OIDCPipelineFilter & {
    #options: {
        provider_host: "https://your.keycloak.provider.com"
        clientId:      "Your client id"
        clientSecret:  "Secret for the client specified by the above id"
        serviceUrl:    "https://url.for.redirect"
        realm:         "Your Realm"
    }
}
...

Remote verification offloads the JWT verification keys to an separate service instead of storing those keys locally. Keycloak comes with this functionality so we will leverage it for this guide.

Step outside the listener scope into the #Edge (or #Service) scope. Add an upstream to raw_upstreams:

gsl.#Edge & {
    ...

    raw_upstreams: {
        "remote_jwks": {
            gsl.#Upstream
            gsl.#TLSUpstream // or use another TLS scheme
            instances: [
                {
                    host: "your.keycloak.provider.com"
                    port: 80
                }
            ]
        }
    }

    "myListener": {
        ...
    }

    ...
}

Finally, add the provider_cluster field to the OIDC pipeline filter options’ definition and set it to the name of the raw upstream. In this case, it is “remote_jwks”:

gsl.#OIDCPipelineFilter & {
    #options: {
        ...
        provider_cluster: "remote_jwks"
    }
}

Local JWKS

Local verification with JWKS is the opposite of remote verification. The filter stores verification keys locally. Local verification eliminates a network hop, but means that the keys could expire, potentially disrupting network accessibility.

In Keycloak, you can manually fetch the keys using this URL:

https://KEYCLOAK_HOST:KEYCLOAK_PORT/realms/YOUR_REALM/protocol/openid-connect/certs

Copy and paste those values inside the OIDC Pipeline filter options’ definition:

    #options: {
        ...
        jwt: {
            local_jwks: {
                inline_string: "## PASTE CONTENTS HERE ##"
            }
        }
    }
}

3. Apply the Configuration Changes

Run greymatter sync --dry-run to ensure your updated configuration is valid.

If that succeeds, commit and push your changes to the remote GitOps repository.

4. Verify the Configurations

Now, attempt to load a URL behind the newly guarded edge proxy. You should immediately get redirected to the Keycloak login page.

Submit your login credentials. If the credentials are correct, then Keycloak should redirect you back to your original destination.

Conclusion

Congratulations, you have successfully guarded your tenant edge with OIDC authentication using the GSL #OIDCPipelineFilter. You can rest assured that users accessing applications within the tenant project are all authenticated.

Next Steps

To learn about additional OIDC options, please refer to the ‘GSL’ section of the filter reference page.

Introduction

Because of its control over critical mesh infrastructure, preventing unauthorized access to the core greymatter services is a priority for any administrator. An excellent solution is to guard the ingress edge with the robust and modern OpenID Connect (OIDC) user authentication flow. Greymatter makes this integration straightforward through the Operator CUE’s _enable_oidc_authentication toggle.

This guide will walk you through configuring an OIDC provider, Keycloak, to integrate with greymatter, toggling and configuring the greymatter OIDC filter, and also the JWT authentication filter. By the end of the guide you should have a fully guarded core edge with OIDC

Prerequisites

  • greymatter version 1.8.0
  • a deployed Keycloak instance

Using the greymatter operator with GitOps makes it simple to add an OIDC provider to your edge gateway. This guide will use Keycloak as the OIDC provider.

1. Configure Keycloak

In Keycloak, you will need to set up a realm and client (if you haven’t already done so) and ensure the client is using the OIDC protocol. Specifically, you must give Keycloak a URL that redirects back to your edge node.

  1. Log in to Keycloak
  2. Select the menu item named ‘Clients’
  3. From the list of client IDs, select the ID you want to associate with this edge node.
  4. Add a URL of the form https://{EXTERNAL_IP_OR_DNS_HOSTNAME}:{PORT}/oauth to the list of Valid Redirect URIs. Upon successful authentication, users will be redirected back to this address with tokens that the edge node’s OIDC filter can parse.

2. Enable OIDC Filters

In <your-org>/greymatter-core repository, open gm/outputs/edge.cue and set _enable_oidc_authentication to true.

This will enable a few filters on your edge proxy’s ingress listener:

  • OIDC Authentication - the primary filter that will connect to your OIDC provider and handle the authentication flow
  • Ensure Variables - passes headers from OIDC Authentication filter to Envoy JWT Authentication filter
  • Envoy JWT Authentication JSON Web Token (JWT) verification filter for JWT token validation and use of token claims to retrieve user identification and access policies

3. Configure OIDC Authentication

Set values in inputs.cue in <your-org>/greymatter-core repository. This will configure the OIDC Authentication filter. Locate the oidc configuration block and set the following values:

  • endpoint_host - the IP or hostname of your Keycloak server
  • endpoint_port - the port of your Keycloak server. Keep the default value.
  • domain - the external IP or hostname of your mesh
  • client_id - the ID of your client in Keycloak
  • client_secret - the secret from your client in Keycloak (credentials tab).
  • realm - the name of your realm in Keycloak

Note the client_secret is a kubernetes secret mixin that will require the creation of a secret named oidc-client-secret in the greymatter namespace. Ex:

kubectl create secret generic oidc-client-secret \
    --from-literal=client-secret=topsecret \
    -n greymatter

In addition, you may also need to set _keycloak_pre_17 field to true if using a Keycloak version less than version 17.

To configure TLS options between the filter and Keycloak, for instance, in the case of mTLS or to trust a set of privately minted certs, set a combination of these values:

  • certPath - Path to the server’s certificate (mTLS)
  • keyPath - Path to the server’s private key (mTLS)
  • caPath - Path to the server’s bundled intermediate and root CA certificates
  • insecureSkipVerify - Boolean determining whether to skip certificate verification

4. Configure Envoy JWT Authentication

In the jwt_authn_provider block in inputs.cue set the following values:

  • audiences - the name of your client in Keycloak

Determine how you want to verify JWTs issued from Keycloak. JSON Web Key Set (JWKS) is a set of keys containing the public keys used to verify these JWTs. Greymatter provides two types of configurations, local and remote JWKS verification.

Local JWKS Verification

Local JWKS Verification allows you to statically configure the key used to verify the JWTs. To do this, you can navigate to https://KEYCLOAK_HOST:KEYCLOAK_PORT/realms/YOUR_REALM/protocol/openid-connect/certs. Then paste the keys directly into the inline_string field in inputs.cue.

The benefit of this approach is that an additional network call does not need to be made to Keycloak to verify JWTs. The drawback is that, if the keys change in Keycloak, you must also update it in inputs.cue. Without doing so will cause authentication errors for your users.

Remote JWKS Verification

Remote JWKS Verification solves the drawbacks of Local JWKS Verification with only the added latency of an additional network call to Keycloak to verify JWTs. Latency will vary depending on your infrastructure set up but it generally goes unnoticed to your users.

To enable Remote JWKS Verification, comment out local_jwks in inputs.cue and the remote_jwks block.

When using remote JWKS, you will also need to add cluster, route, domain, and listener objects to your edge proxy to allow the OIDC authentication filter to validate the JWT, along with a few more changes to ensure that greymatter can discover the new cluster. To do so, uncomment the line at the top of <your-org>/greymatter-core/gm/outputs/edge.cue, along with the commented out objects. You will also need to modify the proxy object to look like the following:

#proxy & {
  proxy_key: defaults.edge.key
  domain_keys: [defaults.edge.key, EgressToRedisName, EdgeToKeycloakName]
  listener_keys: [defaults.edge.key, EgressToRedisName, EdgeToKeycloakName]
},

5. Apply the Configuration Changes.

Now that all configurations are in place, commit and push your changes to your greymatter core repository.

6. Verify the Configurations

Navigate to the greymatter dashboard through your core edge node. Keycloak will redirect you to the login page.

If all the configuration is correct, after submitting your credentials, Keycloak will forward your request back to the edge proxy and on to the dashboard.

Conclusion

Congratulations, you have successfully guarded your edge proxy with OIDC authentication using the Operator’s filter toggles. You can rest assured that users accessing greymatter core services are all authenticated.

Next Steps

To learn about more advanced OIDC options, please read the ‘Operator’ section of the OIDC filter reference page.