Previously, you set up a developer portal in which your end users can discover your API products. Now, you protect your APIs by enforcing external auth and rate limiting policies. Together, these policies make up the usage plans for your API products. For more information, see About usage plans.

Before you begin

  1. Complete the portal setup tutorial.

  2. Complete the API product tutorial.

  3. Optional: Complete the portal tutorial. You can also complete the portal tutorial after this tutorial, if you want to see the usage plans in the frontend portal.

  4. Get the labels of your routes to use to apply policies to, such as with the example query.

      kubectl get rt -n gloo-mesh-gateways -o=jsonpath='{range .items[*]}[{.metadata.name}, {.spec.http[*].name}, {.spec.http[*].labels}]{"\n"}{end}'
      

    Example output:

    • The api-example-com-rt route table does not have any route-level labels. To apply policies, you can add labels to those routes.
    • The petstore-rt route table has a usagePlans: dev-portal label on its pets-api, users-api, and store-api routes.
    • The tracks-rt route table has a usagePlans: dev-portal label on its tracks-api route.
      [api-example-com-rt, , ]
    [petstore-rt, pets-api users-api store-api, {"usagePlans":"dev-portal"} {"usagePlans":"dev-portal"} {"usagePlans":"dev-portal"} ]
    [tracks-rt, tracks-api, {"usagePlans":"dev-portal"}]
      

Set up API key external auth

Require users to authenticate in requests to your API products. The following steps set up external authentication through API keys. The API keys are stored in Kubernetes secrets for simplicity. If you have a portal set up, your users can generate these API keys for themselves through the frontend portal. For more information about API keys, other backing storage options, or other external auth options such as OAuth, see the External auth for portal guide.

Step 1: Create the API key policy

To enforce external auth on the routes to your API products, create an external auth policy.

  1. Select the external auth server to use. The example uses the default external auth server that you created when you installed Gloo Mesh Gateway.

      kubectl apply -f - << EOF
    apiVersion: admin.gloo.solo.io/v2
    kind: ExtAuthServer
    metadata:
      name: ext-auth-server
      namespace: gloo-mesh-addons
    spec:
      destinationServer:
        ref:
          cluster: $CLUSTER_NAME
          name: ext-auth-service
          namespace: gloo-mesh-addons
        port:
          name: grpc
    EOF
      
  2. Create an API key external auth policy.

      kubectl apply -f - << EOF
    apiVersion: security.policy.gloo.solo.io/v2
    kind: ExtAuthPolicy
    metadata:
      name: api-key-auth
      namespace: default
    spec:
      applyToRoutes:
      - route:
          labels:
            usagePlans: dev-portal
      config:
        server:
          name: ext-auth-server
          namespace: gloo-mesh-addons
          cluster: $CLUSTER_NAME
        glooAuth:
          configs:
            - apiKeyAuth:
                headerName: api-key
                headersFromMetadataEntry:
                  x-solo-plan: 
                    name: usagePlan
                    required: true
                k8sSecretApikeyStorage:
                  labelSelector:
                    extauth: apikey
    EOF
      

    For more information, see the API docs.

    SettingDescription
    metadata.namespaceCreate the external auth policy in the same namespace or import it into the same Gloo workspace as the external auth server. In this example, the policy is in the default namespace.
    applyToRoutesApply the policy to the tracks-api route that you previously created in the API product’s route table. You apply policies by labels. The tracks-api route has the usagePlans: dev-portal label.
    config.serverSelect the external auth server that you configured in the previous step.
    headerNameSet the name of the header. In this example, requests must include the API key in the api-key header.
    headersFromMetadataEntryConfigure extra API key details to add to the request headers of successfully authenticated requests. In this example, successful requests add in the usagePlan details in the x-solo-plan header from the API key. These details can then be used to rate limit authenticated requests per the matching usage plan and rate limit policy.
    k8sSecretApikeyStorageSelect the Kubernetes secret where the API key details are stored. This value is only required if you use local Kubernetes secrets for testing. If you configured the external auth server to use Redis as a backing database, omit this value.
  3. Verify that requests to your API now require external auth. The following request fails because you do not have the API key details stored in a local Kubernetes secret.

      curl -v -H 'api-key: apikey1' --resolve api.example.com:80:${INGRESS_GW_IP} http://api.example.com/trackapi/tracks
      

    Example output:

      < HTTP/1.1 401 Unauthorized
    < www-authenticate: API key is missing or invalid
      

