//

API-Management mit Kong – Ein Update und mehr

3.9.2019 | 5 Minuten Lesezeit

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"}
16
1FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
2 
3COPY ./app /app
4
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
69

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}
14

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}
16

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}
36

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}
11

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}
16

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}
15

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!

Beitrag teilen

Gefällt mir

0

//

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.