Set up external authentication
You can set up OpenID Connect (OIDC) authentication to secure access to your developer portal. To learn more about how external authentication works with your portal, see External authentication with the developer portal.
You can choose among the supported OIDC providers to secure your developer portal. Example steps are provided for access token validation with Keycloak and Okta.
Before you begin
-
Make sure that you created your developer portal and exposed the portal on the gateway.
-
Get the external address of the ingress gateway. If you deployed your ingress gateway in a different namespace or with a different version, update the command.
export INGRESS_GW_IP=$(kubectl get svc -n gloo-mesh-gateways istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}') echo $INGRESS_GW_IP
export INGRESS_GW_IP=$(kubectl get svc -n gloo-mesh-gateways istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') echo $INGRESS_GW_IP
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 insufficent 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-18-2 8081
-
For local testing with your browser, update your
/etc/hosts
DNS file. Map the IP address of your ingress gateway to resolve to thedeveloper.example.com
host domain that you set in the route table.sudo nano /etc/hosts
Replace
${INGRESS_GW_IP}
with the value that you previously retrieved.${INGRESS_GW_IP} developer.example.com
Step 1: Set up the OAuth for external auth
To enforce external authentication for Gloo Platform Portal, you must have an OIDC provider to use to get an OAuth access token. The following examples uses Keycloak or Okta. For other options, see the OIDC and OAuth guides.
- Follow the steps to install Keycloak.
- Follow the steps to configure Keycloak.
- Create the secret and ext auth server. Note that you can skip creating the httpbin sample app route table, as you create a route table for portal later.
- Configure OAuth with external auth policy for access token validation.
Step 2: Set up routing
Now that you secured your routes with OAuth, set up the routing details for the portal server's APIs.
- Decide on the portal APIs that you want to enforce authentication for. In the following example, you set up two forward actions for
authn
andno-auth
that allow access to different API methods.authn
: To apply an external auth policy to these APIs and enforce authentication, you add theoauth: "true"
label on this route. Users must authenticate before they can perform certain API methods, such asGET /v1/me
,POST /v1/api-keys
, andDELETE /v1/api-keys
. The access token for authentication is extracted from theAuthorization
headerno-auth
: Users do not have to authenticate before they can perform certain read-only API methods, such asGET /v1/apis
,GET /v1/usage-plans
, andGET /v1/api-keys
.
kubectl apply -f - <<EOF apiVersion: networking.gloo.solo.io/v2 kind: RouteTable metadata: name: dev-portal-rt namespace: gloo-mesh-gateways spec: hosts: - developer.example.com virtualGateways: - name: istio-ingressgateway-portal namespace: gloo-mesh-gateways defaultDestination: port: number: 8080 ref: name: gloo-mesh-portal-server namespace: gloo-mesh-addons cluster: $CLUSTER_NAME http: # # Portal server routes that require authentication. # - forwardTo: {} name: authn labels: oauth: "true" # Use this label to apply an OAuth external auth policy route: portal-api matchers: # # /v1/me - uri: prefix: /v1/me method: OPTIONS - uri: prefix: /v1/me method: GET headers: - name: Authorization value: "Bearer.*" regex: true # # /v1/apis - uri: prefix: /v1/apis method: GET headers: - name: Authorization value: "Bearer.*" regex: true # # /v1/usage-plans - uri: prefix: /v1/usage-plans method: GET headers: - name: Authorization value: "Bearer.*" regex: true # # /v1/api-keys - uri: prefix: /v1/api-keys method: GET headers: - name: Authorization value: "Bearer.*" regex: true - uri: prefix: /v1/api-keys method: POST headers: - name: Authorization value: "Bearer.*" regex: true - uri: prefix: /v1/api-keys method: DELETE headers: - name: Authorization value: "Bearer.*" regex: true # # Portal server routes that are public and do not require authentication. # - forwardTo: {} name: no-auth labels: route: portal-api matchers: - uri: prefix: /v1/apis method: GET - uri: prefix: /v1/usage-plans method: GET - uri: prefix: /v1/api-keys method: GET # # Allow OPTION requests without authentication. # - uri: prefix: /v1/api-keys method: OPTIONS - uri: prefix: /v1/usage-plans method: OPTIONS - uri: prefix: /v1/apis method: OPTIONS EOF
- For local development and testing, apply a CORS policy. This way, you can access the portal frontend that you set up later from your localhost.
kubectl apply -f -<<EOF apiVersion: security.policy.gloo.solo.io/v2 kind: CORSPolicy metadata: name: dev-portal-cors namespace: gloo-mesh-gateways spec: applyToRoutes: - route: labels: route: portal-api config: allowCredentials: true allowHeaders: - "Content-Type" - "api-key" - "id_token" - "Authorization" allowMethods: - GET - POST - DELETE - PUT - OPTIONS allowOrigins: - prefix: http://localhost - prefix: http://127.0.0.1 - prefix: https://developer.example.com EOF
Step 3: Verify external authentication
Now that the OIDC provider is set up and your Gloo external auth policy is configured, you can verify that OAuth protects the portal.
-
Send a request to the portal server. Verify that you get back a 200 from an API that does not require authentication, such as
GET /v1/apis
.curl -vik --resolve developer.example.com:80:$INGRESS_GW_IP http://developer.example.com:80/v1/apis
Example output:
HTTP/1.1 200 OK ... [{"apiProductDisplayName":"Catstronauts Course Tracks","apiProductId":"tracks","apiVersions":[{"apiId":"tracks-v1","apiVersion":"v1","contact":"support@example.com","customMetadata":{"compatibility":"None"},"description":"REST API for Catstronauts to retrieve data for tracks, authors and modules.","license":"License info, such as MIT","lifecycle":"Supported","termsOfService":"You must authenticate to use this API! And other Terms of Service.","title":"Catstronauts REST API","usagePlans":["bronze","gold","silver"]}]},{"apiProductDisplayName":"Pet Store","apiProductId":"petstore","apiVersions":[{"apiId":"petstore-v1","apiVersion":"v1","contact":"support@example.com","customMetadata":{"compatibility":"None"},"description":"Totally awesome API for all things pets!","license":"License info, such as MIT","lifecycle":"Supported","termsOfService":"You must authenticate to use this API! And other Terms of Service.","title":"Pet Store REST API","usagePlans":["bronze","gold","silver"]}]}]
-
Send another request to the portal server. Verify that you get back a 401 from an API that requires authentication, such as
GET /v1/api-keys
.curl -vik --resolve developer.example.com:80:$INGRESS_GW_IP http://developer.example.com:80/v1/api-keys
Example output:
HTTP/1.1 401 Unauthorized ... {"message":"user is not authenticated"}
After you set up a frontend app for the portal, you can verify that you can log in through the OIDC provider.
Next steps
Check out these common next steps.
Having trouble getting OAuth to work? Try debugging OAuth issues.
- Set up authorization for private APIs to create portal groups that let users access private APIs based on the claims in the ID token.
- Create a frontend app to serve the catalog of your portal API products.
- When you are done with trying out Portal, you can clean up all of the resources that you created.