Nasze doświadczenie w tworzeniu API Gateway

Niektóre firmy, w tym nasz klient, rozwijają produkt poprzez sieć partnerską. Na przykład, duże sklepy internetowe są zintegrowane z usługą dostawy — zamawiasz produkt, a wkrótce otrzymujesz numer śledzenia przesyłki. Innym przykładem jest to, że razem z biletem lotniczym kupujesz ubezpieczenie lub bilet na aerobus.

Do tego używany jest jeden API, który należy udostępnić partnerom poprzez API Gateway. Ten problem właśnie rozwiązaliśmy. W tym artykule przedstawimy szczegóły.

Dane: ekosystem i portal API z interfejsem, w którym użytkownicy są zarejestrowani, otrzymują informacje itp. Musimy stworzyć wygodny i niezawodny API Gateway. W trakcie prac musieliśmy zapewnić

  • rejestrację,
  • kontrolę połączeń z API,
  • monitorowanie sposobu, w jaki użytkownicy korzystają z systemu końcowego,
  • uwzględnienie wskaźników biznesowych.

Nasze doświadczenie w tworzeniu API Gateway

W artykule opowiemy o naszym doświadczeniu w tworzeniu API Gateway, podczas którego stawialiśmy czoła następującym zadaniom:

  • uwierzytelnianie użytkownika,
  • autoryzacja użytkownika,
  • modyfikacja oryginalnego żądania,
  • proxy żądania,
  • przetwarzanie odpowiedzi.


Istnieją dwa rodzaje zarządzania API:

1. Standardowe, które działa w następujący sposób. Przed połączeniem użytkownik testuje możliwości, następnie płaci i wbudowuje je na swojej stronie. Najczęściej korzystają z tego małe i średnie przedsiębiorstwa.

2. Duże zarządzanie B2B API, kiedy firma najpierw podejmuje decyzję biznesową o połączeniu, staje się partnerem firmy z umową, a następnie łączy się z API. Dopiero po załatwieniu wszystkich formalności firma otrzymuje dostęp do testów, przechodzi testy i przechodzi do produkcji. Jednak jest to niemożliwe bez decyzji zarządzającej o połączeniu.

Nasze doświadczenie w tworzeniu API Gateway

Nasze rozwiązanie

W tej części opowiemy o tworzeniu API Gateway.

Końcowi użytkownicy stworzonego API Gateway to partnerzy naszego klienta. Dla każdego z nich już przechowujemy niezbędne umowy. Musimy jedynie rozszerzyć funkcjonalność, zaznaczając przyznany dostęp do bramy. W związku z tym potrzebny jest kontrolowany proces połączenia i zarządzania.

Oczywiście, można było skorzystać z gotowego rozwiązania do zarządzania API i tworzenia API Gateway w szczególności. Na przykład takim rozwiązaniem mogło być Azure API Management. Nie pasowało nam to, ponieważ w naszym przypadku mieliśmy już portal API oraz ogromny ekosystem, który został wokół niego zbudowany. Wszyscy użytkownicy byli już zarejestrowani i wiedzieli, gdzie i jak mogą zdobyć potrzebne informacje. W portalu API istniały już potrzebne interfejsy, potrzebny był nam tylko API Gateway. Właśnie jego opracowaniem się zajęliśmy.

To, co nazywamy API Gateway, to rodzaj proxy. I tu ponownie mieliśmy wybór — można napisać własne proxy lub wybrać coś gotowego. W tym przypadku poszliśmy drugą drogą i wybraliśmy zestawienie nginx+Lua. Dlaczego? Potrzebowaliśmy niezawodnego, sprawdzonego oprogramowania wspierającego skalowanie. Nie chcieliśmy po realizacji testować oraz poprawiać zarówno poprawności logiki biznesowej, jak i działania proxy.

Każdy serwer WWW ma potok przetwarzania żądań. W przypadku nginx wygląda to następująco:

Nasze doświadczenie w tworzeniu API Gateway

