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

API Gateway IAM Authorization #612

Merged
merged 11 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from 10 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
216 changes: 89 additions & 127 deletions aws/cloudformation-templates/apigateway.yaml

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions aws/cloudformation-templates/base/_template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,10 @@ Outputs:
Description: Authentication Cognito Authorized Role name
Value: !GetAtt Authentication.Outputs.CognitoAuthorizedRole

CognitoUnAuthorizedRole:
Description: Authentication Cognito UnAuthorized Role name
Value: !GetAtt Authentication.Outputs.CognitoUnAuthorizedRole

StackBucketName:
Description: Stack Bucket
Value: !GetAtt Buckets.Outputs.StackBucketName
Expand Down
5 changes: 4 additions & 1 deletion aws/cloudformation-templates/base/authentication.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -265,4 +265,7 @@ Outputs:
Value: !Ref IdentityPool
CognitoAuthorizedRole:
Description: Cognito Authorized Role
Value: !Ref CognitoAuthorizedRole
Value: !Ref CognitoAuthorizedRole
CognitoUnAuthorizedRole:
Description: Cognito UnAuthorized Role
Value: !Ref CognitoUnAuthorizedRole
65 changes: 17 additions & 48 deletions aws/cloudformation-templates/location.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ Parameters:
LambdaVpcSubnets:
Type: String

CognitoAuthorizedRole:
Type: String

Conditions:
DefaultGeofence: !Equals
- !Ref DeployDefaultGeofence
Expand Down Expand Up @@ -326,60 +329,26 @@ Resources:
DeploymentId: !Ref LocationGeofenceBrowserNotificationApiDeployment
ApiId: !Ref LocationGeofenceBrowserNotificationApi

LambdaAuthorizerRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

LambdaAuthorizerFunction:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: !Ref ResourceBucket
S3Key: !Sub '${ResourceBucketRelativePath}aws-lambda/apigw-ws-authorizer.zip'
Handler: index.handler
Runtime: nodejs18.x
Role: !GetAtt LambdaAuthorizerRole.Arn
MemorySize: 512
Timeout: 60
Environment:
Variables:
ALLOWED_ORIGIN: !Ref WebURL

LambdaAuthorizer:
Type: 'AWS::ApiGatewayV2::Authorizer'
Properties:
Name: LambdaAuthorizer
ApiId: !Ref LocationGeofenceBrowserNotificationApi
AuthorizerType: REQUEST
AuthorizerUri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaAuthorizerFunction.Arn}/invocations"

LambdaAuthorizerFunctionPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:invokeFunction
FunctionName: !GetAtt LambdaAuthorizerFunction.Arn
Principal: apigateway.amazonaws.com
SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${LocationGeofenceBrowserNotificationApi}/authorizers/${LambdaAuthorizer}"
ApiGatewayLocationAccessPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: ApiGatewayLocationAccessPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: "execute-api:Invoke"
Resource:
- !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${LocationGeofenceBrowserNotificationApi}/${LocationGeofenceBrowserNotificationApiStage}/POST/@connections"
Roles:
- !Ref CognitoAuthorizedRole

LocationGeofenceBrowserNotificationApiConnectRoute:
Type: 'AWS::ApiGatewayV2::Route'
Properties:
ApiId: !Ref LocationGeofenceBrowserNotificationApi
RouteKey: $connect
AuthorizationType: CUSTOM
AuthorizerId: !Ref LambdaAuthorizer
AuthorizationType: AWS_IAM
OperationName: ConnectRoute
Target: !Join
- '/'
Expand Down
28 changes: 20 additions & 8 deletions aws/cloudformation-templates/room-generator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ Parameters:
Default: controlnet-depth-sdxl
ApiGatewayId:
Type: String
LambdaAuthorizer:
Type: String
WebURL:
Type: String
CognitoAuthorizedRole:
Expand Down Expand Up @@ -694,6 +692,23 @@ Resources:
Principal: apigateway.amazonaws.com
SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiGatewayId}/*/*/*"

ApiGatewayRoomAccessPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: ApiGatewayRoomAccessPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: "execute-api:Invoke"
Resource:
- !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiGatewayId}/*/POST/rooms"
- !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiGatewayId}/*/GET/rooms"
- !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiGatewayId}/*/GET/rooms/*"
Roles:
- !Ref CognitoAuthorizedRole


ApiIntegration:
Type: 'AWS::ApiGatewayV2::Integration'
Properties:
Expand All @@ -710,8 +725,7 @@ Resources:
Properties:
ApiId: !Ref ApiGatewayId
RouteKey: 'GET /rooms/{id}'
AuthorizationType: CUSTOM
AuthorizerId: !Ref LambdaAuthorizer
AuthorizationType: AWS_IAM
Target: !Join
- /
- - integrations
Expand All @@ -722,8 +736,7 @@ Resources:
Properties:
ApiId: !Ref ApiGatewayId
RouteKey: 'GET /rooms'
AuthorizationType: CUSTOM
AuthorizerId: !Ref LambdaAuthorizer
AuthorizationType: AWS_IAM
Target: !Join
- /
- - integrations
Expand All @@ -734,8 +747,7 @@ Resources:
Properties:
ApiId: !Ref ApiGatewayId
RouteKey: 'POST /rooms'
AuthorizationType: CUSTOM
AuthorizerId: !Ref LambdaAuthorizer
AuthorizationType: AWS_IAM
Target: !Join
- /
- - integrations
Expand Down
3 changes: 3 additions & 0 deletions aws/cloudformation-templates/services/service/service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,9 @@ Resources:
Resource:
- !Sub 'arn:${AWS::Partition}:evidently:${AWS::Region}:${AWS::AccountId}:project/${EvidentlyProjectName}*'
- !Sub 'arn:${AWS::Partition}:evidently:${AWS::Region}:${AWS::AccountId}:project/${EvidentlyProjectName}/feature/*'
- Effect: Allow
Action: cognito-idp:ListUsers
Resource: !Sub 'arn:${AWS::Partition}:cognito-idp:${AWS::Region}:${AWS::AccountId}:userpool/${UserPoolId}'

ManagedPolicyArns:
- arn:aws:iam::aws:policy/AWSCloudMapDiscoverInstanceAccess
Expand Down
6 changes: 3 additions & 3 deletions aws/cloudformation-templates/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -729,8 +729,8 @@ Resources:
VpcCidr: !GetAtt Base.Outputs.VpcCidr
ResourceBucket: !Ref ResourceBucket
ResourceBucketRelativePath: !Ref ResourceBucketRelativePath
CognitoUserPoolId: !GetAtt Base.Outputs.UserPoolId
CognitoAppClientId: !GetAtt Base.Outputs.UserPoolClientId
CognitoAuthorizedRole: !GetAtt Base.Outputs.CognitoAuthorizedRole
CognitoUnAuthorizedRole: !GetAtt Base.Outputs.CognitoUnAuthorizedRole

# Web UI Pipeline
WebUIPipeline:
Expand Down Expand Up @@ -854,6 +854,7 @@ Resources:
]
LambdaVpcSecurityGroup: !GetAtt Base.Outputs.PrivateVPCSecurityGroup
LambdaVpcSubnets: !GetAtt Base.Outputs.Subnets
CognitoAuthorizedRole: !GetAtt Base.Outputs.CognitoAuthorizedRole

AmazonPay:
Type: AWS::CloudFormation::Stack
Expand Down Expand Up @@ -976,7 +977,6 @@ Resources:
CleanupBucketLambdaArn: !GetAtt CleanupBucket.Outputs.LambdaFunctionArn
OpenSearchDomainEndpoint: !GetAtt Base.Outputs.OpenSearchDomainEndpoint
ApiGatewayId: !GetAtt ApiGateway.Outputs.ApiGatewayId
LambdaAuthorizer: !GetAtt ApiGateway.Outputs.ApiGatewayAuthorizer
WebUIBucketName: !GetAtt Base.Outputs.WebUIBucketName
WebURL: !If
- ConditionCustomDomain
Expand Down
18 changes: 2 additions & 16 deletions aws/cloudformation-templates/web-ui-pipeline.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -303,22 +303,8 @@ Resources:
Value: !Sub ${UserPoolClientId}
- Name: COGNITO_IDENTITY_POOL_ID
Value: !Sub ${IdentityPoolId}
- Name: PRODUCTS_SERVICE_URL
Value: !Ref APIGatewayUrl
- Name: USERS_SERVICE_URL
Value: !Ref APIGatewayUrl
- Name: CARTS_SERVICE_URL
Value: !Ref APIGatewayUrl
- Name: ORDERS_SERVICE_URL
Value: !Ref APIGatewayUrl
- Name: RECOMMENDATIONS_SERVICE_URL
Value: !Ref APIGatewayUrl
- Name: LOCATION_SERVICE_URL
Value: !Ref APIGatewayUrl
- Name: SEARCH_SERVICE_URL
Value: !Ref APIGatewayUrl
- Name: VIDEOS_SERVICE_URL
Value: !Ref APIGatewayUrl
- Name: API_GATEWAY_URL
Value: !Ref APIGatewayUrl
- Name: DEPLOYED_REGION
Value: !Ref AWS::Region
- Name: PINPOINT_APP_ID
Expand Down
80 changes: 8 additions & 72 deletions src/README.md
Original file line number Diff line number Diff line change
@@ -1,72 +1,8 @@
# Local Development Instructions

The Retail Demo Store's web services such as [users](./users), [carts](./carts), [orders](./orders), [products](./products), and others can be run locally on your development system using [Docker Compose](https://docs.docker.com/compose/). You can choose to run them all locally or just one or two locally and the rest running in your AWS account. For example, suppose you're working on an enhancement or fix in the [products](./products) service. You can run just that service locally to test your changes while all of the other services are running in your AWS account. If your changes require UI testing, you can run the [web-ui](./web-ui) in a local container as well configured to connect to your local product service instance while still having both of them connect to the other services running in your AWS account.

Before you can run the Retail Demo Store web services locally, you must first deploy the Retail Demo Store project to your AWS account and then clone this repository to your local machine. The instructions below provide additional details on configuration and how to setup the services to run locally. The [docker-compose.yml](./docker-compose.yml) file includes the configuration used by Docker Compose. Note that there are some dependencies between services which are noted.

## Configuring your Environment

Besides cloning this repository to your local system, you also need to have the AWS CLI [installed](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html) and [configured](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html) locally.

Docker Compose will load the [.env](.env) file to resolve environment variables referenced in the [docker-compose.yml](./docker-compose.yml) file. You can copy the [.env.template](.env.template) file to [.env](.env) as a starting point. This is where you can customize variables to match your desired configuration.

You can find the common environment variables from your deployed stack in the CloudFormation output name `ExportEnvVarScript`. Use this CLI to get the output in a proper format.

```sh
aws cloudformation describe-stacks --stack-name retaildemostore \
--region REGION \
--query "Stacks[0].Outputs[?OutputKey=='ExportEnvVarScript'].OutputValue" \
--output text
```

Then you can copy and override variables for each service in your [.env](.env) file.

### Amazon ECR authorization

Since some of the Docker images are hosted in Amazon ECR, you must authenticate your shell session before running docker-compose. Otherwise, the images will not be able to be downloaded. Run the following command to authenticate before running docker-compose. You should only have to do this once per shell session.

```sh
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws
```

### AWS credentials

Some services, such as the [products](./products) and [recommendations](./recommendations) services, need to access AWS services running in your AWS account from your local machine. Given the differences between these container setups, different approaches are needed to pass in the AWS credentials needed to make these connections. For example, for the recommendations service we can map your local `~./.aws` configuration directory into the container's `/root` directory so the AWS SDK in the container can pick up the credentials it needs. Alternatively, since the products service is packaged from a [scratch image](https://hub.docker.com/_/scratch), credentials must be passed using the `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN` environment variables. In this case, rather than setting these variables in `.env` and risk exposing these values, consider setting these three variables in your shell environment. The following command can be used to obtain a session token which can be used to set your environment variables in your shell.

> DynamoDB is one dependency that can be run locally rather than connecting to the real DynamoDB. This makes it easier to run services like the [products](./products) service completely local to you computer.

```console
foo@bar:~$ aws sts get-session-token
```

Docker compose will still pick variables set in your shell when building and launching the services.

## Run All Services

The following command will build and launch all Retail Demo Store web services in your local Docker engine.

```console
foo@bar:~$ docker compose up --build
```

## Run Specific Services

You can also choose to run specific services locally by appending the service names to the above command. For example, the following command builds and launches the [products](./products) and [web-ui](./web-ui) services only. Note that some configuration of the [web-ui](./web-ui) environment will likely be needed to match your configuration.

```console
foo@bar:~$ docker compose up --build products web-ui
```

For instructions specific to each Retail Demo Store web service, view the README page in each service sub-directory.

## Web UI Service

When deployed to AWS, the Web UI is hosted in an S3 bucket and served by CloudFront. For local development, you can deploy the Web UI in a Docker container. Since the Web UI makes REST API calls to all of the other services, you can configure the [Web UI's .env](web-ui/.env) file for which there is an example at [web-ui/.env.template](web-ui/.env.template) to point to services running either locally or deployed on AWS or a combination. Just update the appropiate environment variables to match your desired configuration.


## Swagger UI

There is a `swagger-ui` service in the `docker-compose.yml`. You can access it via [localhost:8081](http://localhost:8081). From there, you can select which service you want to check and send request agains the service via Swagger UI.

The `Dockerfile` of `swagger-ui` copies OpenAPI spec from each service (located at `<serviceName>/openapi/spec.yaml`). If you add a new service, please ensure that you write the OpenAPI spec and update the `Dockerfile` to copy yours.

> [!IMPORTANT]
> The documentation is now supported by [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/)
>
> You can read / browse directly on github [here](../docs/index.md)
>
> Alternatively you can clone the repo and run mkdocs locally to view the documentation:
> * Install [Mkdocs](https://squidfunk.github.io/mkdocs-material/getting-started/)
> * run `mkdocs serve` from the root of this repo
20 changes: 0 additions & 20 deletions src/aws-lambda/apigw-authorizer/bundle.sh

This file was deleted.

36 changes: 0 additions & 36 deletions src/aws-lambda/apigw-authorizer/index.js

This file was deleted.

20 changes: 0 additions & 20 deletions src/aws-lambda/apigw-authorizer/package-lock.json

This file was deleted.

5 changes: 0 additions & 5 deletions src/aws-lambda/apigw-authorizer/package.json

This file was deleted.

Loading