Amazon API Gateway authentication through Keycloak combined with OAuth2.0 protocol

1 Introduction

This article describes how to use Keycloak and combine it with the built-in authorization function of Amazon API Gateway to complete the authentication process of Amazon resource requests. API Gateway helps developers securely create, publish, maintain and manage API access. In China, since Cognito is not yet online, using Keycloak as the authentication service for API calls has important practical significance.

The Amazon Cloud Technology Developer Community provides developers with global development technology resources. There are technical documents, development cases, technical columns, training videos, activities and competitions, etc. Help Chinese developers connect with the world's most cutting-edge technologies, ideas, and projects, and recommend outstanding Chinese developers or technologies to the global cloud community. If you haven't followed/collected it yet, please don't rush through it when you see it. Click here to make it your technical treasure trove!

This article is divided into four major modules:

Introduction : Introduce Keycloak, OAuth2.0 and Amazon API Gateway Authorizer;

Configuration instructions : detailed descriptions of the environment settings, including the settings of DynamoDB and the construction and settings of the Keycloak environment;

Verify JWT Authorizer : Verify the authorization function of API Gateway through Postman;

Summary : A summary of the full text.

1.1 About Keycloak

Keycloak is an open source and widely used solution for user identity management and authorization. Keycloak supports multiple protocols and standards, including OpenID Connect, OAuth2.0 and SAML2.0. At the same time, Keycloak can be integrated with existing LDAP or Active Directory services for single sign-on. Based on OAuth2.0, Keycloak can also complete the API authentication through JWT Token. Based on this scenario, this article combines Keycloak to complete the request authentication through Amazon Gateway's Authorizer.

1.2 About OAuth2.0

The full name of OAuth2.0 is Open Authorization 2.0, which is a protocol for authentication. Through the OAuth protocol, a third-party application can be authorized to request the user's resources without requiring the resource owner to directly provide any authentication credential information to the third party. OAuth2.0 authentication process

image.png

1.3 About Amazon API Gateway Authorizer

In this article, we take HTTP API as an example, and use the built-in authorization function of HTTP API to authenticate API requests. If you use the REST API, you need to verify the JWT Token by combining Lambda. You can refer to this documentation for configuration.

2. Configuration instructions

image.png

In this design, users access database resources on Amazon by calling the API defined in API Gateway. We complete reading/writing of DynamoDB data by defining 2 routes and integrating Lambda functions.

  • GET /items: No authentication is required, DynamoDB data can be obtained directly through API Gateway.
  • POST /items: Authentication is required, and the request token is verified through API Gateway. After the verification is successful, data is written to DynamoDB.
2.2 Preset conditions
  • Create a DynamoDB Table, DemoTable.
  • Create an HTTP API on Amazon API Gateway and integrate with Lambda.

DynomoDB settings

image.png

  • Partition key : pk
  • Sort key :sk
  • Leave other default configurations

API Gateway settings

Create an API Gateway, create 2 routes for the API Gateway, and associate the Lambd function. The list is as follows:

image.png

Lambda function sample

  • GetItemsLambda
import boto3
import os
import json
import botocore
 
def lambda_handler(event, context):
    try:
        client = boto3.resource("dynamodb")
        table_name = os.environ.get('DDB_TABLE')
        table = client.Table(table_name)
        scanning_result = table.scan()
 
        return {
            'statusCode': 200,
            'body': json.dumps(scanning_result),
            'headers': {
                    'Content-Type': 'application/json'
                },
            'isBase64Encoded': 'false'
        }
    except botocore.exceptions.ClientError as e:
        print(e)

  • GetItemsLambdaRole Policy:
"Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "xray:PutTraceSegments",
                "xray:PutTelemetryRecords"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "dynamodb:DescribeTable",
                "dynamodb:Query",
                "dynamodb:Scan"
            ],
            "Resource": [
                "arn:aws:dynamodb:us-east-1:123456789012:table/DemoTable"
            ],
            "Effect": "Allow"
        }
    ]
}

  • CreateItemsLambda:
import json
import datetime
import boto3
import os
import botocore
import uuid
 