(schemat z GitHub Lua Nginx)

Naszym celem było wkomponowanie się w ten potok w momencie, w którym możemy modyfikować oryginalne żądanie.

Chcemy stworzyć transparentne proxy, żeby funkcjonalnie żądanie pozostało takim, jakim przyszło. Tylko kontrolujemy dostęp do końcowego API i pomagamy żądaniu do niego dotrzeć. W przypadku, gdy żądanie było niepoprawne, błąd powinno pokazać końcowe API, ale nie my. Jedynym powodem, dla którego możemy odrzucić żądanie, jest brak dostępu u klienta.

Dla nginx już istnieje rozszerzeniu na Lua. Lua to język skryptowy, jest bardzo lekki i łatwy do opanowania. W ten sposób potrzebną logikę zrealizowaliśmy za pomocą Lua.

Konfiguracja nginx’a (analogicznie do trasy aplikacji), gdzie wykonywana jest cała praca, jest całkowicie zrozumiała. Ciekawa jest tutaj ostatnia dyrektywa — 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;
}

Przyjrzyjmy się, co dzieje się w tej konfiguracji:
more_clear_input_headers — oczyszcza wartość wskazanych po dyrektywie nagłówków.
lua_need_request_body — reguluje, czy należy odczytać oryginalne ciało żądania przed wykonaniem dyrektyw rewrite/access/access_by_lua, czy nie. Domyślnie nginx nie odczytuje ciała żądania klienta, a jeśli konieczne jest uzyskanie do niego dostępu, ta dyrektywa musi mieć wartość on.
rewrite_by_lua_file — ścieżka do skryptu, w którym opisana jest logika modyfikacji żądania
access_by_lua_file — ścieżka do skryptu, w którym opisana jest logika sprawdzająca dostęp do zasobu.
proxy_pass — url, na który będzie przekazywane żądanie.
body_filter_by_lua_file — ścieżka do skryptu, w którym opisana jest logika filtrująca żądanie przed zwróceniem go do klienta.
I, w końcu, post_action — oficjalnie niedokumentowana dyrektywa, która pozwala na wykonanie dodatkowych działań po tym, jak odpowiedź została zwrócona klientowi.

Dalej opowiemy krok po kroku, jak rozwiązaliśmy nasze zadania.

Autoryzacja/uwierzytelnienie i modyfikacja żądania

Autoryzacja

Autoryzację i uwierzytelnienie zbudowaliśmy z wykorzystaniem dostępów za pomocą certyfikatu. Istnieje certyfikat główny. Każdemu nowemu klientowi zamawiającego generowany jest jego osobisty certyfikat, z którym może uzyskać dostęp do API. Certyfikat ten jest konfigurowany w sekcji server ustawień nginx.

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;

Modyfikacja

Może powstać słuszne pytanie: co zrobić z certyfikowanym klientem, jeśli nagle zechcieliśmy go odciąć od systemu? Nie można przecież ponownie wydawać certyfikatów dla wszystkich innych klientów.

Tak dotarliśmy do kolejnego zadania — modyfikacji pierwotnego żądania. Pierwotne żądanie klienta, ogólnie rzecz biorąc, nie jest ważne dla docelowego systemu. Jednym z zadań jest dodanie brakujących części do żądania, aby uczynić je ważnym. Część brakujących danych różni się dla każdego klienta. Wiemy, że klient przybywa do nas z certyfikatem, z którego możemy uzyskać odcisk i wydobyć z bazy niezbędne dane klienta.

Jeśli w pewnym momencie zajdzie potrzeba odcięcia klienta od naszego serwisu, jego dane znikną z bazy i nie będzie mógł nic zrobić.

Praca z danymi klienta

Musieliśmy zapewnić wysoką dostępność rozwiązania, szczególnie w kwestii, jak zdobywamy dane klienta. Trudność polega na tym, że pierwotnym źródłem tych danych jest zewnętrzna usługa, która nie gwarantuje nieprzerwanej i wystarczająco dużej prędkości działania.

Dlatego musieliśmy zapewnić wysoką dostępność danych klientów. Jako narzędzie wybraliśmy Hazelcast, który dostarcza nam:

  • szybki dostęp do danych,
  • możliwość zorganizowania klastra z wieloma węzłami z replikowanymi danymi na różnych węzłach.

Zastosowaliśmy najprostsza strategię dostarczania danych do cache:

Nasze doświadczenie w tworzeniu API Gateway

Praca z systemem końcowym odbywa się w ramach sesji i istnieje limit na maksymalną ich ilość. Jeśli klient nie zamknął sesji, będziemy musieli to zrobić za niego.

Dane o otwartej sesji pochodzą z systemu końcowego i są pierwotnie przetwarzane po stronie Lua. Zdecydowaliśmy się użyć Hazelcast do przechowywania tych danych w zadaniu napisanym w .NET. Następnie co jakiś czas sprawdzamy żywotność otwartych sesji i zamykamy wygasłe.

Dostęp do Hazelcast zarówno z Lua, jak i z .NET

Nie ma klientów Lua do pracy z Hazelcast, ale Hazelcast ma REST API, z którego postanowiliśmy skorzystać. Dla .NET jest 客户端, przez co planowaliśmy uzyskać dostęp do danych Hazelcast po stronie .NET. Ale ku naszemu zdziwieniu, było to bardziej skomplikowane.

Nasze doświadczenie w tworzeniu API Gateway

Podczas zapisywania danych za pomocą REST i odczytywania ich przez klienta .NET używane są różne serializatory-deserializatory. Dlatego nie można zapisać danych za pomocą REST, a odczytać przez klienta .NET i odwrotnie.

Jeśli będą zainteresowani, chętnie opowiemy o tym problemie w osobnym artykule. Spoiler — w schemacie.

Nasze doświadczenie w tworzeniu API Gateway

Logowanie i monitorowanie

Naszym standardem korporacyjnym do logowania w .NET jest Serilog, wszystkie logi trafiają ostatecznie do Elasticsearch, ich analizę przeprowadzamy przez Kibana. Coś podobnego chcieliśmy osiągnąć w tym przypadku. Jedynym 客户端 klientem do pracy z Elastic w Lua, który został znaleziony, zepsuł się na pierwszym imporcie. Dlatego użyliśmy Fluentd.

Fluentd — open source'owe rozwiązanie zapewniające jednolitą warstwę logowania aplikacji. Umożliwia zbieranie logów z różnych warstw aplikacji i ich późniejsze przesyłanie do jednego źródła.

API Gateway działa w K8S, dlatego postanowiliśmy dodać kontener z fluentd w tym samym podzie, aby zapisywać logi w istniejącym otwartym porcie TCP fluentd.

Zbadaliśmy również, jak będzie działał fluentd, jeśli nie będzie miał połączenia z Elasticsearch. Przez dwa dni do bramy stale napływały żądania, logi były przesyłane do fluentd, ale IP Elastic zostało zablokowane. Po przywróceniu połączenia fluentd z powodzeniem przesłał wszystkie logi do Elastic.

Podsumowanie

Wybrana metoda realizacji pozwoliła nam dostarczyć rzeczywiście działający produkt w środowisku produkcyjnym w zaledwie 2,5 miesiąca.

Jeśli kiedykolwiek będziesz zajmować się podobnymi kwestiami, zdecydowanie zalecamy, aby najpierw dokładnie zrozumieć, jaki problem chcesz rozwiązać i jakie zasoby już posiadasz. Zwróć uwagę na trudności związane z integracją z istniejącymi systemami zarządzania API.

Zrozum, co dokładnie zamierzasz rozwijać – tylko logikę biznesową do przetwarzania zapytań czy, jak miało to miejsce w naszym przypadku, cały proxy. Pamiętaj, że wszystko, co zrobisz samodzielnie, powinno być później starannie przetestowane.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster