Unsere Erfahrung mit der Erstellung eines API Gateways

Einige Unternehmen, darunter unser Kunde, entwickeln ihr Produkt über ein Partnernetzwerk. Zum Beispiel sind große Online-Shops mit dem Lieferservice integriert – Sie bestellen ein Produkt und erhalten kurz darauf eine Sendungsverfolgungsnummer. Ein weiteres Beispiel ist die Buchung einer Versicherung oder eines Tickets für den Flughafentransfer zusammen mit Ihrem Flugticket.

Hierfür wird eine API verwendet, die den Partnern über das API-Gateway bereitgestellt werden muss. Diese Aufgabe haben wir erfolgreich gelöst. In diesem Artikel geben wir detaillierte Informationen dazu.

Gegeben: ein Ökosystem und ein API-Portal mit einer Benutzeroberfläche, in der Nutzer registriert sind und Informationen erhalten. Wir müssen ein benutzerfreundliches und zuverlässiges API-Gateway erstellen. Dabei mussten wir sicherstellen,

  • die Registrierung,
  • die Kontrolle der Verbindung zur API,
  • die Überwachung, wie die Nutzer das Endsystem verwenden,
  • die Erfassung von Geschäftskennzahlen.

Unsere Erfahrung mit der Erstellung eines API Gateways

In diesem Artikel berichten wir von unserer Erfahrung bei der Erstellung des API-Gateways, während wir die folgenden Herausforderungen bewältigt haben:

  • die Benutzerautorisierung,
  • die Benutzerautorisierung,
  • die Modifikation der ursprünglichen Anfrage,
  • das Proxying der Anfrage,
  • die Nachbearbeitung der Antwort.


Es gibt zwei Arten des API-Managements:

1. Standardlösung, die wie folgt funktioniert. Vor der Verbindung testet der Nutzer die Möglichkeiten, bezahlt und integriert die Lösung in seine Webseite. Dies wird häufig im kleinen und mittleren Unternehmen verwendet.

2. Großes B2B API-Management, bei dem das Unternehmen zunächst eine geschäftliche Entscheidung zur Anbindung trifft, Partner wird und vertragliche Verpflichtungen eingeht, bevor es sich mit der API verbindet. Nachdem alle Formalitäten geklärt sind, erhält das Unternehmen Zugang zum Test und durchläuft die Testphase, um schließlich in den produktiven Betrieb zu gehen. Dies ist jedoch ohne eine Managemententscheidung zur Anbindung nicht möglich.

Unsere Erfahrung mit der Erstellung eines API Gateways

Unsere Lösung

In diesem Abschnitt erläutern wir die Erstellung eines API-Gateways.

Die Endnutzer des generierten API-Gateways sind Partner unseres Kunden. Für jeden von ihnen haben wir bereits die erforderlichen Verträge gespeichert. Wir müssen lediglich die Funktionalität erweitern, indem wir den bereitgestellten Zugang zum Gateway markieren. Dementsprechend ist ein kontrollierter Anschluss- und Verwaltungsprozess erforderlich.

Selbstverständlich hätte man auch eine fertige Lösung für die Aufgabe des API-Managements und die Erstellung eines API-Gateways in Betracht ziehen können. Ein Beispiel hierfür könnte sein, Azure API Management. Es war für uns nicht geeignet, da wir bereits ein API-Portal und ein umfassendes Ökosystem darum herum hatten. Alle Nutzer waren bereits registriert und wussten, wo und wie sie die benötigten Informationen erhalten konnten. Im API-Portal existierten bereits die erforderlichen Schnittstellen, wir benötigten lediglich ein API-Gateway. Damit befassten wir uns dann auch.

Was wir als API-Gateway bezeichnen, ist eine Art Proxy. Hier hatten wir erneut die Wahl — entweder einen eigenen Proxy zu schreiben oder eine bereits vorhandene Lösung zu wählen. In diesem Fall entschieden wir uns für Letzteres und wählten die Kombination aus nginx und Lua. Warum? Wir benötigten zuverlässige, getestete Software, die Skalierung unterstützt. Nach der Implementierung wollten wir weder die Geschäftslogik noch die Funktionsweise des Proxys überprüfen müssen.

Jeder Webserver hat ein Anfrageverarbeitungs-Pipeline. Im Fall von nginx sieht sie folgendermaßen aus:

Unsere Erfahrung mit der Erstellung eines API Gateways

(Diagramm aus GitHub Lua Nginx)

Unser Ziel war es, uns in diese Pipeline an dem Punkt einzufügen, an dem wir die ursprüngliche Anfrage modifizieren konnten.