def lambda_handler(event, context):
    try:
        client = boto3.client('dynamodb')
        table_name = os.environ.get('DDB_TABLE')
        req_body = json.loads(event["body"])
        req_user = event["requestContext"]["authorizer"]["jwt"]["claims"]["email"]
        ct = datetime.datetime.now()
        client.put_item(
            TableName = table_name,
            Item = {
                'pk': {'S':req_user},
                'sk': {'S':'item#' + str(uuid.uuid4())},
                'title': {'S':req_body["title"]},
                'timeCreated': {'S': ct.isoformat()}
                 
            }
                )
                 
        return {
            'statusCode': 200,
            'body': json.dumps('New Item Created')
        }
    except botocore.exceptions.ClientError as e:
        print(e)

  • CreateItemsLambdaRole Policy:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "xray:PutTraceSegments",
                "xray:PutTelemetryRecords"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "dynamodb:BatchGetItem",
                "dynamodb:GetRecords",
                "dynamodb:GetShardIterator",
                "dynamodb:Query",
                "dynamodb:GetItem",
                "dynamodb:Scan",
                "dynamodb:ConditionCheckItem",
                "dynamodb:BatchWriteItem",
                "dynamodb:PutItem",
                "dynamodb:UpdateItem",
                "dynamodb:DeleteItem"
            ],
            "Resource": [
                " arn:aws:dynamodb:us-east-1:123456789012:table/DemoTable "
            ],
            "Effect": "Allow"
        }
    ]
}

2.3 Keycloak settings

2.3.1 Keycloak installation

For the installation of Keycloak, please refer to the blog: Using SAML and Keycloak to establish Amazon SSO and log in to the Console

2.3.2 Establishment of Keycloak realm

Realm can be understood as a domain, used to manage users, user credentials, roles and user groups. Usually we need to create a client in the realm, and different application clients should configure different clients in the realm.  When performing authentication, the application client requesting resources will request the Auth Code from the authentication server, as shown in step 2 of the OAuth2.0 authentication process above  . To complete the establishment of the Keycloak realm, we can:

  1. Log in to the keycloak admin console, click "Administration Console" and log in;

image.png

  1. Create a realm and enter the realm;

image.png

2.3.3 Establishment of Keycloak Client

  1. Click "Configure->Clients->Create" in the realm;

image.png

  1. Enter the relevant information according to the instructions below; pay attention to select Standard Flow Enabled, which will make the client's authentication complete according to the "Authorization Code Flow" of 0, which is shown in the OAuth2.0  authentication process .

Note that if there is no special need, try to avoid using "Implicit Flow" or turn off "Implicit Flow Enabled". This method does not have the intermediate step of authorization code, so it is called (authorization code) "implicit". This will pass the token directly to the front end, which is very unsafe. Therefore, it can only be used in some scenarios with low security requirements.

image.png

  1. In the "Credentials tab", select Client Id and Secret, and a random string will be generated as Secret.  In the process of exchanging Token in step 6 of the OAuth2.0 authentication process above, the Secret will be sent to the Keycloak Client in the POST Body of the application client as the value of client_secret to ensure that the Token exchanged with the Client is issued to the  Correct application client.

2.3.4 Creation of Keycloak User

  1. To create a user for testing, click Manage->Users->Add user” on the left;

image.png

  1. Enter User information;

image.png

  1. Set a password, enter the password, and enter Password Confirmation, click Reset Password to complete the setup.

image.png

2.4 API Gateway Authorizer settings
  1. Enter the API Gateway created above, because our purpose is to perform API authentication when creating an item, so we only need to attach the authorizer to the route of POST /items:

image.png

  1. Enter relevant information;

image.png

  • Identity source : Normally, when requesting a resource server, the JWT Token will be written into the Authorization field in the request header, so you can keep the default.
  • Publisher URL : for Keycloak is https://{Keycloak_URL}/auth/realms/{realm}/
  • Audience : Associated audience, enter account here

3. Verify JWT Authorizer

3.1 Request Auth Code
  1. According to  the OAuth2.0 authentication process , when the user requests resources, the application client will send a GET request to the authentication server to request the Auth Code;
GET https://{Keycloak_URL}/auth/realms/Keycloaksso/protocol/openid-connect/auth?response_type=code&client_id=Keycloak

  1. During this process, the authentication server will return to the Keycloak login interface, requiring the user to enter their username and password. Here, we enter the username and password of the User created in the Keycloak User creation chapter.

image.png

  1. After entering the correct username and password, Keycloak will return the Auth Code through Query String, as shown in the figure below;

image.png

