gRPC Example

This example demonstrates how to set up a Gateway that terminates TLS traffic and routes requests to a gRPC service (i.e. using HTTP/2). In order for this example to work, ALPN support needs to be enabled with the Helm flag gatewayAPI.enableAlpn set to true. This enables clients to request HTTP/2 through the TLS negotiation.

apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
  name: tls-gateway
spec:
  gatewayClassName: cilium
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    hostname: grpc-echo.cilium.rocks
    tls:
      certificateRefs:
      - kind: Secret
        name: grpc-certificate
---
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
  name: grpc-route
spec:
  parentRefs:
  - name: tls-gateway
  rules:
  - backendRefs:
    - name: grpc-echo
      port: 7070
---
apiVersion: v1
kind: Service
metadata:
  name: grpc-echo
spec:
  selector:
    app.kubernetes.io/name: grpc-echo
  ports:
    - name: grpc
      port: 7070
      # This is needed to instruct the route to use plaintext HTTP/2 or
      # you will get protocol errors.
      appProtocol: kubernetes.io/h2c
      targetPort: grpc
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: grpc-echo
  labels:
    app.kubernetes.io/name: grpc-echo
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: grpc-echo
  template:
    metadata:
      labels:
        app.kubernetes.io/name: grpc-echo
    spec:
      containers:
        - name: app
          image: gcr.io/istio-testing/app:latest
          ports:
            - name: grpc
              containerPort: 7070
          readinessProbe:
            failureThreshold: 2
            grpc:
              port: 7070
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 1

This example uses a TLS certificate signed by a made-up, self-signed certificate authority (CA). One easy way to do this is with mkcert. The certificate will validate the hostname grpc-echo.cilium.rocks used in this example.

$ mkcert bookinfo.cilium.rocks hispter.cilium.rocks
Created a new local CA 💥
Note: the local CA is not installed in the system trust store.
Run "mkcert -install" for certificates to be trusted automatically ⚠

Created a new certificate valid for the following names 📜
 - "grpc-echo.cilium.rocks"

The certificate is at "./grpc-echo.cilium.rocks.pem" and the key at "./grpc-echo.cilium.rocks-key.pem" ✅

It will expire on 28 September 2027 🗓

Create a Kubernetes secret with this demo key and certificate:

$ kubectl create secret tls grpc-certificate --key=grpc-echo.cilium.rocks-key.pem --cert=grpc-echo.cilium.rocks.pem

Deploy the Gateway and GRPCRoute

This sets up a simple gRPC echo server and a Gateway to expose it.

$ kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/HEAD/examples/kubernetes/gateway/grpc-tls-termination.yaml

The self-signed certificate Secrets from the previous step will be used by this Gateway.

External IP address will be shown up in Gateway. Also, the host names should show up in related HTTPRoutes.

$ kubectl get gateway tls-gateway
NAME          CLASS    ADDRESS         PROGRAMMED   AGE
tls-gateway   cilium   10.104.247.23   True         29s

$ kubectl get grpcroutes
NAME         HOSTNAMES   AGE
grpc-route               116s

gRPC-web Translation

Cilium Gateway API enables Envoy’s gRPC-web to gRPC request translation by default. To pass gRPC-web requests through unchanged for all Gateways using a parameterized GatewayClass, set httpOptions.grpcWebTranslation.enabled to false in the CiliumGatewayClassConfig referenced by the GatewayClass. See Disable gRPC-web translation for an example.

Update /etc/hosts with the host names and IP address of the Gateway:

$ sudo perl -ni -e 'print if !/\.cilium\.rocks$/d' /etc/hosts; sudo tee -a /etc/hosts \
  <<<"$(kubectl get gateway tls-gateway -o jsonpath='{.status.addresses[0].value}') grpc-echo.cilium.rocks"

Make gRPC Requests

You can use the grpcurl cli tool to verify that the service works correctly. The echo server used in this example will respond with information about the HTTP/2 request the client made.

By specifying the CA’s certificate on a curl request, you can say that you trust certificates signed by that CA.

$ grpcurl -cacert ~/.local/share/mkcert/rootCA.pem grpc-echo.cilium.rocks:443 proto.EchoTestService/Echo

If you prefer, instead of supplying the CA you can specify -insecure to tell the curl client not to validate the server’s certificate. Without either, you will get an error that the certificate was signed by an unknown authority.