For the last several months, I am using the awesome Kong API gateway 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:
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:
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:
mkdir /var/certbot/web
And restart Kong:
service kong restart
We are almost ready. Now before attempting to obtain an SSL certificate, we need to ensure a couple of things:
- Our domain is pointed to our server and is not forcing an HTTPs redirect from a CDN end, i.e. Cloudflare
- Certbot is installed
If certbot isn't installed, it can be installed using snap
on Ubuntu:
snap install certbot --classic
That's it. Now we are ready. Now we have to run certbot in certonly mode:
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:
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:
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:
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 :)
Top comments (2)
Thanks for your article. I am assuming you are using DB-less mode, right? Is it possible to follow this approach while i am using KONG from a docker container?
thank you! work like a charm!