EnRoute Kubernetes Ingress With Self-Signed Certificate

EnRoute Kubernetes Ingress With Self-Signed Certificate

Published February 02, 2022
Last Modified February 05, 2022

EnRoute OneStep Gateway

EnRoute Universal Gateway is a an API gateway built to support traditional and cloud-native use cases. It is designed to run either as a Kubernetes Ingress Gateway, Standalone Gateway, Horizontally scaling L7 API gateway or a Mesh of Gateways. Depending on the need of the user, the environment, the application, either one or many of these solutions can be deployed.

EnRoute also supports plugins/filters to extend functionality and enforce policies. The features page lists the available plugins for the Gateway. More details about each of the plugins can also be found on plugin pages.

A consistent policy framework across all these network components makes the EnRoute Universal Gateway a versatile and powerful solution.

What this article covers

This article covers how to use a self-signed certificate with EnRoute Kubernetes Ingress Gateway. The minimum requirement is a working Kubernetes cluster.

To get a more detailed understanding of EnRoute Universal Gateway and its architecture, refer to the article here To run EnRoute outside of kubernetes as a standalone gateway, refer to the article on standalone gateway

EnRoute also supports several other topologies including a Standalone Gateway. Only the Kubernetes Ingress topology is covered in this article.

Configure EnRoute using helm

A simple non-SSL example of EnRoute gateway with Lua and Rate-Limit filters can be programmed using the EnRoute helm chart.

Add the helm chart -

helm repo add saaras https://getenroute.io

Check repositories -

helm search repo
NAME                    CHART VERSION   APP VERSION     DESCRIPTION
saaras/enroute          0.5.0           v0.8.0          EnRoute API Gateway
saaras/service-policy   0.3.1           0.8.0           Service L7 Policy using EnRoute API Gateway

Install the helm chart -

helm install enroute-demo saaras/enroute   \
    --set serviceAccount.create=true --create-namespace --namespace enroutedemo
NAME: enroute-demo
LAST DEPLOYED: Tue Dec 28 01:37:05 2021
NAMESPACE: enroutedemo
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
###################
# π™΄πš—πšπš˜πšžπšπšŽ πš‚πšŽπš›πšŸπš’πšŒπšŽ #
###################

It got installed in namespace: enroutedemo

This installs the EnRoute Ingress API Gateway.

kubectl get svc -n enroutedemo
NAME           TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)                      AGE
enroute-demo   LoadBalancer   10.43.113.134   212.2.246.47   80:32365/TCP,443:32120/TCP   50s

Questions about the helm chart?       Slack        Send Us a Note        

However we still need to program the gateway to expose a service. Let us start by creating a demo namespace and a demo service.

kubectl create namespace demo-service
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: httpbin
  namespace: demo-service
  labels:
    app: httpbin
spec:
  containers:
  - name: httpbin
    image: kennethreitz/httpbin
    ports:
      - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin
  namespace: demo-service
spec:
  selector:
    app: httpbin
  ports:
  - port: 80
EOF

This creates a demo service in demo-service namepspace.

Now lets expose this service using a simple helm command

helm install httpbin-service-policy saaras/service-policy    \
     --set service.name=httpbin                              \
     --set service.prefix=/get                               \
     --set service.port=80                                   \
     --namespace demo-service
NAME: httpbin-service-policy
LAST DEPLOYED: Tue Dec 28 01:54:03 2021
NAMESPACE: demo-service
STATUS: deployed
REVISION: 1
NOTES:
##########################
# π™΄πš—πšπš˜πšžπšπšŽ πš‚πšŽπš›πšŸπš’πšŒπšŽ π™Ώπš˜πš•πš’πšŒπš’ #
##########################

It got installed in namespace: demo-service

The above command makes the service httpbin running on port 80 externally visible on path /get

Let’s check all the helm charts installed

helm ls --all-namespaces
NAME                    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
enroute-demo            enroutedemo     1               2021-12-28 01:37:05.978469338 +0000 UTC deployed        enroute-0.5.0           v0.8.0
httpbin-service-policy  demo-service    1               2021-12-28 01:54:03.485778209 +0000 UTC deployed        service-policy-0.3.1    0.8.0

Use the External IP to send traffic

The EnRoute service can be reached using the External-IP and a request on path /get sends it to the httpbin service

curl 212.2.246.47/get
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Host": "212.2.246.47",
    "User-Agent": "curl/7.68.0",
    "X-Envoy-Expected-Rq-Timeout-Ms": "15000",
    "X-Envoy-Internal": "true"
  },
  "origin": "10.42.0.41",
  "url": "http://212.2.246.47/get"
}

Adding SSL with a self-signed certificate

The above config does not add SSL config. For SSL to work, we need a certificate installed with the appropriate domain name.

Let’s install a SSL certificate for both the httpbin service.

Create a self-signed certificate

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -subj '/CN=hello-enroute.enroutedemo.com' -nodes

Create a Kubernetes Secret with the self-signed certificate created in previous step

kubectl create secret tls -n demo-service hello-enroute-tls-secret --cert=./cert.pem --key=./key.pem

Update the GatewayHost for the service

When we exposed the service using the helm command above, a GatewayHost was created for it. Here we edit the GatewayHost to add TLS

Note that we have added the fields fqdn and tls to GatewayHost

kubectl edit -n demo-service gatewayhosts.enroute.saaras.io httpbin-80-gatewayhost
# Update GatewayHost

# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: enroute.saaras.io/v1
kind: GatewayHost
metadata:
  annotations:
    meta.helm.sh/release-name: httpbin-service-policy
    meta.helm.sh/release-namespace: demo-service
  creationTimestamp: "2022-02-05T23:44:49Z"
  generation: 4
  labels:
    app: httpbin
    app.kubernetes.io/managed-by: Helm
  name: httpbin-80-gatewayhost
  namespace: demo-service
  resourceVersion: "7900"
  uid: bc4f1e2e-6fa9-4bdf-b687-0e94d747eedd
