Skip to content
malak.cloud
  • Kontakt
  • O mnie
  • Search Icon

malak.cloud

Cloud Native na co dzień

API Gateway – Autoryzacja

API Gateway – Autoryzacja

6 października 2017

Jakiś czas temu pojawiły się nowe możliwości autoryzacji zapytań kierowanych do AWS API Gateway. Akurat miałem się tym zająć.

Jakiś czas temu bawiliśmy się API połączonym z Lambdą. Rzadko mamy jednak do czynienia z aplikacjami, z których mogą korzystać wszyscy i to jeszcze anonimowi użytkownicy. Potrzebujemy autoryzacji.

Out of the box AWS oferuje nam autoryzację za pomocą IAM.

AWS autoryzacja

 

Nie chcmy jednak przecież tworzyć użytkowników naszego API w IAM. Udostępniając światu jakieś API, skorzystamy z własnych metod autoryzacji. Na szczęście jest to możliwe.

AWS udostępnia nam dwa sposoby autoryzacji. Możemy wykorzystać Cognito lub funkcje Lambda. Cognito bobawimy się w przyszłości. Dziś za pomocą Lambdy drobimy prostą funkcję autoryzującą requesty. Nie będzie to przykład do zastosowania na produkcji, pokaże on jadnek zasady działania całości. Jeżeli ktoś chce coś na szybko dowedzieć się o Cognito, to proponuję przesłuchanie 209 epizodu podstactu AWS.

Jak to działa? W momencie nadejścia requesta do naszego API, wywoływana jest funkcja Lambda, do której przekazywane są dane z requesta. Tutaj jest opis danych, które przesyłane są do funkcji. W przypadku autoryzacji poprzez token, są to: typ autoryzacji, sam token oraz arn naszego endpointa. Funkcja Lambda waliduje dane, sprawdza czy możemy autoryzować użytkownika i odpowiada naszemu API. Odpowiada zwacając między innymi dokument policy, który zezwala lub nie na użycie naszego API.
{
"Effect": "Allow",
"Action": "execute-api:Invoke"
}

Dodawkowo koniecznie musimy zwrócić z Lambdy id naszego użytkownika "principalId": "userId". Jeżeli chcemy, możemy zwrócić w naszej odpowiedzi dodatkowe dane, umieszczając je w obiekcie context. Całość struktury odpowiedzi pochodząca z dokumentacji wygląda tak:

{
  "principalId": "yyyyyyyy", // The principal user identification associated with the token sent by the client.
  "policyDocument": {
    "Version": "2012-10-17",
    "Statement": [
      {
        "Action": "execute-api:Invoke",
        "Effect": "Allow|Deny",
        "Resource": "arn:aws:execute-api:<regionId>:<accountId>:<appId>/<stage>/<httpVerb>/[<resource>/<httpVerb>/[...]]"
      }
    ]
  },
  "context": {
    "stringKey": "value",
    "numberKey": "1",
    "booleanKey": "true"
  }
}

 

Zanim klikniemy więc w Create New Authorizer musimy przygotować Lambdę, która nam tą autoryzację przeprowadzi.

Autoryzujemy

Obsługę autoryzacji podzielimy na dwie funkcje. Pierwsza wygeneruje dla nas odpowiednie policy, a druga przeparsuje dane otrzymane z API Gateway i odeśle mu politykę.

Policy

def policy_generator(resource, token):
    effect = 'Deny'
    if token.upper() == 'ALLOW':
        effect = 'Allow'
    return {
        "principalId": "principalId1",
        "policyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": effect,
                "Action": "execute-api:Invoke",
                "Resource": resource
            }
        ]
    }
}

Metoda przyjmyje dwa parametry. Zasób dla którego tworzymy politykę (ARN) oraz token. Logika fukcji sprawdza czy dla danego tokena możemy pozwolić na użycie naszego API (linia 3 i 4), przygotowuje politykę i zwraca ją.

