Skip to content

Example api with FastAPI + Cognito + Docker + Pytorch

License

Notifications You must be signed in to change notification settings

ae9is/py-fastapi

Repository files navigation

py-fastapi

Boilerplate example for setting up a FastAPI endpoint with AWS Cognito authorisation.

Provides run scripts to bundle a Docker image and upload to ECR for later deployment.

Setup

Environment variables

Setup loading .env variables: https://direnv.net/

direnv allow

Python

Uses Python 3.11. To easily switch between versions of python, consider setting up pyenv.

PDM is used for proper dependency resolution and convenience scripts.

pip install pipx
pipx install pdm

Pre-commit is used for some commit hooks:

pip install pre-commit
pre-commit install

IAM Identity Center (SSO)

  1. Enable IAM Identity Center following: https://aws.amazon.com/iam/identity-center/
  2. Add user admin
  3. Add group Admins to Groups
  4. Add admin to Admins
  5. Add a permission set AdministratorAccess based on the AdministratorAccess AWS managed policy
  6. Assign the permission set to the Admins group under AWS accounts → Assign users or groups

AWS CLI

  1. Install AWS CLI

    curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
    unzip awscliv2.zip
    sudo ./aws/install
    # or update:
    $ sudo ./aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update

    (ref: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)

  2. Configure CLI session and login

    aws configure sso
    # enter info...
    aws sso login --sso-session admin
  3. Check the resulting config at ~/.aws/config and make sure it matches what you expect, for ex:

    [profile admin]
    region = us-east-1
    sso_session = admin
    sso_account_id = 123456789012
    sso_role_name = AdministratorAccess
    
    [sso-session admin]
    sso_region = us-east-1
    sso_start_url = https://my-sso-portal.awsapps.com/start
    sso_registration_scopes = sso:account:access
    

    (ref: https://docs.aws.amazon.com/cli/latest/userguide/sso-configure-profile-token.html)

Cognito

You'll need to setup an authentication provider for the FastAPI endpoints.

The FastAPI authentication library used is fastapi-cloudauth, which supports AWS Cognito / Auth0 / Firebase Auth. The app is setup to use Cognito.

  1. Create a new user pool in Cognito in the AWS console.
  2. Sign-in and sign-up options should be arbitrary, just don't enable public sign-up. You don't need any actual users or groups.
  3. Once the user pool is created, select it and click "App integration" options.
  4. Under "Domain" setup a new cognito domain
  5. Create a resource server, with Resource server identifier pyapi and custom scope user for example. These values should match .env environment variable COGNITO_AUTH_USER_SCOPE, i.e. as in pyapi/user (resource_server_id/custom_scope_name).
  6. Under "App client list" click "Create app client" → App type "Confidential client"
  7. Client secret → Generate a client secret
  8. Accept default and create
  9. Once created, select the app client again and configure Hosted UI
    • Callback URLs: http://localhost
    • OAuth grant types: enable Client credentials grant
    • Custom scopes: pyapi/user (for example)

Once this setup is complete, note your:

  • Custom Cognito user pool domain
  • Custom scope
  • App integration → app client → Client ID
  • App integration → app client → Client secret

These will be needed to generate access tokens to authenticate requests against the api later.

Install

pdm install-all

Build

pdm docker-build

Deploy

Set environment variables for Dockerfile images in .env.dockerfile. Make sure to set PYTHON_ENV=production, or unset it. The app needs some Cognito config to be set in .env.dockerfile so that it knows what user pool to authenticate against.

Make sure AWS_REGION and AWS_ACCOUNT_ID are set in .env environment variables. These are needed to login Docker to ECR.

Login Docker to AWS ECR:

pdm docker-login

Create a new private registry called fastapi (adjust the PDM run scripts in pyproject.toml to change this): https://console.aws.amazon.com/ecr/get-started

Push the built docker image to ECR:

pdm docker-push

No infrastructure is provisioned in code for this example.

An example deploying on Fargate:

  1. Create a new ECS cluster, type Fargate.
  2. Create an ecsTaskExecutionRole following: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_execution_IAM_role.html#create-task-execution-role
  3. Attach the following inline policy to ecsTaskExecutionRole (in addition to AmazonECSTaskExecutionRolePolicy):
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "logs:CreateLogGroup"
                ],
                "Resource": "*"
            }
        ]
    }
  4. Create a new task definition from JSON file task-definition.json, editing the file with the ecsTaskExecutionRole's ARN.
  5. In the ECS cluster, create a new service:
    • Specify FARGATE_SPOT capacity provider
    • Select Task definition → Family: pyapi
    • Service name: fastapi
  6. Edit security group config at: AWS ECS → Clusters → <cluster_name> → Services → <service_name> → Configuration and networking → Network configuration → Security groups
  7. Edit inbound rules → Add new custom TCP inbound rule for port 5000, source "My IP" (or anywhere)
  8. Grab the endpoint's Public ID from Tasks → <task_id> → Public IP

Note: memory requirements for each task varies depending on what kind of model and job you're running! Check the task definition JSON file to adjust: task-definition.json.

Run (local api)

Different pdm scripts exist for testing the endpoint locally:

  • asgi: run the FastAPI app via an ASGI server, without docker
  • docker-run fastapi: run the FastAPI app via the docker image

Authentication

In order to authenticate against the FastAPI endpoints, you need to provide credentials. This section assumes a Cognito User Pool and App Client have already been setup previously (see here), and is an example for using Postman from a trusted client to side step having to setup any actual users and login in Cognito.

  1. Create a new postman environment, and edit it, adding the following variables:
    client_id       <client_id_from_cognito_app_client>
    client_secret   <client_secret_from_cognito_app_client>
    token_url       https://<cognito_subdomain>.<aws_region>.amazoncognito.com/oauth2/token
    scope           pyapi/user (or whatever scope you wish, i.e. pyapi/write, pyapi/read, ..., matching the values configured in the Cognito App Client)
  1. Create a new request
  2. Click Authorization → OAuth 2.0 → Add auth data to Request Headers
  3. Fill in the Configuration Options:
    Token Name             pyapi (arbitrary)
    Grant Type             Client credentials
    Access Token URL       {{token_url}}
    Client ID              {{client_id}}
    Client Secret          {{client_secret}}
    Scope                  {{scope}}
    Client Authentication  Send client credentials in body (arbitrary)
  1. Click "Get New Access Token" and copy the access_token in the response body
  2. Alternatively, you can just directly send a POST request yourself to the endpoint at {{token_url}}, specifying a x-www-form-urlencoded body:
    grant_type    client_credentials
    client_id     {{client_id}}
    client_secret {{client_secret}}
    scope         {{scope}}
  1. Open a new request to the development endpoint at (for ex.) GET http://localhost:5000/v1/healthz
  2. Click Authorization → OAuth 2.0 → Add auth data to Request Headers
  3. Paste the access token into Current Token → Access Token, just above Header Prefix "Bearer"

Test

Make sure to set the .env environment variables for Cognito.

Start up endpoint:

pdm docker-build
pdm docker-run

Then:

pdm test

About

Example api with FastAPI + Cognito + Docker + Pytorch

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published