API-Management mit Kong

Keine Kommentare

Die Verwendung von APIs zur Förderung von Innovationen und zur Schaffung neuer Geschäftsmöglichkeiten ist kein neues Konzept. Viele Success Stories von eBay, Netflix, Expedia, mobile.de und vielen anderen zeigen den wachsenden Trend API-getriebener Geschäftsmodelle. Die meisten Anbieter von API-Management-Lösungen sind bekannte Unternehmen wie IBM, Oracle oder MuleSoft, die versuchen, eine Lösung anzubieten, die an ihr bestehendes Ökosystem von Unternehmensprodukten gekoppelt ist. Eine der wenigen Ausnahmen ist Kong Inc (früher bekannt als Mashape Inc), ein in San Fransisco ansässiges Start-up, das in den letzten zwei Jahren durch Open-Sourcing seines Produktes, des Kong API Gateway, populär wurde. In diesem Artikel werde ich kurz das Thema API-Management vorstellen und zeigen, wie man ein Kong API Gateway aufbaut und verwendet.

Warum ist API-Management interessant?

Adaption und Geschwindigkeit zählen zu den wichtigsten Erfolgsfaktoren in der Softwarebranche. Die Ergebnisse dieser Faktoren sind Trends wie Microservices-Architekturen, Continuous Delivery, DevOps-Kultur, agile Softwareentwicklung und Cloud Computing. Um schnell zu sein, muss man ein System in unabhängige Dienste aufteilen und jeden Teil des Systems schnell und reibungslos ändern können. Daraus resultiert eine hohe Nachfrage nach Integrationen zwischen verschiedenen Anwendungen und Diensten. API-Management spielt bei dieser Integration eine wichtige Rolle: Sie schaffen klare Grenzen und Abstraktionen zwischen Systemen. Heutzutage entsteht eine Softwarelösung durch Einkauf und Integration verschiedener Services, statt dass man alles selbst von Grund auf programmiert. Mit dem wachsenden API-Trend haben viele Unternehmen ihr Geschäftsmodell geändert und einige haben sogar vollständig auf einen API-zentrierten Geschäftsansatz umgestellt. Expedia Inc generiert 90% des Umsatzes über das Expedia Affiliate Network, eine API-Plattform. Netflix hat ein Ökosystem von über 1000 APIs aufgebaut, um viele Endgeräte für seine Streaming-Plattform zu unterstützen. Salesforce, einer der am schnellsten wachsenden CRM-Anbieter, generiert über 50 % seines Umsatzes mit APIs. Andere häufige Anwendungen für APIs sind:

  • Nutzer erreichen oder ihre Inhalte erfassen
  • Traffic generieren
  • Partnernetzwerk erweitern
  • neue Einnahmequellen schaffen
  • mehr Geräte für ein Service unterstützen
  • Flexibilität für interne Projekte schaffen
  • Integrationsmöglichkeiten für andere Systeme anbieten

Aber APIs zu verwenden ist nicht besonders einfach, und es hat seinen Preis. Die Kosten für die Vorteile sind eine zunehmende technische und organisatorische Komplexität. In diesem Blogbeitrag werde ich Möglichkeiten zur Bewältigung der technischen Komplexität untersuchen und herausfinden, wie Kong API Gateway dabei helfen kann.

Kong-Architektur

Kong ist ein Open-Source-API-Gateway, um RESTful APIs zu verwalten. Es ist Teil von Kong Enterprise, einem Paket von Kong API Gateway, einem Entwicklerportal namens Gelato und einer Analyseplattform namens Galileo. Es richtet sich an Unternehmenskunden, die Tausende von APIs haben und einen dedizierten Support rund um die Uhr benötigen. Für kleine bis mittelgroße Unternehmen reicht das Kong API Gateway (Community Edition) aus, um erste Schritte in der API-Verwaltung zu machen.

API-Management Kong Architektur


Kong-Architektur mit fünf Komponenten.

