Best Practices How-tos kubernetes Spring spring cloud tutorials

API Key Management with API Portal and Spring Cloud Gateway for Kubernetes

Ignacio Lozano, Karine Pires, and Chris Sterling contributed to this blog post.

In today’s world of digital transformation, APIs are present in almost every software product. Many teams are responsible for deploying and managing a large portfolio of APIs. However, that scale and complexity of APIs also makes it complicated to control and manage access. Specifically, understanding granular usages and uncovering insights and utilization can be difficult. Enter API key management with API portal for VMware Tanzu and Spring Cloud Gateway for Kubernetes, designed to solve this problem and more. This post primarily explores the features for API key management. For information about other features, check out the latest documentation.

API key management features

As an API Consumer, you can generate API keys for single or multiple API groups configured with your API portal for VMware Tanzu. You can view the list of keys that are currently active and revoke them once they are no longer needed. Any generated key is stored in a secret store from which the configured Spring Cloud Gateway for Kubernetes can read and verify any incoming requests. HashiCorp Vault is a leading provider in secret management and hence was chosen as the inaugural integration for API key management.

Create API Key modal view

As an API Manager, in addition to all of the above features, you can also see a detailed view of all the keys generated by all users in your instance of the API portal. For each key, you can view the key name, issued on date, owner, and the API groups accessible with that key. You can also revoke keys created by any user within the API portal. A user is identified as an API Manager by inspecting a claim within the ID token from the OIDC Identity Provider. For more details on configuring API portal to inspect the right claim, see the API Manager section in the documentation.

API Keys list view for API Managers

Getting started with API Management

Prerequisites:

Note: The rest of this guide will assume that API portal is installed in the “api-portal” namespace, Spring Cloud Gateway for Kubernetes is installed in “spring-cloud-gateway” namespace, and Vault is installed in the “vault” namespace. Please substitute your custom namespace wherever needed.

Configuring Vault access 

Here is a bird’s-eye view of the different pieces needed for Vault to integrate with API portal and Spring Cloud Gateway for Kubernetes. You will need to create Vault access policies for each of the two products, create service accounts in their respective namespaces, and attach those service accounts to the Vault access policies.

The next set of commands can also be set using the Vault UI if you prefer. Start by accessing the Vault instance from the command line and configuring a dedicated path for API keys to be stored. 

vault secrets enable -path=api-portal-keys kv-v2

Next, configure access policies for this exact path. API portal needs complete access to this path, whereas Spring Cloud Gateway for Kubernetes only needs the read and list permissions in this path. Create your “api-portal-policy”.

(
cat << EOF
  path "api-portal-keys/data/*" {
    capabilities = ["create", "read", "update", "delete", "list"]
  }
  path "api-portal-keys/metadata/*" {
    capabilities = ["list", "delete"]
  }
EOF
) | vault policy write api-portal-policy -

Next, create the “gateway-policy” to read all API keys.

(
cat << EOF
  path "api-portal-keys/data/*" {
    capabilities = ["read"]
  }
  path "api-portal-keys/metadata/*" {
    capabilities = ["list"]
  }
EOF
) | vault policy write gateway-policy -

Alternatively, you can create the “gateway-policy” to only read API keys belonging to a specific API group ID. 

(
cat << EOF
  path "api-portal-keys/data/my-group-id*" {
    capabilities = ["read"]
  }
  path "api-portal-keys/metadata/my-group-id*" {
    capabilities = ["list"]
  }
EOF
) | vault policy write gateway-policy -

Connecting Vault to your Kubernetes cluster

In order for your deployments to access the Vault, you need the Kubernetes auth method that uses the Kubernetes Service Account Token. 

vault auth enable kubernetes
vault write auth/kubernetes/config
    token_reviewer_jwt="<your reviewer service account JWT>"
    kubernetes_host=https://192.168.99.100:<your TCP port or blank for 443>

If your Vault instance is in the same cluster as API portal and Spring Cloud Gateways, then you can run:

vault write auth/kubernetes/config
     token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
     kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443"
     kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

Next, you need to create the roles that bind namespaced service accounts to the policies you’ve created. You can create the “api-portal-role” in Vault that allows a service account named “api-portal-sa” in the “api-portal” namespace attached to the “api-portal-policy” in Vault.

