You can install an OpenID Connect (OIDC) identity provider (IdP) such as Keycloak in your cluster. Then, configure Gloo Mesh Gateway external auth with the OIDC details. You can adapt these steps for other IdPs.

Before you begin

  1. Set up Gloo Mesh Gateway in a single cluster.
  2. Install Bookinfo and other sample apps.
  3. Configure an HTTP listener on your gateway and set up basic routing for the sample apps.

  4. Make sure that the external auth service is installed and running. If not, install the external auth service.

      kubectl get pods -A -l app=ext-auth-service
      
  5. Get the external address of your ingress gateway. The steps vary depending on the type of load balancer that backs the ingress gateway.

      export INGRESS_GW_ADDRESS=$(kubectl get svc -n gloo-mesh-gateways istio-ingressgateway -o jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}")
    echo $INGRESS_GW_ADDRESS
      

    Note: Depending on your environment, you might see <pending> instead of an external IP address. For example, if you are testing locally in kind or minikube, or if you have insufficient permissions in your cloud platform, you can instead port-forward the service port of the ingress gateway:

      kubectl -n gloo-mesh-gateways port-forward deploy/istio-ingressgateway-1-20 8081
      

Step 1: Install Keycloak

You might want to test how to restrict access to your applications to authenticated users, such as with external auth or JWT policies. You can install Keycloak in your cluster as an OpenID Connect (OIDC) provider.

The following steps install Keycloak in your cluster, and configure two user credentials as follows.

  • Username: user1, password: password, email: user1@example.com
  • Username: user2, password: password, email: user2@solo.io

