Custom Auth server

The custom auth feature was introduced with Gloo, release 0.20.7, and Gloo Enterprise, release 0.13.5. If you are using an earlier version, this tutorial will not work.

Gloo Enterprise ships with an external auth server that implements a wide array of authentication and authorization models. Even though these features are not available in the open source version of Gloo, you can deploy your own service and configure Gloo to use it to secure your Virtual Services.

In this guide we will see how to create such a custom external auth service. For simplicity, we will implement an HTTP service. With minor adjustments, you should be able to use the contents of this guide to deploy a gRPC server that implements the Envoy spec for an external authorization server.

Setup

This guide assumes that you have installed Gloo into the gloo-system namespace and that glooctl is installed on your machine. For convenience, let’s also store the URL of the Gloo Gateway in a variable in your terminal:

export GATEWAY_URL=$(glooctl proxy url)

Let’s start by creating the sample petstore application:

kubectl apply --filename https://raw.githubusercontent.com/solo-io/gloo/master/example/petstore/petstore.yaml

We can now add a route to the sample application by running the following command:


kubectl apply -f - <<EOF
apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
  name: default
  namespace: gloo-system
spec:
  virtualHost:
    domains:
    - '*'
    routes:
    - matcher:
        prefix: /
      routeAction:
        single:
          upstream:
            name: default-petstore-8080
            namespace: gloo-system
EOF

glooctl add route --name default --namespace gloo-system --path-prefix / --dest-name default-petstore-8080 --dest-namespace gloo-system

Let’s verify that everything so far works by querying the virtual service.

curl $GATEWAY_URL/api/pets/

You should see the following output:

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

Creating a simple HTTP Authentication service

When a request matches a route that defines an extauth configuration, Gloo will forward the request to the external auth service. If the HTTP service returns a 200 OK response, the request will be considered authorized and sent to its original destination. Otherwise the request will be denied. You can fine tune which headers are sent to the the auth service, and whether or not the body is forwarded as well, by editing the extauth settings in the Gloo settings (see the example below).

For reference, here’s the code for the authorization server used in this tutorial:

import http.server
import socketserver

class Server(http.server.SimpleHTTPRequestHandler):
    def do_GET(self):
        path = self.path
        print("path", path)
        if path.startswith("/api/pets/1"):
            self.send_response(200, 'OK')
        else:
            self.send_response(401, 'Not authorized')
        self.send_header('x-server', 'pythonauth')
        self.end_headers()

def serve_forever(port):
    socketserver.TCPServer(('', port), Server).serve_forever()

if __name__ == "__main__":
    serve_forever(8000)

As you can see, this service will allow requests to /api/pets/1 and will deny everything else.

Deploy auth service

To deploy this service to your cluster, download the auth-service yaml file and apply it:

kubectl apply --filename auth-service.yaml

This file contains the deployment, service and upstream definitions.

When running in minikube you can easily update this sample auth service. Just download the Dockerfile and the server.py file to a local directory, apply your changes to the server code, and run the following commands:

eval $(minikube docker-env)
docker build -t quay.io/solo-io/sample-auth .
kubectl --namespace gloo-system delete pod -l app=sample-auth

Configure Gloo to use your server

Configure Gloo settings

To use our custom auth server, we need to edit the Gloo Settings resource. Run the following command to edit the settings:

kubectl --namespace gloo-system edit settings default`) to point to your auth server.

We need to add the following extauth attribute:

apiVersion: gloo.solo.io/v1
kind: Settings
metadata:
  name: default
  namespace: gloo-system
spec:
  discoveryNamespace: gloo-system
  gateway:
    validation:
      alwaysAccept: true
      proxyValidationServerAddr: gloo:9988
  gloo:
    xdsBindAddr: 0.0.0.0:9977
  kubernetesArtifactSource: {}
  kubernetesConfigSource: {}
  kubernetesSecretSource: {}
  refreshRate: 60s
  extauth:
   extauthzServerRef:
     name: auth-server
     namespace: gloo-system
   httpService: {}
   requestBody:
     maxRequestBytes: 10240
   requestTimeout: 0.5s

More details about the httpService object are available here . For example, if you want to copy some of the original request headers to the request that gets sent to the custom auth server, you would need to configure the extauth attribute in the following way:

apiVersion: gloo.solo.io/v1
kind: Settings
metadata:
  name: default
  namespace: gloo-system
spec:
  discoveryNamespace: gloo-system
  gateway:
    validation:
      alwaysAccept: true
      proxyValidationServerAddr: gloo:9988
  gloo:
    xdsBindAddr: 0.0.0.0:9977
  kubernetesArtifactSource: {}
  kubernetesConfigSource: {}
  kubernetesSecretSource: {}
  refreshRate: 60s
  extauth:
   extauthzServerRef:
     name: auth-server
     namespace: gloo-system
   httpService:
     request:
       allowedHeaders:
       - "X-foo"
   requestBody:
     maxRequestBytes: 10240
   requestTimeout: 0.5s

When using a gRPC auth service, remove the httpService attribute from the configuration above.

This configuration also sets other configuration parameters:

Securing the Virtual Service

Edit the VirtualService and mark it with custom auth to turn authentication on:

kubectl apply -f - <<EOF
apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
  name: default
  namespace: gloo-system
spec:
  virtualHost:
    domains:
    - '*'
    virtualHostPlugins:
      extauth:
        customAuth: {}
    routes:
    - matcher:
        prefix: /
      routeAction:
        single:
          upstream:
            name: default-petstore-8080
            namespace: gloo-system
EOF

If you have followed this guide verbatim, you can just download and apply this manifest to update both the Settings and the Virtual Service.

Test

Let’s verify that our configuration has been accepted by Gloo. Requests to /api/pets/1 should be allowed:

curl --write-out "%{http_code}\n" $GATEWAY_URL/api/pets/1
{"id":1,"name":"Dog","status":"available"}
200

Any request with a path that is not /api/pets/1 should be denied.

curl --write-out "%{http_code}\n" $GATEWAY_URL/api/pets/2
401

Conclusion

Gloo’s extendable architecture allows follows the ‘batteries included but replaceable’ approach. while you can use Gloo’s built in auth services for OpenID Connect and Basic Auth, you can also extend Gloo with your own custom auth logic.