Die fünf Komponenten der Kong-Architektur sind: nginx, OpenResty, Datastore, Plugins und eine RESTful Admin API. Die grundlegende Low-Level-Komponente ist nginx, ein bekannter und erprobter Webserver. Im Jahr 2017 nutzen 35,5% aller bekannten und 54,2% der Top 100.000 Websites weltweit nginx. Es kann bis zu 10.000 gleichzeitige Verbindungen auf einem Knoten mit geringem Speicherbedarf verarbeiten und wird häufig als Reverse-Proxy in Microservice-Architekturen, als Load-Balancer, als SSL-Terminierung-Proxy oder als Webserver für statische Inhalte verwendet. Abgesehen von diesen Anwendungsfällen hat nginx viele weitere Funktionen, die separate Blogbeiträge verdienen. OpenResty ist eine Webplattform, die nginx, LuaJIT-, Lua-Bibliotheken und nginx-Module von Drittanbietern vereint, um einen Webserver für skalierbare Webanwendungen und Webservices bereitzustellen. Es wurde ursprünglich von taobao.com gebaut, der größten Online-Auktionsplattform in Asien mit 368 Millionen aktiven Nutzern (2017), und 2011 freigegeben. Danach unterstützte und entwickelte Cloudflare Inc. die Plattform bis 2016. Seitdem entwickelt die OpenResty Software Foundation die Plattform weiter. Die Datastore-Komponente verwendet Apache Cassandra oder PostgreSQL, um die Konfigurationsdaten, Consumer und Plugins aller APIs zu persistieren. Die API-Konfiguration wird ebenfalls in nginx im Cache gespeichert, sodass die Last auf der Datenbank gering sein sollte. Plugins sind Lua-Module, die während eines Request-Response-Lebenszyklus ausgeführt werden. Sie erweitern das API-Gateway um Funktionalitäten für unterschiedliche Anwendungsfälle. Möchte man zum Beispiel eine API absichern, so verwendet man ein Sicherheits-Plugin, das nur diese Funktion während der Anfrage bereitstellt. Das Kong-Plugin-System ist offen, und man kann eigene Plugins schreiben und verwenden. Schließlich gibt es eine RESTful Admin API, um die APIs zu verwalten. Es fühlt sich am Anfang etwas seltsam an, keine Benutzeroberfläche zu haben. Aus Sicht des Entwicklers ist das akzeptabel, weil es ein notwendiges Werkzeug bietet, um die Arbeitsabläufe zu automatisieren, zum Beispiel mit Postman, httpie oder curl. Ich arbeite seit einigen Monaten mit Kong und habe nie das Bedürfnis nach einer Benutzeroberfläche verspürt, da ich auf alle Informationen schnell und zuverlässig zugreifen konnte. Wenn man jedoch ein Dashboard für APIs haben möchte, kann man Konga oder kong-dashboard verwenden, beides freie Open-Source-Community-Projekte.

Schauen wir uns nun an, wie man APIs mit Kong verwaltet und welche Plugins grundlegende Sicherheitsfunktionen bieten.

Kong API Gateway in action

Dieser Teil wird technischer als der vorherige sein. Zuerst zeige ich, wie man eine minimale Infrastruktur für Kong API Gateway erstellt. Dann werde ich eine API und ein Sicherheits-Plugin hinzufügen, um den Zugriff auf einen bestimmten Benutzer einzuschränken.

Um die Infrastruktur zu starten, verwende ich docker-compose mit dieser Service-Definition:

version: '2.1'

services:
  kong-database:
    container_name: kong-database
    image: postgres:9.4
    environment:
      - POSTGRES_USER=kong
      - POSTGRES_DB=kong
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
  
  kong-migration:
    image: kong
    depends_on:
      kong-database:
        condition: service_healthy
    environment:
      - KONG_DATABASE_postgres
      - KONG_PG_HOST=kong-database
    command: kong migrations up

  kong:
    container_name: kong
    image: kong:0.11.0
    depends_on:
      kong-database:
        condition: service_healthy
      kong-migration:
        condition: service_started
    environment:
      - KONG_DATABASE=postgres
      - KONG_PG_HOST=kong-database
      - KONG_PG_DATABASE=kong
    expose:
      - 8000
      - 8001
      - 8443
      - 8444
    ports:
      - "8000-8001:8000-8001"
    healthcheck:
      test: ["CMD-SHELL", "curl -I -s -L http://127.0.0.1:8000 || exit 1"]
      interval: 5s
      retries: 10

Man kann Kong auch auf vielen Plattformen wie AWS, Google Cloud, Kubernetes, DC/OS und vielen anderen installieren. In meiner docker-compose-Definition gibt es drei Services: kong-database, kong und kong-migration. Ich verwende das PostgreSQL Docker-Image für die Datastore-Komponente, die in der Architekturübersicht erwähnt wurde. Der kong-service stellt vier verschiedene Ports für zwei Funktionalitäten bereit:

  • 8000, 8443: HTTP- und HTTPS-Zugriff auf die APIs (Consumer-Endpunkt)
  • 8001, 8444: HTTP- und HTTPS-Zugriff auf die Admin-API (Admin-Endpunkt)