Install and configure Keycloak:

  1. Create a namespace for your Keycloak deployment.

      kubectl create namespace keycloak
      
  2. Create the Keycloak deployment.

      kubectl -n keycloak apply -f https://raw.githubusercontent.com/solo-io/gloo-mesh-use-cases/main/policy-demo/oidc/keycloak.yaml
      
  3. Wait for the Keycloak rollout to finish.

      kubectl -n keycloak rollout status deploy/keycloak
      
  4. Set the Keycloak endpoint details from the load balancer service.

      export ENDPOINT_KEYCLOAK=$(kubectl -n keycloak get service keycloak -o jsonpath='{.status.loadBalancer.ingress[0].*}'):8080
    export HOST_KEYCLOAK=$(echo ${ENDPOINT_KEYCLOAK} | cut -d: -f1)
    export PORT_KEYCLOAK=$(echo ${ENDPOINT_KEYCLOAK} | cut -d: -f2)
    export KEYCLOAK_URL=http://${ENDPOINT_KEYCLOAK}
    echo $KEYCLOAK_URL
      
  5. Set the Keycloak admin token. If you see a parsing error, try running the curl command by itself. You might notice that your internet provider or network rules are blocking the requests. If so, you can update your security settings or change the network so that the request can be processed.

      export KEYCLOAK_TOKEN=$(curl -d "client_id=admin-cli" -d "username=admin" -d "password=admin" -d "grant_type=password" "$KEYCLOAK_URL/realms/master/protocol/openid-connect/token" | jq -r .access_token)
    echo $KEYCLOAK_TOKEN
      
  6. Use the admin token to configure Keycloak with the two users for testing purposes. If you get a 401 Unauthorized error, run the previous command and try again.

      # Create initial token to register the client
    read -r client token <<<$(curl -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" -X POST -H "Content-Type: application/json" -d '{"expiration": 0, "count": 1}' $KEYCLOAK_URL/admin/realms/master/clients-initial-access | jq -r '[.id, .token] | @tsv')
    export KEYCLOAK_CLIENT=${client}
    echo $KEYCLOAK_CLIENT
    
    # Register the client
    read -r id secret <<<$(curl -k -X POST -d "{ \"clientId\": \"${KEYCLOAK_CLIENT}\" }" -H "Content-Type:application/json" -H "Authorization: bearer ${token}" ${KEYCLOAK_URL}/realms/master/clients-registrations/default| jq -r '[.id, .secret] | @tsv')
    export KEYCLOAK_SECRET=${secret}
    echo $KEYCLOAK_SECRET
    
    # Add allowed redirect URIs
    curl -k -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" -X PUT -H "Content-Type: application/json" -d '{"serviceAccountsEnabled": true, "directAccessGrantsEnabled": true, "authorizationServicesEnabled": true, "redirectUris": ["*"]}' $KEYCLOAK_URL/admin/realms/master/clients/${id}
    
    # Add the group attribute in the JWT token returned by Keycloak
    curl -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" -X POST -H "Content-Type: application/json" -d '{"name": "group", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "config": {"claim.name": "group", "jsonType.label": "String", "user.attribute": "group", "id.token.claim": "true", "access.token.claim": "true"}}' $KEYCLOAK_URL/admin/realms/master/clients/${id}/protocol-mappers/models
    
    # Create first user
    curl -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" -X POST -H "Content-Type: application/json" -d '{"username": "user1", "email": "user1@example.com", "enabled": true, "attributes": {"group": "users"}, "credentials": [{"type": "password", "value": "password", "temporary": false}]}' $KEYCLOAK_URL/admin/realms/master/users
    
    # Create second user
    curl -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" -X POST -H "Content-Type: application/json" -d '{"username": "user2", "email": "user2@solo.io", "enabled": true, "attributes": {"group": "users"}, "credentials": [{"type": "password", "value": "password", "temporary": false}]}' $KEYCLOAK_URL/admin/realms/master/users
      
  7. Open the Keycloak frontend.

      open $KEYCLOAK_URL
      
  8. Log in to the admin console, and enter admin as the username and admin as your password.

  9. In the Keycloak admin console, go to Users, and verify that the users that created earlier are displayed. You might need to click on View all users to see them.

  10. In the Keycloak admin console, go to Clients, and verify that you can see a client ID that equals the output of $KEYCLOAK_CLIENT.

Step 2: Configure Keycloak

Now that you installed Keycloak and set up clients to use, configure Keycloak for certain OAuth use cases. The following instructions assume that you are still logged into the Administration Console from the previous step.

You might integrate OIDC with your apps. In such cases, you might need particular details from the OIDC provider to fully set up your apps. To use Keycloak for OAuth protection of these apps, you need certain settings and information from Keycloak.

  1. For authorization code OAuth: Confirm that you have the following environmental variables set. If not, refer to the Before you begin and Step 1: Install Keycloak sections.
      echo $CLUSTER_NAME
    echo $INGRESS_GW_IP
    echo $KEYCLOAK_CLIENT
    echo $KEYCLOAK_URL
      
  2. For access token validation: Get a JWKS URI to use for an inline OAuth policy.
    1. From the sidebar menu options, click Realm Settings.
    2. From the General tab, scroll down to the Endpoints section and open the OpenID Endpoint Configuration link. In a new tab, your browser opens to a URL similar to http://$KEYCLOAK_URL:8080/realms/master/.well-known/openid-configuration
    3. In the OpenID configuration, search for the token_endpoint field. Save the value as an environment variable, such as the following example.
        export KEYCLOAK_TOKEN_ENDPOINT=$KEYCLOAK_URL/realms/master/protocol/openid-connect/token
        
    4. In the OpenID configuration, search for the jwks_uri field, and copy this value, similar to http://$KEYCLOAK_URL:8080/realms/master/protocol/openid-connect/certs.
        export KEYCLOAK_JWKS_URI=<jwks_uri>
        
    5. In a new browser tab, open the jwks_uri that you previously copied.
    6. Copy and save the entire value of these keys as an environment variable.
        export KEYCLOAK_CERT_KEYS={"keys":[{"kid":"_YYA...","kty":"RSA","alg":"RSA-OAEP","use":"enc","n":"r4AXlC9sR..."}]}
        
  3. For the developer portal: Configure your Keycloak client with the appropriate settings for the developer portal frontend authentication.
    1. From the sidebar menu options, click Clients.
    2. Click the Client ID that matches the $KEYCLOAK_CLIENT that you previously set.
    3. From the client Settings tab, find the Access settings and update the following fields.
      • Valid redirect URIs field with * wildcard or the domain that you want to use for redirects.
      • Valid post logout redirect URIs field with * wildcard or the domain that you want to use for logout redirects.
      • Web origins field with * wildcard to allow all origins.
    4. Scroll down to the Capability config section and update the following sections:
      • Toggle the Client authentication setting to Off to enable public access.
      • In the Authentication flow section, enable the Standard Flow Enabled and Direct access grants options.
    5. At the bottom of the form, click Save. The Client successfully updated message pops up to confirm your settings are saved.
    6. From the client Advanced tab, find the Advanced settings. Set the Proof Key for Code Exchange Code Challenge Method dropdown to S256. For more information on PKCE, refer to RFC 7636.
    7. Scroll down and click Save. The Client successfully updated message pops up to confirm your settings are saved.
  4. For developer portal: Get the OIDC endpoint details.
    1. From the sidebar menu options, click Realm Settings.
    2. From the General tab, scroll down to the Endpoints section and open the OpenID Endpoint Configuration link. In a new tab, your browser opens to a URL similar to http://$KEYCLOAK_URL:8080/realms/master/.well-known/openid-configuration
    3. In the OpenID configuration, search for the token_endpoint field. Save the value as an environment variable, such as the following example.
        export TOKEN_ENDPOINT=$KEYCLOAK_URL/realms/master/protocol/openid-connect/token
        
    4. In the OpenID configuration, search for the authorization_endpoint field. Save the value as an environment variable, such as the following example.
        export AUTH_ENDPOINT=$KEYCLOAK_URL/realms/master/protocol/openid-connect/auth
        
    5. In the OpenID configuration, search for the end_session_endpoint field. Save the value as an environment variable, such as the following example.
        export LOGOUT_ENDPOINT=$KEYCLOAK_URL/realms/master/protocol/openid-connect/logout
        

Step 3: Prepare resources for external auth

Create resources that you need for external auth, such as a Gloo external auth server and route table with a label that you can use to apply policies.

  1. Create a Kubernetes secret with the Keycloak OIDC secret.
      kubectl apply -f - <<EOF
    apiVersion: v1
    kind: Secret
    metadata:
      name: oauth
      namespace: gloo-mesh
    type: extauth.solo.io/oauth
    stringData:
      client-secret: ${KEYCLOAK_SECRET
    EOF
      
  2. Create an external auth server to use for your policy. The example uses the default external auth server that you created when you installed Gloo Platform.
      kubectl apply -f - <<EOF
    apiVersion: admin.gloo.solo.io/v2
    kind: ExtAuthServer
    metadata:
      name: ext-auth-server
      namespace: gloo-mesh
    spec:
      destinationServer:
        ref:
          cluster: $CLUSTER_NAME
          name: ext-auth-service
          namespace: gloo-mesh
        port:
          name: grpc
    EOF
      
  1. Create a route table for the httpbin app and external auth policy. Note that the route table selects the virtual gateway that you created before you began, and routes to the httpbin service.
      kubectl apply -f - <<EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: RouteTable
    metadata:
      name: httpbin
      namespace: httpbin
      labels:
        expose: "true"
    spec:
      hosts:
        - '*'
      virtualGateways:
        - name: istio-ingressgateway
          namespace: bookinfo
          cluster: $CLUSTER_NAME
      workloadSelectors: []
      http:
        - name: httpbin
          labels:
            oauth: "true"
          matchers:
          - uri:
              exact: /get
          - uri:
              prefix: /callback
          forwardTo:
            destinations:
            - kind: SERVICE
              ref:
                name: httpbin
                namespace: httpbin
                cluster: $CLUSTER_NAME
              port:
                number: 8000
    EOF
      

Step 4: Create an OAuth policy

Create the external auth policy that uses Keycloak as the OIDC provider. The steps vary depending on how you want to configure the OAuth, with an authorization code or access token validation. For more information about these types, see Supported types of OAuth2.

Configure OAuth with authorization codes

Create an external auth policy that uses authorization codes, such as the following example YAML. Review the following table to understand this configuration. For more information, see the API reference docs for OidcAuthorizationCode.

  kubectl apply -f - <<EOF
apiVersion: security.policy.gloo.solo.io/v2
kind: ExtAuthPolicy
metadata:
  name: oauth-auth-code
  namespace: gloo-mesh
spec:
  applyToRoutes:
  - route:
      labels:
        oauth: "true"
  config:
    server:
      name: ext-auth-server
      namespace: gloo-mesh
      cluster: $CLUSTER_NAME
    glooAuth:
      configs:
      - oauth2:
          oidcAuthorizationCode:
            appUrl: "https://${INGRESS_GW_IP}:443"
            callbackPath: /callback
            clientId: ${KEYCLOAK_CLIENT}
            clientSecretRef:
              name: oauth
              namespace: gloo-mesh
            issuerUrl: "${KEYCLOAK_URL}/realms/master/"
            scopes:
            - email
            session:
              failOnFetchFailure: true
              redis:
                cookieName: keycloak-session
                options:
                  host: redis:6379
            headers:
              idTokenHeader: jwt
EOF
  
SettingDescription
applyToRoutesUse labels to configure which routes to apply the policy to. This example label matches the app and route from the example route table that you apply separately. If omitted and you do not have another selector such as applyToDestinations, the policy applies to all routes in the workspace.
serverThe external auth server to use for the policy.
oauth2Configure the OAuth 2.0 protocol details to use to authenticate requests. The example uses Keycloak as the external identity provider and an authorization code.
appUrlThe public URL of the app that you want to set up external auth for. This setting is used in combination with the callbackPath attribute.
callbackPathThe callback path, relative to the appUrl setting. After a user authenticates, the identity provider redirects the user to this callback URL. Gloo Gateway intercepts requests with this path, exchanges the authorization code received from the IdP for an ID token, places the ID token in a cookie on the request, and forwards the request to its original destination. Note: The callback path must have a matching route in the route table that is associated with the external auth policy. For example, you could simply have a / path-prefix route which would match any callback path. The important part of this callback “catch all” route is that the request goes through the routing filters including external auth.
clientIdThe client ID token that you got when you registered your app with the identity provider. In this example, you set the client ID before you began in the demo setup.
clientSecretRefThe Kubernetes secret that has the client secret that you got when you registered your app with the identity provider. The secret must exist on the same cluster as the ExtAuthServer resource that this policy refers to. In this example, you created the secret in an earlier step.
issuerUrlThe URL of the OpenID Connect identity provider. Gloo Gateway automatically discovers OIDC configuration by querying the .well-known/openid-configuration endpoint on the issuer_url. In this example, Gloo Gateway expects to find OIDC discovery information at "${KEYCLOAK_URL}/realms/master/".
scopesScopes to request in addition to the openid scope, such as email in this example.
sessionDetails on how to store the user session details. In this example, the cookie is stored as by the name keycloak-session in a Redis instance.
idTokenHeaderForward the ID token to the destination after successful authentication. In this example, the ID token is sent as a JWT.

Configure OAuth with access token validation

Create an external auth policy that uses access token validation. The following example YAML uses JWT validation and an inline JWKS server to provide the JWT.

  kubectl apply -f - <<EOF
apiVersion: security.policy.gloo.solo.io/v2
kind: ExtAuthPolicy
metadata:
  name: oauth-jwt-validation
  namespace: gloo-mesh
spec:
  applyToRoutes:
  - route:
      labels:
        oauth: "true"
  config:
    server:
      name: ext-auth-server
      namespace: gloo-mesh
      cluster: $CLUSTER_NAME
    glooAuth:
      configs:
      - oauth2:
          accessTokenValidation:
            jwt:
              localJwks:
                inlineString: >-
                  $KEYCLOAK_CERT_KEYS
EOF
  
SettingDescription
applyToRoutesUse labels to configure which routes to apply the policy to. This example label matches the app and route from the example route table that you apply separately. If omitted and you do not have another selector such as applyToDestinations, the policy applies to all routes in the workspace.
serverThe external auth server to use for the policy.
oauth2Configure the OAuth 2.0 protocol details to use to authenticate requests. The example uses Keycloak as the external identity provider and access token with JWT validation.
inlineStringReplace $KEYCLOAK_CERT_KEYS with the value from your Keycloak OIDC provider at $KEYCLOAK_URL/realms/master/protocol/openid-connect/certs. For steps to retrieve this value, refer to the previous section about installing Keycloak.

Step 5: Verify the OAuth policy

  1. Verify that the external auth policy is applied successfully.

    1. Review the status of the external auth policy and make sure that it shows ACCEPTED.
        kubectl get extauthpolicy -n gloo-mesh -o yaml
        
    2. Get the authconfig resource that was created for your policy and make sure that it shows ACCEPTED.
        kubectl get authconfig -n gloo-mesh -o yaml
        
      If you see a REJECTED error similar to invalid character 'k' looking for beginning of object key string, try copying the $KEYCLOAK_CERT_KEYS value manually again.
  2. Copy the output of the following command and open the path in your web browser to access the httpbin app. You are redirected to the authentication page from the Keycloak identity provider.

      echo "https://${INGRESS_GW_IP}:443/get"
      
  3. Enter the user credentials from Keycloak, such as the following values from the demo setup.

    • Username: user1
    • Password: password

You are authenticated and returned back to the httpbin home page.

Cleanup

You can optionally remove the resources that you set up as part of this guide.
  1. Remove Keycloak from your cluster.
      kubectl delete namespace keycloak
      
  2. Delete the resources that you created for the external auth policy.
      kubectl delete secret -n gloo-mesh oauth
    kubectl delete routetable -n httpbin httpbin
    kubectl delete extauthserver -n gloo-mesh ext-auth-server
    kubectl delete extauthpolicy -n gloo-mesh oauth-auth-code
    kubectl delete extauthpolicy -n gloo-mesh oauth-jwt-validation