Protecting Kong API gateway using Let's Encrypt
Tags: kong, api, gateway, letsencrypt
Published: 2021-09-09 08:01:13

For the last several months, I am using the awesome [Kong API gateway](https://konghq.com/kong/) to monitor, protect, and scale our microservices. So far, I am learning something new and amazing about this powerful API gateway each day. Previously, I used the certbot's standalone authentication method to retrieve SSL certificates for the gateway but that resulted in renewal problems as Kong service itself needed to be stopped in order to get an SSL certificate renewed.

Today, I tried a different approach. As Kong uses NGINX, I succeeded in obtaining SSL certificates for our API gateway by writing some custom NGINX conf.

First of all, I got started by editing `/etc/kong/kong.conf` file. The file looked like this after I edited and saved it:

```bash
pg_user = kong
pg_password = mydbpass
proxy_listen = 0.0.0.0:80 reuseport backlog=16384, 0.0.0.0:443 http2 ssl reuseport backlog=16384
nginx_http_include = /etc/kong/nginx.conf
``` 
You will notice above that I have instructed Kong to included a custom NGINX conf file. After that, I created the NGINX conf file at `/etc/kong/nginx.conf` with the following content:

```bash
server {
    listen  80;
    server_name     api.myservice.tld;
    server_tokens   off;

    root /var/certbot/web;

    location /.well-known {
        try_files $uri $uri/ =404;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}
```

What does the above NGINX conf do? It routes the HTTP requests to a custom path that I have mentioned and that we will create below, and if the path doesn't match, it redirects the requests to HTTPs.

When we request an SSL certificate from Let's Encrypt using certbot, there are several authentication methods that certbot supports in order to verify the ownership of the domain. The HTTP method that's most common uses a webroot to store some authentication files in and then Let's Encrypt server looks for those files over the domain. The above NGINX configuration allows Let's Encrypt to access the verification content over HTTP and if the path isn't for ACME verification, it redirects to HTTPs.

As I have specified the root path in above NGINX conf, I needed to create the directory as well:

```bash
mkdir /var/certbot/web
```

And restart Kong:
```bash
service kong restart
```

We are almost ready. Now before attempting to obtain an SSL certificate, we need to ensure a couple of things:

1. Our domain is pointed to our server and is not forcing an HTTPs redirect from a CDN end, i.e. Cloudflare
2. Certbot is installed

If certbot isn't installed, it can be installed using `snap` on Ubuntu:
```bash
snap install certbot --classic
```

That's it. Now we are ready. Now we have to run certbot in certonly mode:

```bash
certbot certonly
```

And choose the webroot method when prompted. Provide your domain name that you are using with Kong and that you have added in the custom NGINX conf above, provide the webroot path, i.e. `/var/certbot/web/` and press enter. If all goes well, you will be presented with a success message and the paths of the cert files will be mentioned.

Copy the paths of the cert files and once again edit the Kong conf file located at `/etc/kong/kong.conf`. Add these two lines to the Kong conf file:

```bash
ssl_cert = /etc/letsencrypt/live/api.myservice.tld/fullchain.pem
ssl_cert_key = /etc/letsencrypt/live/api.myservice.tld/privkey.pem
```

Ensure that you are providing the correct SSL file paths. After editing the Kong conf file, it should look something like this:

```bash
pg_user = kong
pg_password = mydbpass
proxy_listen = 0.0.0.0:80 reuseport backlog=16384, 0.0.0.0:443 http2 ssl reuseport backlog=16384
ssl_cert = /etc/letsencrypt/live/api.myservice.tld/fullchain.pem
ssl_cert_key = /etc/letsencrypt/live/api.myservice.tld/privkey.pem
nginx_http_include = /etc/kong/nginx.conf
```
Restart Kong:
```bash
service kong restart
```
And now your Kong installation should be served over HTTPs. The good news is that now you don't need to worry about the SSL renewals as they will not fail even if Kong service is up and using port 80.

I found this to be an easy and elegant way to secure a Kong installation using free SSL certificates from Let's Encrypt. Do you know any better way to do this? Leave a comment and I'll give it a try :)