Der kong-migration-Service wird zum initialen Erstellen der Objekte in der kong-database verwendet. Diese Bootstrap-Funktionalität wird vom kong-service nicht bereitgestellt, daher muss man kong-migration nur einmal innerhalb des Containers ausführen. Mit docker-compose up werden die Dienste gestartet. Der Container-Status sollte mit dem Befehl docker ps etwas so aussehen:

CONTAINER ID        IMAGE               COMMAND                  CREATED                  STATUS                            PORTS                                                                NAMES
87eea678728f        kong:0.11.0         "/docker-entrypoin..."   Less than a second ago   Up 2 seconds (health: starting)   0.0.0.0:8000-8001->8000-8001/tcp, 0.0.0.0:8443-8444->8443-8444/tcp   kong
4e2bf871f0c7        postgres:9.4        "docker-entrypoint..."   3 hours ago              Up 4 minutes (healthy)            5432/tcp                                                             kong-database

Mit einer GET-Anfrage an die Admin-API kann man den Status der API überprüfen. Ich benutze dafür das Tool HTTPie, aber man kann auch curl oder Postman als Alternative verwenden.

$ http localhost:8001/apis/
 
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Date: Fri, 13 Oct 2017 14:59:25 GMT
Server: kong/0.11.0
Transfer-Encoding: chunked
 
{
    "data": [],
    "total": 0
}

Die Kong-Admin-API funktioniert, aber es sind noch keine APIs konfiguriert. Ich füge nun ein Beispiel hinzu:

$ http post localhost:8001/apis/ name=example_api upstream_url=https://example.com uris=/my_api
 
HTTP/1.1 201 Created
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Date: Fri, 13 Oct 2017 15:03:55 GMT
Server: kong/0.11.0
Transfer-Encoding: chunked
 
{
    "created_at": 1507907036000,
    "http_if_terminated": false,
    "https_only": false,
    "id": "59d9749b-694a-4645-adad-d2c974b3df76",
    "name": "example_api",
    "preserve_host": false,
    "retries": 5,
    "strip_uri": true,
    "upstream_connect_timeout": 60000,
    "upstream_read_timeout": 60000,
    "upstream_send_timeout": 60000,
    "upstream_url": "https://example.com",
    "uris": [
        "/my_api"
    ]
}

Dazu sende ich einen POST-Request an localhost:8001/apis/ mit drei Parametern im http-Body:

  • name: API name
  • upstream_url: die Ziel-URL, die auf einen API-Server verweist
  • uris: URI Prefixe, die mit einem API-Server assoziiert werden

Es gibt natürlich mehr Parameter, wie z.B. für SSL, Timeouts, HTTP-Methoden und andere. Man kann alle Konfigurationen in der Dokumentation nachschlagen. Ich rufe nun die API auf:

$ http localhost:8000/my_api
 
HTTP/1.1 200 OK
Cache-Control: max-age=604800
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 606
Content-Type: text/html; charset=UTF-8
Date: Tue, 17 Oct 2017 09:02:26 GMT
Etag: "359670651+gzip"
Expires: Tue, 24 Oct 2017 09:02:26 GMT
Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
Server: ECS (dca/249F)
Vary: Accept-Encoding
Via: kong/0.11.0
X-Cache: HIT
X-Kong-Proxy-Latency: 592
X-Kong-Upstream-Latency: 395
 
<!doctype html>
<html>
<head>
    <title>Example Domain</title>
...

In vielen Fällen möchte man seine API schützen und nur dedizierten Benutzern Zugriff geben. In Kong verwendet man dafür Plugins, die während eines Requests ausgeführt werden.

Consummers und Plugins

Consumer sind Objekte, die (technische) API-Benutzer sind. Die Datenstruktur ist ziemlich einfach gehalten und hat nur drei Felder: id, username und custom_id. Um einen Consumer zu erstellen, schicke man einen POST-Request an localhost:8001/consumer/

$ http post localhost:8001/consumers/ username=John
 
HTTP/1.1 201 Created
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Date: Tue, 17 Oct 2017 10:06:19 GMT
Server: kong/0.11.0
Transfer-Encoding: chunked
 
{
    "created_at": 1508234780000,
    "id": "bdbba9d1-5948-4e1a-94bd-55979b7117a3",
    "username": "John"
}

