Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New serverless pattern - Access Bedrock via API Gateway with Cognito User Management #2064

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions apigw-bedrock-cognito-cdk/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
*.swp
package-lock.json
__pycache__
.pytest_cache
.venv
*.egg-info

# CDK asset staging directory
.cdk.staging
cdk.out
224 changes: 224 additions & 0 deletions apigw-bedrock-cognito-cdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
# Access Bedrock via API Gateway with Cognito User Management

This pattern creates an AWS CDK Python application to access Bedrock via API Gateway with Cognito user management, domain restriction, API request throttling, and quota limits.

Learn more about this pattern at Serverless Land Patterns: << Add the live URL here >>

Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example.

## Requirements

* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources.
* [Install and Configure AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html)
* [Install Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
* [Install Node and NPM](https://nodejs.org/en/download/)
* [Install AWS Cloud Development Kit (AWS CDK)](https://docs.aws.amazon.com/cdk/latest/guide/cli.html)
* [Install Python 3](https://www.python.org/downloads/)
* [Install Docker](https://www.docker.com/products/docker-desktop/)
* [Grant Bedrock Model Access](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html)

## Deployment Instructions

1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository:
```
git clone https://github.com/aws-samples/serverless-patterns
```
2. Change directory to the pattern directory:
```
cd apigw-bedrock-cognito-cdk
```
3. Create a virtual environment for Python:
```
python3 -m venv .venv
```
4. Activate the virtual environment:
```
source .venv/bin/activate
```
For a Windows platform, activate the virtualenv like this:
```
.venv\Scripts\activate.bat
```
5. Install the required Python dependencies:
```
pip install -r requirements.txt
```
6. Bootstrap the AWS environment, if you haven't already done so:
```
cdk bootstrap
```
7. Review the CloudFormation template AWS CDK generates for the stack:
```
cdk synth
```
8. Deploy the AWS resources:
```
cdk deploy
```
Optionally you can add the optional variables using the `--context`, see [API Gateway Configuration](#API-Gateway-Configuration) and [Cognito Integration and Configuration](#Cognito-Integration-and-Configuration).
```
cdk deploy --context API_THROTTLE_RATE_LIMIT=1 --context API_THROTTLE_BURST_LIMIT=2 --context API_QUOTA_LIMIT=25 --context API_QUOTA_PERIOD=DAY --context [email protected]
```
9. Note the outputs from the CDK deployment process. These contain the resource names and/or ARNs which are used for testing.

## How it works

### Overview

This pattern deploys an Amazon API Gateway REST API with the following routes: `POST /register`, `POST /login`, `GET` and `POST /bedrock`. It includes a Amazon Cognito User Pool and Lambdas to handle requests from the API Gateway. The API Gateway allows CORS for all origins and methods, incorporates an Usage Plan, and has throttle and quota limits for the `/bedrock` endpoint. The `/bedrock` endpoint allows access to Amazon Bedrock Foundation models.

### Components and Configuration

#### API Gateway Routes
- `/register` endpoint: Accepts `email`, `password`, and `fullname` in the body, interacts with a proxy lambda integration to register users to the Cognito User Pool. Returns an API Key which will be associated with the API Gateway's usage plan and stored within the Cognito user's custom `api_key` field . If an organization domain is specified in the `ORGANIZATION_DOMAIN` context variable, a pre signup lambda is provisioned to reject users not belonging to the specified domain.

- `/login` endpoint: Accepts `email` and `password` in the body, interacts with a proxy lambda integration to authenticate the user. Returns an bearer token, containing `IdToken`, `AccessToken`, `RefreshToken` and other metadata. If the user loses their API key, they can decrypt the `IdToken` using [jwt.io](https://jwt.io/) or other libraries to retrieve the API key from the `custom:api_key` field.

- `/bedrock` endpoint: Protected with a Cognito authorizer to ensure only requests with valid `Authorization` and `x-api-key` tokens in headers can access the endpoint, interacts with a proxy lambda integration. A `GET` request lists all foundation models, and a `POST` request takes `modelId` and `inferenceParameters` in the body, to invoke and return response from the foundation model.

#### API Gateway Configuration
- CORS: Enabled for all origins and methods.
- Usage Plan: Configured to manage API access.
- Throttle Limits: Rate limit of 1 request per second with a burst limit of 2 requests.
- Quota Limits: Set to 25 requests per day for the `/bedrock` endpoint.
- These limits can be modified during deployment using context variables (`API_THROTTLE_RATE_LIMIT`, `API_THROTTLE_BURST_LIMIT`, `API_QUOTA_LIMIT`, `API_QUOTA_PERIOD`)
- Logging: Enabled for all Error and Info request logs.

#### Cognito Integration and Configuration
- User Pool: Manages user registration and login.
- Organization Domain Restriction: The organization domain restriction can be adjusted during deployment using the context variable `ORGANIZATION_DOMAIN`. A Pre SignUp Lambda trigger will be added to enforce specific domain restrictions.

#### Lambda Integration
- `bedrock.py`:
- Uses the `boto3` library to make API calls to Amazon Bedrock APIs.
- Utilizes the `jsonpath_ng` library to dynamically map and retrieve responses from foundation models provided by Anthropic, AI21 Labs, Amazon, and Meta.
- `auth.py`:
- Uses the `boto3` library to make API calls to Amazon Cognito and Amazon API Gateway.
- Manages user creation, login, and the creation and association of API keys.
- `pre_signup.py` (if valid):
- Validates user email domain during registration.
- All Lambda Configuration:
- Timeout: Set to 29 second due to maximum integration timeout limit - [Amazon API Gateway Limits](https://docs.aws.amazon.com/apigateway/latest/developerguide/limits.html).
- Logging: All events are logged to Amazon CloudWatch, with a custom redaction function to remove passwords from the `auth.py` Lambda prior to logging.

### Request and Response Examples

- **Register User**
- **Request Body:**
```json
{
"email": "[email protected]",
"password": "securePassword123",
"fullname": "John Doe"
}
```
- **Response Body:**
```json
{
"status": 200,
"message": "User [email protected] created successfully.",
"data": {"API Key": "generatedApiKey"},
"success": true,
}
```

- **Login User**
- **Request Body:**
```json
{
"email": "[email protected]",
"password": "securePassword123"
}
```
- **Response Body:**
```json
{
"status": 200,
"IdToken": "generatedIdToken",
"AccessToken": "generatedAccessToken",
"RefreshToken": "generatedRefreshToken",
"ExpiresIn": 3600,
"TokenType": "Bearer",
"sucess": true
}
```

- **Make Bedrock Request**
- **Request Headers:**
- Authorization: Bearer [IdToken]
- x-api-key: [APIKey]
- **GET /bedrock Response Body:**
```json
{
"status": 200,
"foundationModels": [...],
"message": "Successfully retrieved foundation models list."
}
```
- **POST /bedrock Request Body:**
```json
{
"modelId": "exampleModelId",
"inferenceParameters": {...}
}
```
- **POST /bedrock Response Body:**
```json
{
"status": 200,
"message": "Successfully retrieved response from foundation model.",
"data": "..."
}
```

## Testing

Prior to running the tests, ensure that your account has the necessary access to the following Bedrock models: `ai21.j2-mid-v1`, `anthropic.claude-instant-v1`, `amazon.titan-text-express-v1`, and `meta.llama2-13b-chat-v1`. Follow the guide provided in the [Requirements](#Requirements) - [Bedrock model access granted](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html) to grant access to these models. Without access, the tests will fail due to insufficient permissions to interact with the foundation models.

1. Activate the virtual environment, if you haven't already done so from the deployment instructions:
```
source .venv/bin/activate
```
For a Windows platform, activate the virtualenv like this:
```
.venv\Scripts\activate.bat
```
2. Install the Python required dependencies:
```
pip install -r requirements-dev.txt
```
3. From the CDK output during the deployment process, obtain the values for Cognito User Pool ID and Rest API Endpoint:
```
ApigwBedrockCognitoCdkStack.CognitoUserPoolID = us-east-1_XXXXXXXXX
ApigwBedrockCognitoCdkStack.RestAPIEndpoint = https://XXXXXXXXX.execute-api.us-east-1.amazonaws.com/prod/
```
4. Update the `API_ENDPOINT` and `USER_POOL_ID` variables in `tests/e2e/test_apigw_bedrock_cognito_cdk_stack.py` with the obtained values:
```
API_ENDPOINT = "https://XXXXXXXXX.execute-api.us-east-1.amazonaws.com/prod/"
USER_POOL_ID = "us-east-1_XXXXXXXXX"
```
If organization domain restriction is enabled, modify the `TEST_EMAIL` to be an email with your domain, and `NON_ORG_TEST_EMAIL` to an email without your domain:
```
TEST_EMAIL = "[email protected]"
NON_ORG_TEST_EMAIL = "[email protected]"
```
5. Execute Pytest:
```
pytest -v
```

## Cleanup

1. Delete the stack:
```
cdk destroy
```
2. Delete all API Keys:
Before executing the following command, be aware that it will delete all API keys in the account. Ensure you have the necessary backups or are certain of the consequences.
```
sh utils/delete_all_api_keys.sh
```
----
Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.

SPDX-License-Identifier: MIT-0
109 changes: 109 additions & 0 deletions apigw-bedrock-cognito-cdk/apigw-bedrock-cognito-cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
{
"title": "API Gateway with Cognito to Lambda to Amazon Bedrock",
"description": "Create an AWS CDK Python application for Bedrock API with Cognito user management, domain restriction, API request throttling, and quota limits.",
"language": "Python",
"level": "200",
"framework": "CDK",
"introBox": {
"headline": "How it works",
"text": [
"This sample project demonstrates how to create an API Gateway with AWS CDK, backed by a Cognito user pool for user management.",
"Users can register and log in via an endpoint. Registration can be restricted to a specific domain, such as '@example.com'. The application supports request throttling and quota limits to the API.",
"Configuration for domain restriction, request throttling, and quota management can be done using CDK context variables."
]
},
"gitHub": {
"template": {
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/apigw-bedrock-cognito-cdk",
"templateURL": "serverless-patterns/apigw-bedrock-cognito-cdk",
"projectFolder": "apigw-bedrock-cognito-cdk",
"templateFile": "app.py"
}
},
"resources": {
"bullets": [
{
"text": "Amazon API Gateway - REST API",
"link": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html"
},
{
"text": "Amazon Bedrock",
"link": "https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html"
},
{
"text": "Amazon Bedrock - Inference parameters for foundation models",
"link": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters.html"
},
{
"text": "AWS CDK v2 - Python",
"link": "https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-python.html"
},
{
"text": "Amazon Cognito - User Pools",
"link": "https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools.html"
}
]
},
"deploy": {
"text": [
"Deploy the stack: <code>cdk deploy</code>",
"Deploy the stack with context variables: <code>cdk deploy --context [email protected] --context API_THROTTLE_RATE_LIMIT=1 --context API_THROTTLE_BURST_LIMIT=2 --context API_QUOTA_LIMIT=25 --contect API_QUOTA_LIMIT=DAY</code>"
]
},
"testing": {
"text": [
"Run end-to-end tests: <code>pytest</code>"
]
},
"cleanup": {
"text": [
"Delete the stack: <code>cdk destroy</code>."
]
},
"authors": [
{
"name": "Inthuson Anandakumar",
"image": "https://avatars.githubusercontent.com/u/8601106?v=4",
"bio": "Inthuson Anandakumar Technical Account Manager at AWS based out of London. Inthu currently works with strategic financial services customers for AWS, helping them architect, build, and optimize cloud applications. With a background in software development and solution architecture, he thrives on crafting innovative solutions and enjoys sharing his discoveries with customers across a wide array of sectors.",
"linkedin": "inthuson"
}
],
"patternArch": {
"icon1": {
"x": 10,
"y": 50,
"service": "cognito",
"label": "Amazon Cognito"
},
"icon2": {
"x": 38,
"y": 50,
"service": "apigw",
"label": "Amazon API Gateway"
},
"icon3": {
"x": 66,
"y": 50,
"service": "lambda",
"label": "AWS Lambda"
},
"icon4": {
"x": 90,
"y": 50,
"service": "bedrock",
"label": "Amazon Bedrock"
},
"line1": {
"from": "icon1",
"to": "icon2"
},
"line2": {
"from": "icon2",
"to": "icon3"
},
"line3": {
"from": "icon3",
"to": "icon4"
}
}
}
Empty file.
Loading