Wir möchten einen transparenten Proxy einrichten, damit die Anfrage funktional so bleibt, wie sie eingegangen ist. Wir kontrollieren lediglich den Zugang zur endgültigen API und unterstützen die Anfrage auf dem Weg dorthin. Sollte die Anfrage fehlerhaft sein, muss der Fehler von der endgültigen API angezeigt werden, nicht von uns. Der einzige Grund, aus dem wir eine Anfrage ablehnen können, ist, wenn der Kunde keinen Zugang hat.

Für nginx existiert bereits Erweiterung findet man Lua. Lua ist eine leichtgewichtige Skriptsprache, die einfach zu erlernen ist. Daher haben wir die benötigte Logik mit Lua umgesetzt.

Die Konfiguration von nginx (analog zu einer Route in einer Anwendung), in der die gesamte Arbeit verrichtet wird, ist recht verständlich. Besonders hervorzuheben ist hier die letzte Direktive – post_action.

location /middleware {
      more_clear_input_headers Accept-Encoding;
      lua_need_request_body on;
      rewrite_by_lua_file 'middleware/rewrite.lua';
      access_by_lua_file 'middleware/access.lua';
      proxy_pass https://someurl.com;
      body_filter_by_lua_file 'middleware/body_filter.lua';
      post_action /process_session;
}

Schauen wir uns an, was in dieser Konfiguration geschieht:
more_clear_input_headers – entfernt den Wert der nach der Direktive angegebenen Header.
lua_need_request_body — regelt, ob der ursprüngliche Anfragekörper gelesen werden soll, bevor die Direktiven rewrite/access/access_by_lua ausgeführt werden. Standardmäßig liest nginx den Körper der Kundenanfrage nicht. Um darauf zugreifen zu können, muss diese Direktive auf on gesetzt werden.
rewrite_by_lua_file — Pfad zur Skriptdatei, in der die Logik zur Modifikation der Anfrage beschrieben wird.
access_by_lua_file — Pfad zur Skriptdatei, in der die Logik beschrieben wird, die den Zugriff auf die Ressource überprüft.
proxy_pass — URL, an die die Anfrage weitergeleitet wird.
body_filter_by_lua_file — Pfad zur Skriptdatei, in der die Logik zur Filterung der Anfrage vor der Rückgabe an den Kunden beschrieben wird.
Und schließlich, post_action — offiziell nicht dokumentierte Direktive, mit der weitere Aktionen ausgeführt werden können, nachdem die Antwort an den Kunden gegeben wurde.

Im Folgenden erläutern wir Schritt für Schritt, wie wir unsere Aufgaben gelöst haben.

Autorisierung/Authentifizierung und Modifikation der Anfrage

Autorisierung

Die Autorisierung und Authentifizierung erfolgt über Zertifikatszugänge. Es gibt ein Wurzelzertifikat. Für jeden neuen Kunden wird ein persönliches Zertifikat generiert, mit dem er Zugriff auf die API erhält. Dieses Zertifikat wird im Abschnitt server der nginx-Einstellungen konfiguriert.

ssl on;
ssl_certificate /usr/local/openresty/nginx/ssl/cert.pem;
ssl_certificate_key /usr/local/openresty/nginx/ssl/cert.pem;
ssl_client_certificate /usr/local/openresty/nginx/ssl/ca.crt;
ssl_verify_client on;

Modifikation

Eine berechtigte Frage könnte sein: Was passiert mit dem zertifizierten Kunden, wenn wir ihn plötzlich vom System trennen möchten? Es wäre ja nicht sinnvoll, für alle anderen Kunden die Zertifikate neu auszustellen.

So sind wir sanft zur nächsten Aufgabe übergegangen – die Modifikation der ursprünglichen Anfrage. Die ursprüngliche Anfrage des Kunden ist grundsätzlich nicht gültig für das finale System. Eine der Aufgaben besteht darin, die fehlenden Teile in die Anfrage einzufügen, um sie gültig zu machen. Der Clou dabei ist, dass die fehlenden Daten für jeden Kunden unterschiedlich sind. Wir wissen, dass der Kunde mit einem Zertifikat zu uns kommt, von dem wir den Fingerabdruck nehmen und die erforderlichen Kundendaten aus der Datenbank abrufen können.

Wenn es irgendwann erforderlich ist, einen Kunden von unserem Dienst zu trennen, werden seine Daten aus der Datenbank gelöscht und er kann nichts mehr tun.

Umgang mit Kundendaten