spec:
  routes:
  - conditions:
    - prefix: /get
    filters:
    - name: httpbin-80-rl2
      type: route_filter_ratelimit
    services:
    - healthCheck:
        healthyThresholdCount: 3
        host: hc
        intervalSeconds: 5
        path: /
        timeoutSeconds: 3
        unhealthyThresholdCount: 3
      name: httpbin
      port: 80
  virtualhost:
    filters:
    - name: httpbin-80-luatestfilter
      type: http_filter_lua
    fqdn: hello-enroute.enroutedemo.com
    tls:
      secretName: hello-enroute-tls-secret

Create a DNS entry to resolve hello-enroute.enroutedemo.com to the LoadBalancer IP of EnRoute service 212.2.240.30 by updating /etc/hosts or on Route53 or a DNS provider

curl -k -v https://hello-enroute.enroutedemo.com/get

Alternatively, you can force curl to resolve to the LoadBalancer IP by using the following command

curl -k -v https://hello-enroute.enroutedemo.com/get --resolve hello-enroute.enroutedemo.com:443:212.2.240.30
...
* Server certificate:
*  subject: CN=hello-enroute.enroutedemo.com
*  start date: Feb  5 23:55:44 2022 GMT
*  expire date: Feb  5 23:55:44 2023 GMT
*  issuer: CN=hello-enroute.enroutedemo.com
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
...
> GET /get HTTP/2
> Host: hello-enroute.enroutedemo.com
> user-agent: curl/7.68.0
> accept: */*
>
...
< HTTP/2 200
< server: envoy
< date: Sun, 06 Feb 2022 00:09:17 GMT
< content-type: application/json
< content-length: 370
< access-control-allow-origin: *
< access-control-allow-credentials: true
< x-envoy-upstream-service-time: 6
< vary: Accept-Encoding
<
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Host": "hello-enroute.enroutedemo.com",
    "User-Agent": "curl/7.68.0",
    "X-Envoy-Expected-Rq-Timeout-Ms": "15000",
    "X-Envoy-Internal": "true"
  },
  "origin": "10.42.0.7",
  "url": "https://hello-enroute.enroutedemo.com/get"
}
* Connection #0 to host hello-enroute.enroutedemo.com left intact

Questions about SSL/TLS?       Slack        Send Us a Note        

Helm switches to enable/disable features

EnRoute helm chart provides configuration options for multiple clouds and switches to enable/disable plugins or filters. These switches provide a fine-grained control over L7 policy.

The EnRoute Helm chart supports the following filter switches -

One of -
["true", "false"]
SwitchValid ValuesDescription
envoySettings.logLevelOne of -
["trace", "debug", "info", "error"]
Log level for underlying Envoy (chart: enroute)
EnRoute Ingress Controller Service Settings (chart: enroute)
enrouteService.enableOne of -
["true", "false"]
Disabled by default. Enable when installing EnRoute the first time.
Enables creation of EnRoute deployment and service
enrouteService.replicaCountNumber of replicas eg: 3By default, one instance of EnRoute pod is created
Change this value to increase/decrease count of replicas
Proxy Protocol Support (chart: enroute)
service.useproxyprotocolDisabled by default. Enable when proxy protocol support needs to be enabled.
Enables propagation of client-IP to backend service
Filter Settings (chart: service-policy)
filters.lua.enableOne of -
["true", "false"]
Enabled by default. Enable when you want to install a Lua filter for service.
filters.ratelimit.enableOne of -
["true", "false"]
Enabled by default. Enable when you want to install a RateLimit filter for service.
filters.cors.enableOne of -
["true", "false"]
Disabled by default. Enable when you want to install a CORS filter for service.
filters.jwt.enableOne of -
["true", "false"]
Disabled by default. Enable when you want to install a JWT filter for service.
Service Settings (chart: service-policy)
service.nameA string representing service name in KubernetesDefault is "hello-enroute" service. Set it to your own service name
service.portPort on which to access this serviceDefault is 9090, the port for "hello-enroute" service. Set it to your own service port
service.enableTLSWhen securing the service using TLS, use this flag after cert-manager has been setup.Default is false. Enable this flag to automatically get a certificate for a service from Let's encrypt
service.namespaceThe namespace in which the service is runningThis setting is used to determine the namespace in which to create EnRoute Filters and ```GatewayHost```
service.prefixThe prefix on which the service is reachableThis installs the prefix route for this service
Auto-TLS Settings (chart: service-policy)
autoTLS.issueCertOne of -
["true", "false"]
Enable this to issue a certificate signed using the ACME protocol (from Let's Encrypt)
autoTLS.certificateCNCommon Name for CertificateCommon Name to use for Certificate. This also gets installed as ```fqdn``` for the service
autoTLS.enableProdOne of -
["true", "false"]
Default is false.
When set to false, it uses the ACME staging server
https://acme-staging-v02.api.letsencrypt.org/directory .
When set to true, it uses the ACME production server
https://acme-v02.api.letsencrypt.org/directory
As filters/plugins are added to EnRoute, simple switches will allow enabling/disabling these features.

Questions about the helm chart?       Slack        Send Us a Note        

Enforcing L7 Policies

EnRoute uses filter/plugin to add functionality to Ingress for a service. These Filters/Plugins loosely map to Envoy filters/plugins and can be enabled/disabled using the helm chart. The complete list of plugins supported in the helm chart and examples are covered in the Enforce L7 Policy blog

Next Steps

Working with EnRoute Ingress API Gateway is organized in following steps