Proxy gRPC traffic with Kong Gateway
AWS cloud devops

Proxy gRPC traffic with Kong Gateway

COPPER Nguyen

We usually use gRPC for internal service communication, but sometime we need to expose the connection for 3rd party or another client to connect. The architecture is almost same as the image below.

We have several gRPC service listen port diference port, we placed Kong Gateway in the front of them. gRPC client will connect to Kong though HTTP/2 and use ALTS.

ALTS authentication
An overview of gRPC authentication in Go using Application Layer Transport Security (ALTS).

I will use a widecard certificate for Kong Gateway, the FQDN is *.dongnguyen.link.

So let start.

Deploy Kong Gateway

I will deploy Kong using docker-compose for testing purpose. The docker-compose.yml content is below.

version: "3.9"

networks:
  default:
    name: kong-db-less
    driver: bridge

configs:
  kong:
    file: kong.yaml
  cert:
    file: kong.crt
  key:
    file: kong.pem

x-kong-env:
  &kong-env
  KONG_DATABASE: "off"
  KONG_DECLARATIVE_CONFIG: /home/kong/kong.yaml
  KONG_PROXY_ACCESS_LOG: /dev/stdout
  KONG_ADMIN_ACCESS_LOG: /dev/stdout
  KONG_PROXY_ERROR_LOG: /dev/stderr
  KONG_ADMIN_ERROR_LOG: /dev/stderr
  KONG_ADMIN_LISTEN: 0.0.0.0:8001
  KONG_PROXY_LISTEN: 0.0.0.0:443 http2 ssl
  KONG_SSL_CERT: /etc/ssl/kong.crt
  KONG_SSL_CERT_KEY: /etc/ssl/kong.pem

services:
  kong:
    image: kong
    environment: *kong-env
    configs:
      - source: kong
        target: /home/kong/kong.yaml
      - source: cert
        target: /etc/ssl/kong.crt
      - source: key
        target: /etc/ssl/kong.pem
    privileged: true
    restart: always
    ports:
      - 443:443
      - 8001:8001
docker-compose.yml

In this directory we also have
- kong.crt is the fullchain CA certification that kong use for https listener
- kong.pem is the private key for tls
- kong.yaml is the kong declartive file, our kong will run in db less mode, so the kong admin api is read only.

The current directory

❯ tree                                       
.
├── docker-compose.yml
├── kong.crt
├── kong.pem
├── kong.yaml

1 directory, 4 files

The kong.yaml define all service and also route to the service.

_format_version: "3.0"
_transform: true

services:
  - name: order
    host: 192.168.1.115
    port: 9000
    protocol: grpc
    tags:
      - order
    routes:
      - name: order
        preserve_host: true
        snis:
          - order.dongnguyen.link
        strip_path: false
        protocols:
          - grpcs

  - name: noti
    host: 192.168.1.115
    port: 10000
    protocol: grpc
    tags:
      - noti
    routes:
      - name: noti
        preserve_host: true
        snis:
          - noti.dongnguyen.link
        strip_path: false
        protocols:
          - grpcs
kong.yaml

As you can see, in this kong.yaml file above, i defined two services order and api.
Kong will proxy traffic to order service if they recieved request with SNI equal to order.dongnguyen.link, the order service is listening on 192.168.1.115:9000 behind kong.

Kong will proxy traffic to noti service if they recieved request with SNI equal to noti.dongnguyen.link, the noti service is listening on 192.168.1.115:1000 behind kong.

Now deploy kong using docker compose cli.

docker compose up
docker compose up

View Kong Service Route by KongA

Kong Inc did not provide us the management UI for community version,  but luckily we have https://github.com/pantsel/konga, please checkout this site to deploy a konga server.

GitHub - pantsel/konga: More than just another GUI to Kong Admin API
More than just another GUI to Kong Admin API. Contribute to pantsel/konga development by creating an account on GitHub.

For me i already deployed on my host machine. So i can access kong admin api though port 8001 on host machine.

Go to Services tab, you will see that we have 2 defined services.

Go to Routes tab, you will see that we have 2 defined routes.

Deploy Dummy gRPC Server

We will use https://github.com/moul/grpcbin to deployed 2 fake gRPC server that listen on port 9000 and also 10000.

Order service listen on port 9000

docker run -it --rm -p 9000:9000 -p 9001:9001 moul/grpcbin

Noti service listen on port 10000

docker run -it --rm -p 10000:9000 -p 10001:9001 moul/grpcbin

Send Test Request

I will use https://github.com/fullstorydev/grpcurl to send traffic to two servers above.

  1. Call order.dongnguyen.link
docker run fullstorydev/grpcurl -v -d \
    '{"greeting": "Kong gRPC"}' \
    order.dongnguyen.link:443 hello.HelloService.SayHello

From stdout you can see that kong proxied traffic to order service.

2. Call order.dongnguyen.link

docker run fullstorydev/grpcurl -v -d \
    '{"greeting": "Kong gRPC"}' \
    order.dongnguyen.link:443 hello.HelloService.SayHello
    

The result is same as above.

3. Call whatever.dongnguyen.link

It failed because there is no route with SNI equal to whatever.dongnguyen.link

That is, this approch is easy to implement, thank for reading the post.