Wir mussten eine hohe Verfügbarkeit der Lösung sicherstellen, insbesondere wie wir auf die Kundendaten zugreifen. Die Herausforderung besteht darin, dass die ursprüngliche Quelle dieser Daten ein Drittanbieter-Dienst ist, der keine durchgehende und ausreichend hohe Leistung garantiert.

Daher mussten wir eine hohe Verfügbarkeit der Kundendaten gewährleisten. Als Werkzeug haben wir uns für Hazelcast, das uns Folgendes bietet:

  • schnellen Zugriff auf die Daten,
  • und die Möglichkeit, ein Cluster aus mehreren Nodes mit replizierten Daten auf verschiedenen Nodes einzurichten.

Wir haben den einfachsten Ansatz zur Bereitstellung von Daten im Cache gewählt:

Unsere Erfahrung mit der Erstellung eines API Gateways

Die Arbeit mit dem Endsystem erfolgt im Rahmen von Sitzungen, und es gibt eine Begrenzung für die maximale Anzahl. Wenn der Kunde die Sitzung jedoch nicht schließt, müssen wir dies tun.

Die Informationen über offene Sitzungen kommen vom Endgerät und werden zunächst auf der Lua-Seite verarbeitet. Wir haben uns entschieden, Hazelcast für die Speicherung dieser Daten zu verwenden, und dafür ein Job in .NET geschrieben. In regelmäßigen Abständen überprüfen wir die Lebensfähigkeit der offenen Sitzungen und schließen abgelaufene.

Zugang zu Hazelcast sowohl aus Lua als auch aus .NET

Es gibt keine Lua-Clients für die Arbeit mit Hazelcast, aber Hazelcast bietet eine REST-API, die wir genutzt haben. Für .NET gibt es einen Client, über den wir Zugriff auf die Hazelcast-Daten auf der .NET-Seite planen. Aber das stellte sich als problematisch heraus.

Unsere Erfahrung mit der Erstellung eines API Gateways

Bei der Speicherung von Daten über REST und der Auslese über den .NET-Client kommen unterschiedliche Serialisierer/Deserialisierer zum Einsatz. Daher ist es nicht möglich, Daten über REST zu speichern und sie über den .NET-Client abzurufen und umgekehrt.

Wenn es Interessierte gibt, können wir in einem separaten Artikel detaillierter über dieses Problem berichten. Spoiler — in der Skizze.

Unsere Erfahrung mit der Erstellung eines API Gateways

Protokollierung und Überwachung

Unser Unternehmensstandard für die Protokollierung über .NET ist Serilog, alle Protokolle gelangen schließlich in Elasticsearch, und die Analyse erfolgt über Kibana. Ähnliches wollten wir auch in diesem Fall erreichen. Das einzige einen Client für die Arbeit mit Elastic auf Lua, das gefunden wurde, brach beim ersten require. Und wir nutzten Fluentd.

Fluentd ist eine Open-Source-Lösung, die eine einheitliche Protokollierungsschicht für Anwendungen bereitstellt. Sie ermöglicht das Sammeln von Logs aus verschiedenen Anwendungsschichten und deren Kategorisierung in einer zentralen Quelle.

Die API-Gateway funktioniert in K8S, weshalb wir beschlossen haben, einen Container mit Fluentd in dasselbe Pod hinzuzufügen, um Logs in den vorhandenen offenen TCP-Port von Fluentd zu schreiben.

Wir haben auch untersucht, wie sich Fluentd verhalten würde, wenn keine Verbindung zu Elasticsearch besteht. Über einen Zeitraum von zwei Tagen gingen kontinuierlich Anfragen an das Gateway, Fluentd erhielt Logs, aber die IP von Elastic war gesperrt. Nach der Wiederherstellung der Verbindung übertrug Fluentd alle Logs einwandfrei nach Elastic.

Fazit

Der gewählte Implementierungsansatz ermöglichte es uns, ein funktionierendes Produkt in einer Produktionsumgebung in nur 2,5 Monaten zu liefern.

Sollten Sie jemals mit ähnlichen Dingen zu tun haben, empfehlen wir, zuerst klar zu verstehen, welches Problem Sie lösen und welche Ressourcen Ihnen bereits zur Verfügung stehen. Achten Sie auf die Herausforderungen der Integration mit bestehenden API-Management-Systemen.

Verstehen Sie für sich selbst, was genau Sie entwickeln möchten – lediglich die Geschäftslogik zur Verarbeitung von Anfragen oder, wie in unserem Fall, das gesamte Proxy. Vergessen Sie nicht, dass alles, was Sie selbst erstellen, anschließend gründlich getestet werden muss.

Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster