Hydra
Let users authenticate with your app by using an access token from ORY Hydra.
Let users authenticate with your app by using an access token from ORY Hydra.
You might control access to your APIs with access tokens. Users can authenticate and authorize access through an OpenID Connect (OIDC) compliant authentication system, such as ORY Hydra. The authentication system issues an access token. Users add the access token in their requests to your app.
Gloo Mesh Gateway accepts the request and validates the token by using the authentication system’s introspection endpoint. If the access token is authorized to perform the requested action, the request is returned successfully. Otherwise, the request is denied.
If you import or export resources across workspaces, your policies might not apply. For more information, see Import and export policies.
Before you begin
This guide assumes that you use the same names for components like clusters, workspaces, and namespaces as in the getting started. If you have different names, make sure to update the sample configuration files in this guide.
- Set up Gloo Mesh Gateway in a single cluster.
- Install Bookinfo and other sample apps.
Configure an HTTP listener on your gateway and set up basic routing for the sample apps.
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
Install Hydra
To set up authentication, you need an OpenID Connect (OIDC) provider to use with Gloo Gateway. For demonstration purposes, you can deploy ORY Hydra in your demo cluster.
Add the Ory Helm repository to your cluster.
helm repo add ory https://k8s.ory.sh/helm/charts helm repo update
Deploy the Hydra Helm chart.
This example uses an in-memory database and disables SSL for demonstration purposes. Do not use this setup for production.helm install \ --set 'hydra.config.secrets.system={$(LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | base64 | head -c 32)}' \ --set 'hydra.config.dsn=memory' \ --set 'hydra.config.urls.self.issuer=http://public.hydra.localhost/' \ --set 'hydra.config.urls.login=http://example-idp.localhost/login' \ --set 'hydra.config.urls.consent=http://example-idp.localhost/consent' \ --set 'hydra.config.urls.logout=http://example-idp.localhost/logout' \ --set 'ingress.public.enabled=true' \ --set 'ingress.admin.enabled=true' \ --set 'hydra.dangerousForceHttp=true' \ --set 'image.tag=latest-sqlite' \ hydra-token-example \ ory/hydra
Verify that the Hydra pods are running. In the service ports, note that
admin
endpoint runs on port 4445 and thepublic
endpoint runs on port 4444. You use theadmin
endpoint to create a client ID and password and to validate the token. You use thepublic
endpoint to generate an access token.kubectl get all -l app.kubernetes.io/name=hydra -n default
Example output:
NAME READY STATUS RESTARTS AGE pod/hydra-token-example-cdcf57f87-zpq9q 1/1 Running 0 111s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/hydra-token-example-admin ClusterIP 10.108.3.142 <none> 4445/TCP 111s service/hydra-token-example-public ClusterIP 10.108.12.219 <none> 4444/TCP 111s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/hydra-token-example 1/1 1 1 111s NAME DESIRED CURRENT READY AGE replicaset.apps/hydra-token-example-cdcf57f87 1 1 1 111s
Create the OIDC credentials
Now that you have an OIDC provider running, you can create the credentials.
Enable port-forwarding for the administrative endpoint on port 4445.
kubectl port-forward deploy/hydra-token-example 4445
In a new tab in your terminal, send a request to the admin endpoint to create a client ID and secret.
curl -X POST http://127.0.0.1:4445/clients \ -H 'Content-Type: application/json' \ -H 'Accept: application/json' \ -d '{"client_id": "my-client", "client_secret": "secret", "grant_types": ["client_credentials"]}'
Example output:
{"client_id":"my-client","client_name":"","client_secret":"secret","redirect_uris":null,"grant_types":["client_credentials"],"response_types":null,"scope":"offline_access offline openid","audience":[],"owner":"","policy_uri":"","allowed_cors_origins":[],"tos_uri":"","client_uri":"","logo_uri":"","contacts":null,"client_secret_expires_at":0,"subject_type":"public","jwks":{},"token_endpoint_auth_method":"client_secret_basic","userinfo_signed_response_alg":"none","created_at":"2022-05-24T21:36:11Z","updated_at":"2022-05-24T21:36:10.78725Z","metadata":{}}
Enable port-forwarding for the public endpoint on port 4444.
kubectl port-forward deploy/hydra-token-example 4444
In a new tab in your terminal, send a request to the public endpoint to create an access token. The access token uses the client ID and secret that you created in the previous step.
curl -X POST http://127.0.0.1:4444/oauth2/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ -H 'Accept: application/json' \ -u my-client:secret \ -d 'grant_type=client_credentials' | jq .access_token -r
Set the access token as an environment variable.
#SET VARIABLE export HYDRA_ACCESS_TOKEN=<_EB6xI-hnCryL_D...>
Check that the access token works by using the introspection path of the admin endpoint. The introspection path is the same path that Gloo Gateway uses to check the validity of access tokens.
curl -X POST http://127.0.0.1:4445/oauth2/introspect \ -H 'Content-Type: application/x-www-form-urlencoded' \ -H 'Accept: application/json' \ -d "token=$HYDRA_ACCESS_TOKEN" | jq
Example output:
{ "active": true, "client_id": "my-client", "sub": "my-client", "exp": 1653432108, "iat": 1653428508, "nbf": 1653428508, "aud": [], "iss": "http://public.hydra.localhost/", "token_type": "Bearer", "token_use": "access_token" }
Configure an OAuth policy
You can do the following steps in a different order, depending on when you want the policy to take effect. For example, you might want the policy to always take effect as soon as the route is created. To do so, you can create the policy before you add the route to the route table.
Create an external auth server to use for your policy.
kubectl apply -f - <<EOF apiVersion: admin.gloo.solo.io/v2 kind: ExtAuthServer metadata: name: ext-auth-server namespace: bookinfo spec: destinationServer: port: number: 8083 ref: cluster: $CLUSTER_NAME name: ext-auth-service namespace: gloo-mesh EOF
Create an external auth policy that points to the introspection URL for access token validation.
kubectl apply -f -<<EOF apiVersion: security.policy.gloo.solo.io/v2 kind: ExtAuthPolicy metadata: name: ratings-hydra namespace: bookinfo spec: applyToRoutes: - route: labels: route: ratings config: server: name: ext-auth-server namespace: bookinfo cluster: $CLUSTER_NAME glooAuth: configs: - oauth2: accessTokenValidation: introspectionUrl: http://hydra-token-example-admin.default:4445/oauth2/introspect EOF
Review the following table to understand this configuration. For more information, see the API reference.
Setting Description applyToRoutes
Use 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.accessTokenValidation
Configure the details to validate the access token. If the token is missing or invalid, Gloo Gateway denies the request. In this example, the introspection URL is set to the OIDC provider value, the Hydra admin port. You can use the internal hostname of the Hydra admin service, because the request comes from Gloo Gateway’s external auth pod that has access to Kubernetes DNS. Send a request to the
ratings
app without providing an access token. Because you enabled OAuth, the request fails with a403 Forbidden
HTTP error code.Send the request again, this time with an invalid token value. Again, the request fails with a
403 Forbidden
error code.Send the request once more, this time with the access token that you previously created. The request succeeds with a
200
HTTP response and the body of the Bookinfo homepage.
Good job, you used an access token to authenticate your request! As you plan your production scenario, keep in mind a few things about access tokens. Your app likely sends a request to get its own access token, instead of you providing one directly in the header of a request. Typically, you scope the access token to certain API actions. Also, access tokens expire. Check the default authorization and expiry settings for Hydra or your identity provider when you set up your apps to authenticate with access tokens.
Cleanup
You can optionally remove the resources that you set up as part of this guide.
helm uninstall hydra-token-example
kubectl delete extauthserver -n bookinfo ext-auth-server
kubectl delete extauthpolicy -n bookinfo ratings-hydra