Envoy External Authorization with Golang GRPC service
Tags: envoy, go, grpc, istio
Published: 2023-06-21 12:10:11

---
title: Envoy External Authorization with Golang GRPC service
published: true
description: A guide to connect a GRPC-based Golang service using the Envoy external auth filter
tags: envoy,golang,grpc,istio
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zwx150o2b8yh1uu1e2v.png
# published_at: 2023-06- 12:28 +0000
---
[Envoy](https://www.envoyproxy.io) is a cloud native opensource proxy server. The Envoy proxy offers a variety of http filters to handle incoming requests.

Out of them [External authorisation](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/ext_authz_filter) is a filter type that directs an incoming request to an external service and waits for its authorisation to continue the request.The external service, which has the ability to modify or suspend the incoming request, can be either a grpc_service or a http_service.

Working example: [prakashchokalingam/envoy_ext_auth_grpc_go](https://github.com/prakashchokalingam/envoy_ext_auth_grpc_go)

![envoy filter to go flow diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ek8vgpnh3mystitusajs.png)

Let's look at connecting a GRPC-based Golang service using the Envoy external auth filter.

### Create a golang grpc based server:

###### main.go
```go
package main

import (
  "fmt"
  "net"
  "google.golang.org/grpc"
)

func main() {
  endPoint := fmt.Sprintf("localhost:%d", 3001)
  listen, err := net.Listen("tcp", endPoint)
  
  grpcServer := grpc.NewServer()
  grpcServer.Serve(listen)
}
```

### Extend with go-control-plane protobuf

The above server should be extended and registered with the envoyproxy go-control-plane protobuf server with a check function defined struct.

###### main.go
```go
package main

import (
  "fmt"
  "net"

   auth_pb "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
  "google.golang.org/grpc"
)

func main() {
  // struct with check method
  type AuthServer struct {}
  
  func (server *AuthServer) Check(
    ctx context.Context, 
    request *auth_pb.CheckRequest,
  ) (*auth_pb.CheckResponse, error) {
    fmt.println("All request goes through me")
    
    // block if path is /private
    path = request.Attributes.Request.Http.Path[1:]
    if path == 'private' {
      return nil, fmt.Errorf('private request not allowed')
    }
    
    // allow all other requests
    return &auth_pb.CheckResponse{}, nil
  }


  endPoint := fmt.Sprintf("localhost:%d", 3001)
  listen, err := net.Listen("tcp", endPoint)
  
  grpcServer := grpc.NewServer()
  
  // register envoy proto server
  server := &AuthServer{}
  auth_pb.RegisterAuthorizationServer(grpcServer, server)
  
  grpcServer.Serve(listen)
}
```
If nil is returned in the check method rather than &auth_pb.CheckResponse, the request will be suspended with a 403 error code.

> Note: Envoy will also return 403 if the service is offline or unreachable.

### Last but not least, set up your Envoy 

In your envoy config add the filter `envoy.filters.http.ext_authz`and point it to the Go service cluster

###### envoy.yml

```yml
static_resources:
  listeners:
    - name: listener_0
      address:
        socket_address: { address: 0.0.0.0, port_value: 80 }
      filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                codec_type: auto
                stat_prefix: ingress_http
                route_config:
                  name: local_route
                  virtual_hosts:
                   ...
                http_filters:
                  - name: envoy.filters.http.ext_authz
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
                      transport_api_version: v3
                      grpc_service:
                        envoy_grpc:
                          cluster_name: go_grpc_cluster
                      include_peer_certificate: true
                        ...
  clusters:
    - name: go_grpc_cluster
      connect_timeout: 0.25s
      type: LOGICAL_DNS
      typed_extension_protocol_options:
        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
          "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
          explicit_http_config:
            http2_protocol_options: {}
      load_assignment:
        cluster_name: go_grpc_cluster
        endpoints:
        - lb_endpoints:
          - endpoint:
              address:
                socket_address:
                  address: 127.0.0.1
                  port_value: 3001
```

To see an example snippet for customising headers, [click here](https://github.com/prakashchokalingam/envoy_ext_auth_grpc_go/blob/main/clusters/go_grpc_filter/main.go#L34)

Check out this repository for a fully functional code sample

{% embed https://github.com/prakashchokalingam/envoy_ext_auth_grpc_go %}