Usage Plans with Custom Authentication

Add custom authentication configuration to a Gloo Portal Usage Plan.

Gloo Portal Usage Plans define how users can access API Products within an Environment. If you optionally set an authPolicy within a usage plan, Portal deterministically generates an authorization configuration that enforces the policy. To add additional authentication steps to the generated configuration, you can specify a customAuthConfig as part of the authPolicy.

Pre-requisites

  1. Install Gloo Edge Enterprise version 1.8.0 or later in a Kubernetes cluster.
  2. Install Gloo Portal version 1.3.0 or later in the same cluster.
  3. Follow the Create an API Product and Create a Portal guides to set up an Environment and Portal.
  4. Follow the Users and Groups Guide to create a Usage Plan with an apiKey Auth Policy for the Environment.

Create an AuthConfig

Define your custom authentication configuration in an AuthConfig custom resource. For example, you can apply the following AuthConfig derived from the “Securing the Virtual Service” step in Gloo Edge's basic auth guide, which expects user:password as credentials.

cat << EOF | kubectl apply -f-
apiVersion: enterprise.gloo.solo.io/v1
kind: AuthConfig
metadata:
  name: basic-auth
  namespace: gloo-system
spec:
  booleanExpr: basicAuth
  configs:
  - basicAuth:
      apr:
        users:
          user:
            hashedPassword: V/j4vjbW81mB6ciVZtG3g/
            salt: qVKGMOtb
    name: basicAuth
EOF

For more information, see the Basic Auth guide and the Gloo Edge reference documentation.

Add the AuthConfig to a UsagePlan

  1. In the basic usage plan of the dev environment, add the AuthConfig in a customAuthConfig section.

       cat << EOF | kubectl apply -f-
       apiVersion: portal.gloo.solo.io/v1beta1
       kind: Environment
       metadata:
         name: dev
         namespace: default
       spec:
         apiProducts:
         - labels:
           - key: app
             operator: Equals
             values:
             - petstore
           namespaces:
           - '*'
           usagePlans:
           - basic
           versions:
             tags:
             - stable
         displayInfo:
           description: This environment is meant for developers to deploy and test their
             APIs.
           displayName: Development
         domains:
         - api.example.com
         - api.example.com:32000
         parameters:
           usagePlans:
             basic:
               authPolicy:
                 apiKey: {}
               customAuthConfig:
                 name: basic-auth
                 namespace: gloo-system
               displayName: Basic plan with ApiKey and basic auth required
               rateLimit:
                 requestsPerUnit: 3
                 unit: MINUTE
       EOF
       

  2. Verify that the generated AuthConfig for the dev environment contains the custom configuration in addition to the configuration that was generated for the API key Auth Policy.

    $ kubectl get -n default authconfig default-petstore-product-dev -oyaml
    

    Example output:

    apiVersion: enterprise.gloo.solo.io/v1
    kind: AuthConfig
    metadata:
    ...
      labels:
        apiproducts.portal.gloo.solo.io: petstore-product.default
        environments.portal.gloo.solo.io: dev.default
      name: default-petstore-product-dev
      namespace: default
      ownerReferences:
      - apiVersion: portal.gloo.solo.io/v1beta1
        blockOwnerDeletion: true
        controller: true
        kind: Environment
        name: dev
    ...
    spec:
      booleanExpr: (basic && (basicAuth))
      configs:
      - apiKeyAuth:
          headersFromMetadata:
            x-solo-email:
              name: email
            x-solo-plan:
              name: plan
              required: true
            x-solo-username:
              name: username
              required: true
          labelSelector:
            apiproducts.portal.gloo.solo.io: petstore-product.default
            environments.portal.gloo.solo.io: dev.default
        name: apiKeys
      - basicAuth:
          apr:
            users:
              user:
                hashedPassword: V/j4vjbW81mB6ciVZtG3g/
                salt: qVKGMOtb
        name: basicAuth
    status:
      statuses:
        gloo-system:
          reportedBy: gloo
          state: Accepted
    
Note that the `booleanExpr` from the `customAuthConfig` is ANDed with the configuration generated for the usage plan's Auth Policy. If the `customAuthConfig` does not contain a `booleanExpr`, all configurations specified in the `AuthConfig` are required to authenticate in the order that they are specified.

Try it out

  1. Log in to the Portal, retrieve an API key, and use the key to authorize “Try it Out” requests for “Petstore Product”. Notice that when you click “Execute”, Basic Auth credentials are now required in addition to the API key. Enter user and password. Basic Auth pop-up

  2. Optional: You can also test the authentication by sending a curl request with and without Basic Auth credentials.

    1. Send a request with API key but without Basic Auth credentials.

      $ curl -v -X 'GET' \
        'http://api.example.com:32000/api/pets' \
        -H 'accept: application/json' \
        -H 'api-key: <API key>'
      

      Example output, in which a 401 Unauthorized response is returned:

      *   Trying 127.0.0.1...
      * TCP_NODELAY set
      * Connected to api.example.com (127.0.0.1) port 32000 (#0)
      > GET /api/pets HTTP/1.1
      > Host: api.example.com:32000
      > User-Agent: curl/7.64.1
      > accept: application/json
      > api-key: <API key>
      >
      < HTTP/1.1 401 Unauthorized
      < www-authenticate: Basic realm=""
      ...
      <
      * Connection #0 to host api.example.com left intact
      * Closing connection 0
      
    2. Send a request with API key and Basic Auth credentials.

      $ curl -X 'GET' \
        'http://user:password@api.example.com:32000/api/pets' \
        -H 'accept: application/json' \
        -H 'api-key: <API key>'
      

      Now, the correct response is returned by /pets:

      [{"id":1,"name":"Dog","status":"available"},{"id":2,"name":"Cat","status":"pending"}]
      

Guarantees and limitations