Seit dem letzten Blogpost zu diesem Thema von Alexander Melnyk sind fast zwei Jahre vergangen, und es ist in Sachen „API-Management mit Kong“ eine Menge passiert. Daher war es an der Zeit, zum einen die Inhalte des Posts von Alexander zu aktualisieren und zum anderen das Thema „API-Management mit Kong“ und das Produkt Kong detaillierter zu betrachten. Dieser Post stellt den Beginn einer Serie von Beiträgen dar, welche in nächster Zeit erscheinen werden. Der Schwerpunkt der Serie wird erst einmal auf dem Open-Source-Produkt liegen, d.h. auf dem API-Gateway Kong .
Aufbau der Infrastruktur
Um euch nicht mit Inhalten aus den Release Notes zu langweilen, wird direkt technisch eingestiegen. Die Grundlage für die folgenden Betrachtungen stellt die Infrastruktur auf Basis eines docker-compose-File dar, welches im GitHub-Repo zum Artikel gefunden werden kann. Zudem benötigt man ein API. Hierfür wird das Python-Framework FastAPI verwendet, welches das API in Form von drei Endpunkten (/
(root), service1
, service2
) in einem Container mittels Dockerfile bereitstellt. Auch das API ist ein Teil des Repos.
1from fastapi import FastAPI
2
3app = FastAPI()
4
5@app.get("/")
6def read_root():
7 return {"Hello": "World"}
8
9@app.get("/api/service1")
10def read_service1():
11 return {"status_code": 200, "message": "service1 is called"}
12
13@app.get("/api/service2")
14def read_service2():
15 return {"status_code": 200, "message": "service2 is called"}
1FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7 2 3COPY ./app /app
1version: '3' 2networks: 3 kong-blogposts: 4 driver: bridge 5 6services: 7 api-service: 8 build: ./api-service 9 networks: 10 - kong-blogposts 11 expose: 12 - 80 13 ports: 14 - "80:80" 15 16 kong-database: 17 container_name: kong-database 18 image: postgres:9.6 19 restart: always 20 networks: 21 - kong-blogposts 22 environment: 23 - POSTGRES_USER=kong 24 - POSTGRES_DB=kong 25 healthcheck: 26 test: ["CMD", "pg_isready", "-U", "kong"] 27 interval: 10s 28 timeout: 5s 29 retries: 5 30 31 kong-migration: 32 image: kong 33 depends_on: 34 - "kong-database" 35 container_name: kong-migration 36 networks: 37 - kong-blogposts 38 restart: on-failure 39 environment: 40 - KONG_DATABASE=postgres 41 - KONG_PG_HOST=kong-database 42 - KONG_PG_DATABASE=kong 43 command: kong migrations bootstrap 44 45 kong: 46 container_name: kong 47 image: kong:latest 48 depends_on: 49 - "kong-migration" 50 - "kong-database" 51 restart: always 52 networks: 53 - kong-blogposts 54 environment: 55 - KONG_DATABASE=postgres 56 - KONG_PG_HOST=kong-database 57 - KONG_PG_DATABASE=kong 58 - KONG_PROXY_LISTEN=0.0.0.0:8000 59 - KONG_ADMIN_LISTEN=0.0.0.0:8001 60 ports: 61 - 8000:8000 62 - 8001:8001 63 - 8443:8443 64 - 8444:8444 65 healthcheck: 66 test: ["CMD-SHELL","curl -I -s -L http://localhost:8000 || exit 1"] 67 interval: 5s 68 retries: 10
Die docker-compose
-Definition erzeugt die drei Services kong
, kong-database
und kong-migration
. Als Datenbank bzw. DataStore-Komponente werden wir PostgreSQL benutzen. Der kong
-Service als API-Gateway stellt vier Ports für zwei Endpunkte bereit, zum einen den Consumer- und zum anderen den Admin-Endpunkt, jeweils für http und https.
Um den kong
-Service zu betreiben, wird der kong-migration
-Service zur initialen Generierung der Objekte in der kong-database
verwendet. Das Befüllen der Datenbank wird leider nicht durch den kong
-service erledigt. Die Services werden mit docker-compose up
gestartet. Mit dem Befehl docker-compose ps
erhalten wir nun eine Übersicht der laufenden Dienste.
Zuerst schaut man, ob Kong erreichbar ist. Hierzu überprüft man den Status des API-Gateways mit einer GET
-Anfrage an das Admin-API. Der Aufruf http localhost:8001/status
sollte den Statuscode 200
zurückliefern. Hierzu benutze ich persönlich das Tool httpie .
Von Services, Routen, Consumern und Plugins
Man sieht, dass der Zugriff auf das Kong-Admin-API funktioniert, aber bisher noch keine APIs konfiguriert sind. Nun wird ein API hinzugefügt, das aus einem Service und Route besteht. Hier zeigt sich eine Veränderung des Admin API. Ab der Version 0.13 wurden Routen und Services für eine bessere Abgrenzung und die Möglichkeit, Plugins auf bestimmte Endpunkte anzuwenden, eingeführt. Um einen Service anzulegen, sendet man einen POST-Request an das Gateway (localhost:8001/services
).
http POST localhost:8001/services/ name=service1 url=http://host.docker.internal/api/service1
Für dieses kurze Einführungsbeispiel werden die anderen möglichen Parameter nicht betrachtet. Da man Kong innerhalb von Docker einsetzt, ist es wichtig die host.docker.internal
IP zu verwenden. Sonst kommt es zu Schwierigkeiten beim Aufruf des API über das API-Gateway.
Nachdem der Service angelegt wurde, muss außerdem noch eine Route erstellt werden.
http POST localhost:8001/services/service1/routes paths:='["/service1"]' name=service1_route methods:='["GET"]'
Über http localhost:8000/service1
lässt sich der Service aufrufen und liefert das folgende Ergebnis zurück.
1HTTP/1.1 200 OK 2Connection: keep-alive 3Content-Length: 50 4Content-Type: application/json 5Via: kong/1.3.0 6X-Kong-Proxy-Latency: 7 7X-Kong-Upstream-Latency: 5 8server: uvicorn 9 10{ 11 "message": "service1 is called", 12 "status_code": 200 13}
Im Regelfall möchte man ja sein API vor unberechtigten Zugriffen schützen bzw. nur dezidierten Usern Zugriff gewähren. In Kong verwendet man hierfür Plugins, die während eines Requests ausgeführt werden. Um entsprechende technische User zur Verfügung zu stellen, bietet Kong eine weitere Entität an: die Consumer.
http post localhost:8001/consumers username=api-user
1HTTP/1.1 201 Created 2Access-Control-Allow-Origin: * 3Connection: keep-alive 4Content-Length: 120 5Content-Type: application/json; charset=utf-8 6Date: Sun, 01 Sep 2019 10:02:54 GMT 7Server: kong/1.3.0 8 9{ 10 "created_at": 1567332174, 11 "custom_id": null, 12 "id": "a37333ea-c346-488b-a1f0-1a0b078ea152", 13 "tags": null, 14 "username": "api-user" 15}
Man fügt dem API das Key Authentication Plugin hinzu und verbindet ebenfalls den Consumer damit. Dadurch wird sichergestellt, dass eben nur dieser Consumer mit einem bestimmten Schlüssel auf das API zugreifen kann.
http post localhost:8001/services/service1/plugins name=key-auth
1HTTP/1.1 201 Created 2Access-Control-Allow-Origin: * 3Connection: keep-alive 4Content-Length: 380 5Content-Type: application/json; charset=utf-8 6Server: kong/1.3.0 7 8{ 9 "config": { 10 "anonymous": null, 11 "hide_credentials": false, 12 "key_in_body": false, 13 "key_names": [ 14 "apikey" 15 ], 16 "run_on_preflight": true 17 }, 18 "consumer": null, 19 "created_at": 1567332763, 20 "enabled": true, 21 "id": "a3b0ea80-98ba-43ed-a3dd-9fb5e1b0bbad", 22 "name": "key-auth", 23 "protocols": [ 24 "grpc", 25 "grpcs", 26 "http", 27 "https" 28 ], 29 "route": null, 30 "run_on": "first", 31 "service": { 32 "id": "3d0d837d-8d42-4764-9111-16f195baf762" 33 }, 34 "tags": null 35}
Es folgt die Überprüfung, ob das Plugin eingerichtet ist.
http localhost:8000/service1
1HTTP/1.1 401 Unauthorized 2Connection: keep-alive 3Content-Length: 41 4Content-Type: application/json; charset=utf-8 5Server: kong/1.3.0 6WWW-Authenticate: Key realm="kong" 7 8{ 9 "message": "No API key found in request" 10}
Nun muss noch ein Schlüssel für den Consumer api-user
erstellt werden. Falls kein key angegeben ist, wird dieser automatisch erstellt.
http post localhost:8001/consumers/api-user/key-auth key=secret_key
1HTTP/1.1 201 Created 2Access-Control-Allow-Origin: * 3Connection: keep-alive 4Content-Length: 145 5Content-Type: application/json; charset=utf-8 6Server: kong/1.3.0 7 8{ 9 "consumer": { 10 "id": "a37333ea-c346-488b-a1f0-1a0b078ea152" 11 }, 12 "created_at": 1567333309, 13 "id": "e65bcc7a-9478-40cc-be6c-0df43bad5b03", 14 "key": "secret_key" 15}
Der Aufruf des API erfolgt mit dem api-key
und liefert das folgende Ergebnis zurück.
http localhost:8000/service1 apikey:secret_key
1HTTP/1.1 200 OK 2Connection: keep-alive 3Content-Length: 50 4Content-Type: application/json 5Via: kong/1.3.0 6X-Kong-Proxy-Latency: 8 7X-Kong-Upstream-Latency: 35 8date: Sun, 01 Sep 2019 10:27:25 GMT 9server: uvicorn 10 11{ 12 "message": "service1 is called", 13 "status_code": 200 14}
Alle gezeigten Schritte lassen sich jetzt auch auf den zweiten Service (service2
) anwenden. Wenn dies vollzogen ist, sind beide Services durch Kong abgesichert.
Ausblick
Schließlich haben wir auch das Ende des ersten Teils der Serie zu Kong erreicht. Ich hoffe, dass Euch dieser erste Post einen Einblick in die Funktionsweise und erste Änderung des Kong-Admin-API gegeben hat. In den folgenden Teilen werde ich neben Kong auch auf Kong Enterprise , die Service Control Platform, eingehen. Seid also gespannt!
Weitere Beiträge
von Daniel Kocot
Dein Job bei codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
Weitere Artikel in diesem Themenbereich
Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog-Autor*in
Daniel Kocot
Senior Solution Architect / Head of API Consulting
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.