3.2 Exchange JWT Token
  1. Next, we use Postman to imitate the application client and simulate the process of exchanging JWT Token through POST Auth Code;

image.png

  • client_id : Keycloak client ID,   created in the Keycloak Client establishment chapter;
  • grant_type : 0 authentication mode, we authenticate through the authorization code mode, which is also the most common mode;
  • client_secret : used for client application client verification;
  • code: Auth Code , returned by the authentication server, used to exchange Token.
  1. Implement Postman's request with curl:
curl --location --request POST 'https://{Keycloak_URL}/auth/realms/Keycloaksso/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Cookie: AUTH_SESSION_ID=a0b56dbf-19b0-4d16-b254-c25248834c01.Keycloak-5b7448f8cf-v5wg6; AUTH_SESSION_ID_LEGACY=a0b56dbf-19b0-4d16-b254-c25248834c01.Keycloak-5b7448f8cf-v5wg6; KC_RESTART=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIyYjQ0M2Q2ZS00MzNiLTQwYTQtYjdlMi03MDk2Mjg1YTJkYmMifQ.eyJjaWQiOiJrZXljbG9hayIsInB0eSI6Im9wZW5pZC1jb25uZWN0IiwicnVyaSI6IioiLCJhY3QiOiJBVVRIRU5USUNBVEUiLCJub3RlcyI6eyJpc3MiOiJodHRwczovL2F1dGguY2lhdGVzdC50b3AvYXV0aC9yZWFsbXMva2V5Y2xvYWtzc28iLCJyZXNwb25zZV90eXBlIjoiY29kZSJ9fQ.5T6tBz-j7vbfzvhHBpPnQ2ebRqYC69gNF-EMlWmsA8Q' \
--data-urlencode 'client_id=Keycloak' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'client_secret=bba58d29-xxxx-xxxx-xxxx-xxxxxxxxxxxx' \
--data-urlencode 'code=74926370-xxxx-xxxx-xxxx-xxxxxxxxxxxx.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Response:

    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldU….eyJleHAiOjE2NTYyNDExOTksImlhdCI6MT….m91pmRMmSnA0D37qF4_...",
    "expires_in": 300,
    "refresh_expires_in": 1800,
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldU….eyJleHAiOjE2NTYyNDI2OTksImlhdCI6MT….OaDarszhAnyd3NKZTiZ…",
    "token_type": "Bearer",
    "not-before-policy": 0,
    "session_state": "aa8b66e0-xxxx-xxxx-xxxx-6ff28b1213d5",
    "scope": "profile email"
}

3.3 Request to API Gateway to create resources
  1. Simulate the application client through Postman and simulate the process of creating an item;

image.png

  • Authorization: Paste the information returned in 2  access_token into the Authorization header, the format is:Bearer {access_token}
  1. Implement Postman's request with curl:
curl --location --request POST 'https://80iiueir8b.execute-api.us-east-1.amazonaws.com/items' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldU….eyJleHAiOjE2NTYyNDExOTksImlhdCI6MT….m91pmRMmSnA0D37qF4_...\
--header 'Content-Type: application/json' \
--data-raw '{"title":"nike high heel"}'

Response:

"New Item Created"

  1. Use the browser GET /item to check whether the item is written successfully:

image.png

4. Summary

Since Cognito is currently not available in China, Keycloak can be used as an alternative to complete user single sign-on and API authentication. This blog provides a demonstration of how to combine API Gateway's HTTP API and use Keycloak and JWT for API authentication. In this way, when the application client requests Amazon resources, it needs to pass the Keycloak server for verification and exchange for a valid JWT Token to obtain permission to access resources.

If you are interested in learning more about the technologies mentioned in this article, please refer to:

OAuth2.0 Grant Type

Json Web Token

Establish Amazon SSO login console using SAML and Keycloak

How to secure API Gateway HTTP endpoints with JWT authorizer

The author of this article

Li Xiaoyi  is a security consultant of the Amazon cloud technology professional service team, responsible for the consulting design and implementation of cloud security compliance, cloud security solutions, etc. need.

Article source: https://dev.amazoncloud.cn/column/article/630b4bf9269604139cb5e9ed?sc_medium=regulartraffic&sc_campaign=crossplatform&sc_channel=CSDN

Guess you like

Origin blog.csdn.net/u012365585/article/details/132679057