Oczywiście pokazaną autoryzację możemy zastąpić innymi, bardziej skomplikowanymi sposobami na sprawdzenie czy użytkownik jest tym za kogo się podaje i czy ma prawo korzystać z naszego API.

Metoda parsująca dane i zwracająca wynik jest banalna. Poniżej całość kodu, który należy „wkleić” jako handler naszej lambdy autoryzującej

def lambda_handler(event, context):
    token = event['authorizationToken']
    arn = event['methodArn']
    return policy_generator(arn, token)
    
def policy_generator(resource, token):
    effect = 'Deny'
    if token.upper() == 'ALLOW':
        effect = 'Allow'
    return {
        "principalId": "principalId1",
        "policyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": effect,
                "Action": "execute-api:Invoke",
                "Resource": resource
            }
        ]
    }
}

Authorizer

Mamy już zaimplementowaną logikę naszej autoryzacji, czas na utworzenie authorizera.

Klikamy w ten niebieski guziczek i mamy tochę rzeczy do wypełnienia.

Podajemy jakąś rozsądną nazwę, jako typ wybieramy Lambdę. Wybieramy region, w którym przed chwilą utworzyliśmy naszą funkcję, która nam zapewni autoryzację.

Jako źródło tokena wybierzemy nagłówek o szumnej nazwie token. Pozwolimy także na cachowanie naszej autoryzacji przez 30 sekund.

W sumie wszystko mamy przygotowane i nic nie stoi na przeszkodzie, aby wykonać pierwszy test.

Testujemy

Założyliśmy, że mamy dwa rodzaje tokenów. Jednym z nich jest słowo Allow. Jeżeli prześlemy w nagłówku Allow, Lambda nas autoryzuje pozytywnie. Cokolwiek innego spododuje odrzucenie  naszego wywołania. Klikamy więc na Test i

Voila ! Możemy korzystać z naszego API.

Próbujemy przesłać coś innego

 

 

i zgodnie z przewidywaniami, Access Denied.

Co nam to dało?

W ten sposób w bardzo prosty sposób zabezpieczyliśmy nasze API przed wykorzystaniem przez każdego. Teraz, aby móc korzystać z naszego endpointa, użytkownik w nagłówku HTTP musi przesłać odpowiednią wartość. My sprawdzamy czy wartość ta jest poprawna i zgodna z oczekiwaniem. Poniżej pokazuje dwie próby połączenia się z naszym endpointem. Za pierwszym razem przekazuję w nagłówkach odpowiednią wartość    

i dostajemy oczekiwaną odpowiedź z API. Za drugim token jest niepoprawny i 

dostajemy status 403 i informację o braku możliwości autoryzacji.

Proste i skuteczne rozwiązanie.


AWS, CloudNative, DEV, Security
AWS, serverless

Post navigation

PREVIOUS
Dane w plikach CSV, JSON i SQL? Tak. AWS Athena
NEXT
AWS SNS i NET.Core
Comments are closed.
Cześć. Nazywam się Przemek Malak. Dzięki za wizytę. Mam nadzieję, że to o czym piszę Cię zainteresowało. Jeżeli chcesz ze mną pogadać, najłatwiej będzie przez LinkedIn.

Losowe wpisy

  • AWS API Gateway

    29 czerwca 2017
  • Czym jest dla mnie Cloud Native

    20 listopada 2020
  • Zombie apokalipsa w Łodzi

    14 lutego 2018
  • Jak skasować pliki w S3 przy usuwaniu stacka Cloudformation

    18 stycznia 2022
  • Serverless API – Jak postawić API bez serwera

    13 sierpnia 2017
  • Apps
  • AWS
  • CloudNative
  • Cookbook
  • Data
  • DEV
  • GCP
  • IoT
  • Istio
  • k8s
  • Security
  • Social
  • GitHub
  • LinkedIn
© 2023   All Rights Reserved.