gRPC Passthrough Auth

The gRPC Passthrough feature was introduced with Gloo Gateway Enterprise, release 1.6.0. If you are using an earlier version, this tutorial will not work.

When using Gloo Gateway’s external authentication server, it may be convenient to integrate authentication with a component that implements Envoy’s authorization service API. This guide will walk through the process of setting up Gloo Gateway’s external authentication server to pass through requests to the provided component for authenticating requests.

Make sure to check out the pros and cons of using passthrough auth here

Setup

This guide assumes that you have deployed Gloo to the gloo-system namespace and that the glooctl command line utility is installed on your machine. glooctl provides several convenient functions to view, manipulate, and debug Gloo resources; in particular, it is worth mentioning the following command, which we will use each time we need to retrieve the URL of the Gloo Gateway that is running inside your cluster:

glooctl proxy url

Let’s start by creating a Static Upstream that routes to a website; we will send requests to it during this tutorial.


apiVersion: gloo.solo.io/v1
kind: Upstream
metadata:
  name: json-upstream
  namespace: gloo-system
spec:
  static:
    hosts:
      - addr: jsonplaceholder.typicode.com
        port: 80

glooctl create upstream static --static-hosts jsonplaceholder.typicode.com:80 --name json-upstream

Creating an authentication service

This authentication service will be a gRPC authentication service. For more information, view the service spec in the official docs.

To use an example gRPC authentication service provided for this guide, run the following command to deploy the provided image. This will run a docker image that contains a simple gRPC service running on port 9001.

kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: extauth-grpcservice
spec:
  selector:
    matchLabels:
      app: grpc-extauth
  replicas: 1
  template:
    metadata:
      labels:
        app: grpc-extauth
    spec:
      containers:
        - name: grpc-extauth
          image: quay.io/solo-io/passthrough-grpc-service-example
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 9001
EOF

The source code for the gRPC service can be found in the Gloo Gateway repository here.

Once we create the authentication service, we also want to apply the following Service to assign it a static cluster IP.

kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: example-grpc-auth-service
  labels:
      app: grpc-extauth
spec:
  ports:
  - port: 9001
    protocol: TCP
  selector:
      app: grpc-extauth
EOF

Creating a Virtual Service

Now let’s configure Gloo Gateway to route requests to the upstream we just created. To do that, we define a simple Virtual Service to match all requests that:

Apply the following virtual service:

apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
  name: auth-tutorial
  namespace: gloo-system
spec:
  virtualHost:
    domains:
      - 'foo'
    routes:
      - matchers:
        - prefix: /
        routeAction:
          single:
            upstream:
              name: json-upstream
              namespace: gloo-system
        options:
          autoHostRewrite: true

Let’s send a request that matches the above route to the gateway proxy and make sure it works:

curl -H "Host: foo" $(glooctl proxy url)/posts/1

The above command should produce the following output:

{
  "userId": 1,
  "id": 1,
  "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
  "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}

If you are getting a connection error, make sure you are port-forwarding the glooctl proxy url port to port 8080.

Securing the Virtual Service

As we just saw, we were able to reach the upstream without having to provide any credentials. This is because by default Gloo Gateway allows any request on routes that do not specify authentication configuration. Let’s change this behavior. We will update the Virtual Service so that all requests will be authenticated by our own auth service.

kubectl apply -f - <<EOF
apiVersion: enterprise.gloo.solo.io/v1
kind: AuthConfig
metadata:
  name: passthrough-auth
  namespace: gloo-system
spec:
  configs:
  - passThroughAuth:
      grpc:
        # Address of the grpc auth server to query
        address: example-grpc-auth-service.default.svc.cluster.local:9001
        # Set a connection timeout to external service, default is 5 seconds
        connectionTimeout: 3s
EOF

Passthrough services also allow for failing “open” through the failureModeAllow field. By setting this field to true, the auth service responds with an OK if either your server returns a 5XX-equivalent response or the request times out.

Once the AuthConfig has been created, we can use it to secure our Virtual Service:

kubectl apply -f - <<EOF
apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
  name: auth-tutorial
  namespace: gloo-system
spec:
  virtualHost:
    domains:
      - 'foo'
    routes:
      - matchers:
        - prefix: /
        routeAction:
          single:
            upstream:
              name: json-upstream
              namespace: gloo-system
        options:
          autoHostRewrite: true      
    options:
      extauth:
        configRef:
          name: passthrough-auth
          namespace: gloo-system
EOF

In the above example we have added the configuration to the Virtual Host. Each route belonging to a Virtual Host will inherit its AuthConfig, unless it overwrites or disables it.

Logging

If Gloo Gateway is running on kubernetes, the extauth server logs can be viewed with:

kubectl logs -n gloo-system deploy/extauth -f

If the auth config has been received successfully, you should see the log line:

"logger":"extauth","caller":"runner/run.go:179","msg":"got new config"

Metrics

For more information on how Gloo Gateway handles observability and metrics, view our observability introduction.

Testing the secured Virtual Service

The virtual service that we have created should now be secured using our external authentication service. To test this, we can try our original command, and the request should not be allowed through because of missing authentication.

curl -H "Host: foo" $(glooctl proxy url)/posts/1

The output should be empty. In fact, we can see the 403 (Unauthorized) HTTP status code if we run the same curl, but with a modification to print the http code to the console.

curl -s -o /dev/null -w "%{http_code}" -H "Host: foo" $(glooctl proxy url)/posts/1

The sample gRPC authentication service has been implemented such that any request with the header authorization: authorize me will be authorized. We can easily add this header to our curl request as follows:

curl -H "Host: foo" -H "authorization: authorize me" $(glooctl proxy url)/posts/1

The request should now be authorized!

Configuring retries for unresponsive passthrough services

You can configure the Gloo ExtAuth server to retry the connection to the passthrough service in the case that the passthrough service becomes unavailable. Consider the following two scenarios to learn more about how retries to the passthrough service are executed:

Sharing state with other auth steps

The sharing state feature was introduced with Gloo Gateway Enterprise, release 1.6.10. If you are using an earlier version, this will not work.

A common requirement is to be able to share state between the passthrough service, and other auth steps (either custom plugins, or our built-in authentication) . When writing a custom auth plugin, this is possible, and the steps to achieve it are outlined here. We support this requirement by leveraging request and response metadata.

We provide some example implementations in the Gloo Gateway repository at docs/examples/grpc-passthrough-auth/pkg/auth/v3/auth-with-state.go.

Reading state from other auth steps

State from other auth steps is sent to the passthrough service via CheckRequest FilterMetadata under a unique key: solo.auth.passthrough.

Writing state to be used by other auth steps

State from the passthrough service can be sent to other auth steps via CheckResponse DynamicMetadata under a unique key: solo.auth.passthrough.

Passing in custom configuration to Passthrough Auth Service from AuthConfigs

This feature was introduced with Gloo Gateway Enterprise, release 1.6.15. If you are using an earlier version, this will not work.

Custom config can be passed from gloo to the passthrough authentication service. This can be achieved using the config field under Passthrough Auth in the AuthConfig:

kubectl apply -f - <<EOF
apiVersion: enterprise.gloo.solo.io/v1
kind: AuthConfig
  metadata:
    name: passthrough-auth
    namespace: gloo-system
  spec:
    configs:
    - passThroughAuth:
        grpc:
          # Address of the grpc auth server to query
          address: example-grpc-auth-service.default.svc.cluster.local:9001
          # Set a connection timeout to external service, default is 5 seconds
          connectionTimeout: 3s
      config:
        customKey1: "customConfigStringValue"
        customKey2: false
EOF

This config is accessible via the CheckRequest FilterMetadata under a unique key: solo.auth.passthrough.config.

Summary

In this guide, we installed Gloo Gateway Enterprise and created an unauthenticated Virtual Service that routes requests to a static upstream. We spun up an example gRPC authentication service that uses a simple header for authentication. We then created an AuthConfig and configured it to use Passthrough Auth, pointing it to the IP of our example gRPC service. In doing so, we instructed gloo to pass through requests from the external authentication server to the grpc authentication service provided by the user.