Require API key external auth

Require users to authenticate with an API key in requests to your API products. After you set up the developer portal frontend, your users can generate these API keys for themselves.

For more information about this type of external auth, see API keys.

Before you begin

  1. Create your APIs, including the Gloo ApiDocs that describe the stitched schema.

  2. Bundle your APIs into API products by using a route table.

  3. Optional: Review the Usage plan overview to understand how the various Gloo custom resources work together to create usage plans for your developer 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"}]
    
  5. Make sure that you have the following CLI tools, or something comparable:

    • base64 to encode strings.
  6. Decide on a storage method for API keys. You can choose from the following options:

    • Kubernetes secret: You can use Kubernetes secrets for quick testing, such as when you do not want to configure a Redis database. By default, Gloo creates a Kubernetes secret for each API key that gets generated through the frontend developer portal that you configure later. If you do not have a frontend developer portal yet, you can manually create the secret, as described in Make an API key to test authentication.
    • Local Redis database: You can configure the local Redis database that Gloo Platform sets up for you when you install Portal. Then, each API key that gets generated through the frontend developer portal gets stored in this local Redis database. This setup is more scalable than using Kubernetes secrets and suitable for staging and single cluster environments. However, for higher availability or other security concerns, you might use your own external Redis database instead.
    • External Redis database: You can configure your own external Redis database when you install Portal. Then, each API key that gets generated through the frontend developer portal gets stored in this external Redis database. This setup is common in production-level, multicluster environments.

Apply an API key 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 Platform.

    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
    

    Review the following table to understand this configuration. For more information, see the API docs.

    Setting Description
    metadata.namespace Create 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.
    applyToRoutes Apply 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.server Select the external auth server that you configured in the previous step.
    headerName Set the name of the header. In this example, requests must include the API key in the api-key header.
    headersFromMetadataEntry Configure 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.
    k8sSecretApikeyStorage Select 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
    

Make an API key to test authentication

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 Gateway must be able to check the API keys in requests against valid API keys that are stored in a local or external Redis instance.

For testing purposes, you can manually create a Kubernetes secret with an API key. After you set up your portal backend and frontend later, you can test out external auth with the API keys that Gloo Gateway generates upon user request.

  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 your 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"
        ]
      },
    ...
    

Verify that external auth works with API keys in a backing storage database

After you set up your portal backend and frontend later, you can test out external auth with the API keys that Gloo generates upon user request. For more backing storage options, see Portal server.

Before you begin, set up the frontend app for the developer portal. Keep in mind that this step requires you to have applied a usage plan (external auth and rate limiting policies) as well as configured a backend Portal resource.

  1. Generate an API key by using the developer portal frontend app.

    1. Go to the host domain that your frontend developer portal is exposed on, such as developer.example.com.
    2. Click Login.
    3. Enter your username and password, such as user1@example.com and password.
    4. From your profile dropdown, click API Keys.
    5. Expand the API product that you want to create an API key for.
    6. For the usage plan of the API product that you want to create an API key for, click + Add Key.
    7. Give your API key a name and click Generate Key.
    8. Copy the key's value. You won't be able to see this value later.
    9. Click Close Window.
    10. Optional: To review the API key's custom metadata that is automatically generated for you, click the View key details pencil icon. Details such as name and usagePlan are returned.
    11. Optional: To delete the API key if you no longer need it, click the Delete key X icon.
  2. Update your API key external auth policy to remove the local Kubernetes secret storage. Now, the external auth server uses the backing storage values that you set up, such as for Redis.

    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
    EOF
    

    Review the following table to understand this configuration. For more information, see the API docs.

    Setting Description
    metadata.namespace Create 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.
    applyToRoutes Apply 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.server Select the external auth server that you configured earlier.
    headerName Set the name of the header. In this example, requests must include the API key in the api-key header.
    headersFromMetadataEntry Configure 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.
  3. 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-20 8081
    
  4. Verify that the API key works to authenticate your request. Replace $API_KEY with the value of the API key that you previously created.

    curl -v -H 'api-key: $API_KEY' --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"
        ]
      },
    ...
    
  5. Optional: Check that the API key exists in the backing storage database. For example, you might review the contents of the local Redis database with RedisInsights to find the API key that you just created, such as in the following screenshot. For more information, see Review data in Redis. RedisInsight screenshot of the API key

Next steps

When you are done with trying out Portal, you can clean up all of the resources that you created.