This is part 2 in the series: Kong Up and Running
In the previous post we set up Kong using Docker and Docker Compose. Now, we need to configure our gateway to proxy our various APIs correctly. We'll go through the sames steps outlined in the official Kong getting started tutorial. Only this time we'll be using Ansible to automate the process
Before we start
- Code for this tutorial is available on Github
- We'll assume that our kong instance is installed at
api.example.com
- This tutorial uses Ansible. We assume that you have Ansible installed and a basic understanding of how Ansible works.
- I've written some Kong modules which will make it easy for us to configure Kong via the RESTful admin interface. Understanding how to make Ansible modules is beyond the scope of this tutorial. You can read more about creating Ansible modules in: Custom Ansible Module Hello World. For this tutorial we will simply download the files from github.
Configuring Kong with Ansible
In this section we will:
- add an API
- secure access to our API with the
key-auth
plugin - and finally we'll add a consumer who has access to the API
Getting started.
Make sure you're in the kong
directory which we created in Part 1.
1. Install the kong modules
Download the module files from github and put them in the library
directory:
mkdir library && cd library
curl https://raw.githubusercontent.com/toast38coza/ansible-kong-module/master/library/kong_api.py > kong_api.py
curl https://raw.githubusercontent.com/toast38coza/ansible-kong-module/master/library/kong_plugin.py > kong_plugin.py
curl https://raw.githubusercontent.com/toast38coza/ansible-kong-module/master/library/kong_consumer.py > kong_consumer.py
Note: these modules use the requests library. If you haven't already, you need to:
pip install requests
2. Define your Ansible inventory
cd back into the top level kong
directory:
cd ../
Create an inventory file and put the following in it:
nano inventory
[localhost]
localhost ansible_connection=local
Since these commands are all essentially HTTP requests we will be running the playbook directly off the local machine.
3. Create a playbook
We'll put all our plays in a playbook called playbook.yml
. The rest of the tutorial all takes place in playbook.yml
.
touch playbook.yml
With no tasks defined, our playbook should look like this:
- hosts: localhost
vars:
- kong_admin_base_url: "http://api.example.com:8001"
- kong_base_url: "http://api.example.com:8000"
tasks:
- hosts tell our playbook which inventory to run the plays against
- We define variables for the Kong admin interface url (
kong_admin_base_url
) and the base url for Kong: (kong_base_url
).
At this point, you should have the following file structure:
Dockerfile
docker-compose.yml
inventory
[library]
|_ kong_api.py
|_ kong_plugin.py
|_ kong_consumer.py
playbook.yml
- (the docker files are from part 1)
3. Configuring Kong
Let's get started adding some tasks:
Adding an API
First, we will tell Kong to proxy the Mockbin API. Add the following under tasks:
...
tasks:
- name: Register APIs
kong_api:
kong_admin_uri: "{{kong_admin_base_url}}"
name: "mockbin"
upstream_url: "http://mockbin.com"
request_host: "mockbin.com"
request_path: "/mockbin"
strip_request_path: yes
state: present
You can run your playbook with the following command:
ansible-playbook playbook.yml -i inventory
And you should get output something like the following:
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [localhost]
TASK [Register APIs] ***********************************************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0
We have successfully added our first API to Kong.
Note: that that step: Register APIs status is
changed
. That means that Ansible did something. Ansible is designed to be idempotent. We can run this script as many times as we like and be sure that out environment is in exactly the state that this script depicts.
Kong will now proxy our requests nicely. You can try it out:
curl -i http://api.example.com/mockbin
In fact, we can actually add a verification step to our playbook too:
- name: Verify API was added
uri:
url: "{{kong_admin_base_url}}/apis/mockbin"
status_code: 200
- This will ping the admin endpoint for the API with the name mockbin. If a status code other than
200
is returned (e.g.:404
), then this step will fail.
Note: our implementation is slightly different from the Kong docs. We've specified
request_path
, therefore our API is accessible on the/mockbin
path. Since we've also set therequest_host
, our API could also be accessed using theHost
header as per the official quickstart tutorial.
Note also that we've setstrip_request_path
toTrue
. This is necessary, otherwise, if we go to:api.example.com/mockbin
the upstream base url will become:http://mockbin.com/mockbin
(instead of just:http://mockbin.com
). The default value forstrip_request_path
isFalse
Add authentication to our API
Next up, let's add key authentication to our mockbinAPI.
Add the following tasks to playbook.yml
- name: Add key authentication
kong_plugin:
kong_admin_uri: "{{kong_admin_base_url}}"
api_name: "mockbin"
plugin_name: "key-auth"
state: present
and run the playbook with: ansible-playbook playbook.yml -i inventory
Now, if we make a request to our API, we should get a 401 Unauthorized
:
curl -i http://api.example.com/mockbin
Of course, we can automatically check this worked by adding a verification step to our playbook:
- name: Verify key auth was added
uri:
url: "{{kong_base_url}}/mockbin"
status_code: 401
This will ping our API with no credentials and verify that the correct status code is returned.
Add a consumer
Now, since we anticipate that we will need to add a number of different consumers over time, we're going to add our consumers as a variable. To the vars block at the top of the page add the kong_consumers
variable:
- hosts: localhost
vars:
- kong_admin_base_url: "http://192.168.99.100:8001"
- kong_base_url: "http://192.168.99.100:8000"
- kong_consumers:
- username: Jack
key: 123
- username: Jill
key: 456
tasks:
...
- This will create two consumers, Jack and Jill, with the auth-keys: 123, and 456 respectively.
Note: You would probably want to handle your api-keys a little differently, but for the purpose of this tutorial we'll just hard-code them like that.
Now, we add our consumers like so:
- name: Add a consumer
kong_consumer:
kong_admin_uri: "{{kong_admin_base_url}}"
username: "{{item.username}}"
state: present
with_items: "{{kong_consumers}}"
- Notice that we pass in our
kong_consumers
list towith_items
. That means that should we want to add new consumers, we can simply add them to the variable.
Tip:
with_items
is also a neat way to add multiple APIs.
and then we need to configure our consumer by providing it with a key:
- name: Configure consumer
kong_consumer:
kong_admin_uri: "{{kong_admin_base_url}}"
username: "{{item.username}}"
api_name: key-auth
data:
key: "{{item.key}}"
state: configure
with_items: "{{kong_consumers}}"
Finally: we can verify that these users are now able to access our API with their keys:
- name: Verify consumers can access API
uri:
url: "{{kong_base_url}}/mockbin"
HEADER_apikey: "{{item.key}}"
status_code: 200
with_items: "{{kong_consumers}}"
Conclusion
Nicely done. You are now able to configure your Kong API in an easy and reliable manner. You can be confident that it is in the state that you expect by simply running you Ansible playbook.
ansible-playbook playbook.yml -i inventory
From here, you can add more APIs, plugins and consumers.
- Next up, we will deploy and secure our Kong API gateway (coming soon ...)