Step 2: Verify authentication with an API key

Now that you applied an external auth policy to your routes, requests must include a valid API key in the X-Solo-Plan header. Gloo Mesh Gateway must be able to check the API keys in requests against valid API keys that are stored somewhere. In this example, you store the API key in a Kubernetes secret.

  1. Create a Kubernetes secret with the details of your API key.

    • apikey1 is the API key that you later include in the request header. You can choose any string value for your API key.
    • user1 is the user ID that must be included in the request metadata.
    • user1@solo.io is the email for the user.
    • gold is the name of a usage plan that matches the usage plans you set up as part of rate limiting.
      kubectl apply -f - <<EOF
    apiVersion: v1
    kind: Secret
    metadata:
      name: user1
      namespace: default
      labels:
        extauth: apikey
    type: extauth.solo.io/apikey
    stringData:
      # apikey1
      api-key: apikey1
      # user1
      user-id: user1
      # user1@solo.io
      user-email: user1@solo.io
      # gold
      usagePlan: gold
    EOF
      
  2. Verify that the secret is created.

      kubectl get secret
      
  3. Repeat the request with your API key details. Make sure to use the API key string value that you encoded earlier. The request now succeeds!

      curl -v -H 'api-key: apikey1' --resolve api.example.com:80:${INGRESS_GW_IP} http://api.example.com/trackapi/tracks
      

    Example output:

      < HTTP/1.1 200 OK
    ...
       [
      {
        "id": "c_0",
        "thumbnail": "https://res.cloudinary.com/dety84pbu/image/upload/v1598465568/nebula_cat_djkt9r.jpg",
        "topic": "Cat-stronomy",
        "authorId": "cat-1",
        "title": "Cat-stronomy, an introduction",
        "description": "Curious to learn what Cat-stronomy is all about? Explore the planetary and celestial alignments and how they have affected our space missions.",
        "numberOfViews": 163,
        "createdAt": "2018-09-10T07:13:53.020Z",
        "length": 2377,
        "modulesCount": 10,
        "modules": [
          "l_0",
          "l_1",
          "l_2",
          "l_3",
          "l_4",
          "l_5",
          "l_6",
          "l_7",
          "l_8",
          "l_9"
        ]
      },
    ...
      

Set up rate limiting

Control how many requests within a time period are allowed to your API products, such as 100 requests per minute. The rate limits form a key part of the usage plan for your API products. For more information about rate limiting or for other options such as dynamic rate limiting, see the Rate limiting for portal guide.

  1. Select the rate limiting server to use. The example uses the default rate limiting server that you created when you installed Gloo Mesh Gateway. For more information, see Rate limit server settings.

      kubectl apply -f - << EOF
    apiVersion: admin.gloo.solo.io/v2
    kind: RateLimitServerSettings
    metadata:
      name: rl-server
      namespace: gloo-mesh-addons
      labels:
        portal: rate-limit
    spec:
      destinationServer:
        port:
          name: grpc
        ref:
          cluster: $CLUSTER_NAME
          name: rate-limiter
          namespace: gloo-mesh-addons
    EOF
      
  2. Set up the rate limit client config to define the usagePlan descriptor key and extract details from the x-solo-plan header that is set up in your matching external auth policy. The configuration varies depending on the type of external auth policy that you applied: API key or OAuth. For more information, see Rate limit client config.

      kubectl apply -f - <<EOF
    apiVersion: trafficcontrol.policy.gloo.solo.io/v2
    kind: RateLimitClientConfig
    metadata:
      name: usage-plans
      namespace: gloo-mesh-addons
      labels:
        portal: rate-limit
    spec:
      raw:
        rateLimits:
        - setActions:
          - requestHeaders:
              descriptorKey: usagePlan
              headerName: x-solo-plan
          - metadata:
              descriptorKey: userId
              metadataKey:
                key: envoy.filters.http.ext_authz
                path:
                  - key: userId
    EOF
      
  3. Use the RateLimitServerConfig to define the values of the descriptors that are the usage plan names, that match the usagePlan descriptor key that you configured in the RateLimitClientConfig. The userId and usagePlan details are extracted from the API key details in the request header that is required by the API key external auth policy. The following rate limit server config example creates three usage plans as follows:

    • Bronze: Requests to your APIs are limited to 1 per minute.
    • Silver: Requests to your APIs are limited to 3 per minute.
    • Gold: Requests to your APIs are limited to 5 per minute.

    For more information, see Rate limit server config.

      kubectl apply -f - << EOF
    apiVersion: admin.gloo.solo.io/v2
    kind: RateLimitServerConfig
    metadata:
      name: usage-plans
      namespace: gloo-mesh-addons
      labels:
        portal: rate-limit
    spec:
      destinationServers:
      - port:
          name: grpc
        ref:
          cluster: $CLUSTER_NAME
          name: rate-limiter
          namespace: gloo-mesh-addons
      raw:
        setDescriptors:
          - simpleDescriptors:
              - key: userId
              - key: usagePlan
                value: bronze
            rateLimit:
              requestsPerUnit: 1
              unit: MINUTE
          - simpleDescriptors:
              - key: userId
              - key: usagePlan
                value: silver
            rateLimit:
              requestsPerUnit: 3
              unit: MINUTE
          - simpleDescriptors:
              - key: userId
              - key: usagePlan
                value: gold
            rateLimit:
              requestsPerUnit: 5
              unit: MINUTE
    EOF
      
  4. Apply the rate limit policy to the tracks-api route that you previously created in the API product’s route table. You apply policies by labels. The tracks-api route has the usagePlans: dev-portal label.

      kubectl apply -f - << EOF
    apiVersion: trafficcontrol.policy.gloo.solo.io/v2
    kind: RateLimitPolicy
    metadata:
      name: tracks-rate-limit
      namespace: default
      labels:
        portal: rate-limit
    spec:
      applyToRoutes:
      - route:
          labels:
            usagePlans: dev-portal
      config:
        ratelimitServerConfig:
          name: usage-plans
          namespace: gloo-mesh-addons
          cluster: $CLUSTER_NAME
        ratelimitClientConfig:
          name: usage-plans
          namespace: gloo-mesh-addons
          cluster: $CLUSTER_NAME
        serverSettings:
          name: rl-server
          namespace: gloo-mesh-addons
          cluster: $CLUSTER_NAME
        phase:
          postAuthz:
            priority: 1
    EOF
      
  5. Verify that your rate limiting is in place by repeating the following request 6 times in a row. Because your user ID is limited to the gold usage plan’s limit of 5 requests per minute, the sixth time your request is blocked. Note that this step requires you to have set up API key external auth already.

      curl -v -H 'api-key: apikey1' --resolve api.example.com:80:${INGRESS_GW_IP} http://api.example.com/trackapi/tracks
      

    Example output:

      < HTTP/1.1 429 Too Many Requests
    < x-envoy-ratelimited: true
      

Next steps

Good job! Now, your APIs are secured by external auth and rate limit policies. Together, you can think of these policies as the usage plan for the API products in your developer portal.

Next, Secure access to the portal by requiring users to log in through an OpenID Connect (OIDC) provider.