|
| 1 | +# Certificate-Bound Access Tokens using Amazon API Gateway and Amazon Cognito |
| 2 | + |
| 3 | +This pattern makes use of API Gateway and Cognito to implement certificate-bound access tokens. For more on certificate-boud access tokens, review the [RFC](https://datatracker.ietf.org/doc/html/rfc8705). This solution has some manual steps which will be discussed later. |
| 4 | + |
| 5 | +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. |
| 6 | + |
| 7 | +## Requirements |
| 8 | + |
| 9 | +* [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. |
| 10 | +* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)~ |
| 11 | +* [AWS Serverless Application Model](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)~ (AWS SAM) installed |
| 12 | +* [Docker installed](https://docs.docker.com/engine/install/). |
| 13 | +* A domain that you own. |
| 14 | +* A certificate issued under the domain you own. |
| 15 | +* Create client certificate as per the [mTLS blogpost](https://aws.amazon.com/blogs/compute/introducing-mutual-tls-authentication-for-amazon-api-gateway/). |
| 16 | + |
| 17 | +Place the trust store in the S3 bucket that you will specfiy when deploying in the solution. |
| 18 | + |
| 19 | +## Deployment Instructions |
| 20 | + |
| 21 | +1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository: |
| 22 | +``` |
| 23 | +git clone https://github.com/aws-samples/serverless-patterns |
| 24 | +``` |
| 25 | + |
| 26 | +2. Change directory to the pattern directory: |
| 27 | +``` |
| 28 | +cd apigw-cognito-certificate-bound-access-token |
| 29 | +``` |
| 30 | + |
| 31 | +3. Build the solution: |
| 32 | +``` |
| 33 | +sam build --use-container |
| 34 | +``` |
| 35 | + |
| 36 | +3. Deploy the solution: |
| 37 | +``` |
| 38 | +sam deploy --guided |
| 39 | +``` |
| 40 | + |
| 41 | +Parameter_overrides: |
| 42 | + * BucketName - to store client certificate and trust store. |
| 43 | + * CACertKey - trust store. |
| 44 | + * ClientCertKey - client certificate Amazon S3 object key. |
| 45 | + * CustomDomainCertArn - custom domain AWS Certificate Manager certficate ARN. |
| 46 | + * CustomDomainName - custom domain name for API Gateway. Must match CustomDomainCertArn. |
| 47 | + |
| 48 | +## How it works |
| 49 | + |
| 50 | +This pattern creates an Amazon API Gateway REST API with a custom domain name and enables mTLS. Further, it creates a Cognito User Pool. The Cognito User Pool is used to issue certificate-bound access tokens. The REST API makes use of an authorizer to compare the "cnf" claim in the access token to the fingerprint of the client certificate sent as part of the mutual authentication TLS handshake. |
| 51 | + |
| 52 | +## Testing |
| 53 | + |
| 54 | +1. Determine the fingerprint of the client certificate and base64 encode it: |
| 55 | +``` |
| 56 | +openssl x509 -in client-cert.crt -noout -fingerprint -sha256 | cut -d'=' -f2 | tr -d ':' | xxd -r -p | base64 | tr -d '=' |
| 57 | +``` |
| 58 | + |
| 59 | +2. Navigate to the Cognito User Pool created in the solution. [Then create and verify](https://docs.aws.amazon.com/cognito/latest/developerguide/signing-up-users-in-your-app.html) a user. |
| 60 | + |
| 61 | +3. Add the certificate fingerprint to the `custom:cert_fingerprint` custom attribute of the user. |
| 62 | + |
| 63 | +4. [Create a DNS record](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-to-api-gateway.html) for the custom domain. |
| 64 | + |
| 65 | +5. [Get an access token](https://docs.aws.amazon.com/cognito/latest/developerguide/authentication-flows-public-server-side.html) from Cognito. |
| 66 | + |
| 67 | +Example of getting an access token using the AWSCLI: |
| 68 | +``` |
| 69 | +aws cognito-idp admin-initiate-auth \ |
| 70 | + --user-pool-id YOUR_USER_POOL_ID \ |
| 71 | + --client-id YOUR_CLIENT_ID \ |
| 72 | + --auth-flow ADMIN_USER_PASSWORD_AUTH \ |
| 73 | + --auth-parameters 'USERNAME=YOUR_USERNAME,PASSWORD=YOUR_PASSWORD' \ |
| 74 | + --region us-east-1 \ |
| 75 | + --query 'AuthenticationResult.AccessToken' \ |
| 76 | + --output text |
| 77 | +``` |
| 78 | + |
| 79 | +Notes that this requires the `ADMIN_USER_PASSWORD_AUTH` auth flow which is not enabled by default by this solution. You will need to do it on the console. This is only for testing purposes. |
| 80 | + |
| 81 | +6. Test the solution: |
| 82 | + |
| 83 | +``` |
| 84 | +curl -v https://<your_custom_domain>/example --cert client-cert.crt --key client-cert.key -H "Authorization: <certificate_bound_access_token>" |
| 85 | +``` |
| 86 | + |
| 87 | +You should see output as follows: |
| 88 | +``` |
| 89 | +{"message": "Hello from the example function!", "event": {"resource": "/example", "path": "/example"... |
| 90 | +``` |
| 91 | + |
| 92 | +## Cleanup |
| 93 | + |
| 94 | +1. Delete the stack |
| 95 | + ```bash |
| 96 | + sam delete |
| 97 | + ``` |
| 98 | +1. Confirm the stack has been deleted |
| 99 | + ```bash |
| 100 | + aws cloudformation list-stacks --query "StackSummaries[?contains(StackName,'STACK_NAME')].StackStatus" |
| 101 | + ``` |
| 102 | +---- |
| 103 | +Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
| 104 | + |
| 105 | +SPDX-License-Identifier: MIT-0 |
0 commit comments