vault write auth/kubernetes/role/api-portal-role
    bound_service_account_names=api-portal-sa
    bound_service_account_namespaces=api-portal
    policies=api-portal-policy
    ttl=24h

Similarly, you can create the “gateway-role” for a service account named ”gateway-sa” in the “spring-cloud-gateway” namespace.

vault write auth/kubernetes/role/gateway-role
    bound_service_account_names=gateway-sa
    bound_service_account_namespaces=spring-cloud-gateway
    policies=gateway-policy
    ttl=24h

You can create the aforementioned service accounts in their respective namespaces. API portal can also automatically create service accounts during installation.

kubectl -n api-portal create serviceaccount api-portal-sa

Configure API portal to enable API key management

In the values.yml file used in conjunction with the installation script for API portal, add the following properties to enable and configure API keys:

apiKey:
  enabled: true
  vault:
    url: "<Your vault url or http://vault.vault.svc:8200/ if Vault is installed in the same cluster>"
    role: api-portal-role
    path: api-portal-keys 
 
serviceAccount:
  create: true # Note: This will automatically create the service account
  name: api-portal-sa
 
apiPortalServer:
  sourceUrls: "<Your scg-operator url>/openapi"
 
sso:
  enabled: true
  secretName: <Your sso secret name>

Create an Spring Cloud Gateway with API key enabled

The last step is to create a gateway with the Vault details to allow the gateway to read and list the stored API keys. Create an scg.yaml with the below details and apply it. If you add a “serverUrl”, you will also need to create an ingress to route traffic to my-gateway service from that host.

---
apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: my-gateway
spec:
  api:
    groupId: my-group-id
    serverUrl: my-gateway.my-example-domain.com # Optional but recommended for testing the gateway
    cors: # Optional but needed for API portal’s “Try it out” feature
      allowedOrigins:
        - "<My API portal’s domain>"
      allowedMethods:
        - "GET"
      allowedHeaders:
        - "*"
  serviceAccount:
    name: gateway-sa
  extensions:
    secretsProviders:
      - name: vault-api-keys
        vault:
          roleName: gateway-role
          path: api-portal-keys
    filters:
      apiKey:
        enabled: true
        secretsProviderName: vault-api-keys
---
apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGatewayRouteConfig
metadata:
  name: my-routes
spec:
  routes:
    - predicates:
        - Path=/github/
      uri: https://github.com
---
apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGatewayMapping
metadata:
  name: my-mapping
spec:
  gatewayRef:
    name: my-gateway
  routeConfigRef:
    name: my-routes

Now, any route like “my-routes” mapped to “my-gateway” will require an additional header “X-API-Key: <API Key Value>” to be passed in. 

Create an API key using API portal

In order for API portal to recognize “my-gateway” and its routes, you’ll need to expose the Spring Cloud Gateway operator’s OpenAPI endpoint and, optionally, the my-gateway service too. You can create an ingress using instructions here, or use other methods to expose the operator and gateway.

Then, you can modify the source URLs configured in API portal’s values.yml and rerun the installation script. In case you would like the API portal to trust self-signed or unsecured TLS certificates, you can set the “trustInsecureSourceUrls” property.

apiPortalServer:
    sourceUrls: "https://<my-scg-operator-url>/openapi”
    trustInsecureSourceUrls: true # false by default

Finally, log in to the API portal user interface, navigate to the API Keys tab and click the + API Key button. Give your key a name, select the group, generate the key, and copy the token. Keep the token safe since you can only copy it once.

Try it out

From the list of APIs on the API portal home page, click on the group card that will take you to the Swagger UI page. There, click the Authorize button and paste the API key in the header value field.

Authorization modal for passing the API key with requests

Next, click on the Try it out button and hit Execute to see a 200 OK response.

Response with 200 OK after executing the API with authorization

You can also use an HTTP client like cURL, HTTP, or Postman to test the route.

curl -X GET my-gateway.my-example-domain.com/github --header "X-API-Key:<my-api-key>”
< HTTP/1.1 200 OK
...

You can also see that, without the header present, the request fails:

curl -X GET my-gateway.my-example-domain.com/github
< HTTP/1.1 401 Unauthorized
...

Explore other features 

To explore all other features for both Spring Cloud Gateway for Kubernetes and API portal for VMware Tanzu, view the respective documentation.