Man muss entweder das Feld username oder custom_id oder beides im Request-Body angeben. Zusätzlich kann man eine custom_id für eine Verknüpfung zwischen einem Consumer und einem Benutzer eines internen Systems festlegen, z. B. eine ID in einem CRM-System. Damit kann man Konsistenz zwischen den Consumern in Kong und einem externen System mit Benutzerdaten pflegen. Ich werde nun ein Sicherheits-Plugin zu meiner API hinzufügen und den Consumer mit diesem Plugin verbinden. Dadurch wird sichergestellt, dass nur dieser Benutzer mit einem bestimmten Schlüssel auf die API zugreifen kann. Ein Kong-Plugin ist eine Sammlung von Lua-Modulen, die während eines Request-Response-Lebenszyklus einer API ausgeführt werden. Plugins können zu allen APIs hinzugefügt oder nur nur für eine bestimmte API eingerichtet werden. Zusätzlich können Plugins für einen bestimmten Consumer konfiguriert werden. In meinem Fall füge ich das key authentication plugin hinzu:

$ http post localhost:8001/apis/example_api/plugins name=key-auth
 
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Date: Tue, 17 Oct 2017 11:59:16 GMT
Server: kong/0.11.0
Transfer-Encoding: chunked
 
{
    "api_id": "36d04e5d-436d-4132-abdc-e4d42dc67068",
    "config": {
        "anonymous": "",
        "hide_credentials": false,
        "key_in_body": false,
        "key_names": [
            "apikey"
        ]
    },
    "created_at": 1508241556000,
    "enabled": true,
    "id": "8eecbe27-af95-49d2-9a0a-5c71b9d5d9bd",
    "name": "key-auth"
}

Der API-Name examlpe_api in der Request-URL beschränkt die Plugin-Ausführung nur auf diese API. Versucht man die API zu verwenden, erhält man folgende Antwort:

$ http localhost:8000/my_api
 
hTTP/1.1 401 Unauthorized
connection: keep-alive
content-Type: application/json; charset=utf-8
date: Tue, 17 Oct 2017 12:03:24 GMT
server: kong/0.11.0
transfer-Encoding: chunked
WWW-Authenticate: Key realm="kong"
 
{
    "message": "No API key found in request"
}

Jetzt muss ich einen Schlüssel für meinen Consumer erstellen:

$ http POST localhost:8001/consumers/John/key-auth key=secret_key
 
HTTP/1.1 201 Created
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Date: Tue, 17 Oct 2017 12:35:11 GMT
Server: kong/0.11.0
Transfer-Encoding: chunked
 
{
    "consumer_id": "bdbba9d1-5948-4e1a-94bd-55979b7117a3",
    "created_at": 1508243712000,
    "id": "02d2afd6-1fb6-4713-860f-704c52355780",
    "key": "secret_key"
}

Lässt man das Feld key weg, generiert Kong einen zufälligen Schlüssel. Mit dem konfigurierten Schlüssel rufe ich die API auf:

$ http localhost:8000/my_api apikey=='secret_key'
 
HTTP/1.1 200 OK
Cache-Control: max-age=604800
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 606
Content-Type: text/html; charset=UTF-8
Date: Tue, 17 Oct 2017 12:40:46 GMT
Etag: "359670651+gzip"
Expires: Tue, 24 Oct 2017 12:40:46 GMT
Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
Server: ECS (dca/249B)
Vary: Accept-Encoding
Via: kong/0.11.0
X-Cache: HIT
X-Kong-Proxy-Latency: 25
X-Kong-Upstream-Latency: 374
 
<!doctype html>
<html>
<head>
    <title>Example Domain</title>
...

Das apikey wird als Query-Parameter oder als Header im API-Request mitgeschickt. Das Plugin hat auch Konfigurationen, um den Schlüssel zu verbergen, nachdem die Anfrage verarbeitet wurde oder um ihn in einer Liste von Schlüsseln nachzuschlagen. Es ist auch möglich, Plugins auf Consumer-Ebene zu konfigurieren, sodass jeder Konsument seine eigenen Einstellungen hat. Beispielsweise kann man pro API-Nutzer unterschiedliche Anfrage-Limits festlegen, sodass einige von ihnen häufiger auf Ihre API zugreifen können als die anderen.

Fazit

In diesem Blogpost habe ich das Thema API-Management vorgestellt und warum es für Ihr Unternehmen oder Projekt von Bedeutung sein könnte. Kong API Gateway ist ein großartiges Open-Source-Projekt, mit dem man APIs frei verwalten kann. Mit nur wenigen HTTP-Anfragen habe ich meine erste API erstellt und abgesichert. Die RESTful Admin-API von Kong ist sauber und einfach, was eine schnelle Integration in die meisten Continuous-Delivery-Pipelines ermöglicht. Im nächsten Blogbeitrag werde ich zeigen, wie man eigene Plugins erstellt und einen OpenID-Provider für die Verwaltung der API-Zugriffe integriert.

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.