(Illustration: Afternoon-tea with Grilled Halloumi Cheese. Not-so-related to this article, I know XDD. When writing such a long post, you know :p Image source: by Ernest, in London.)
This month Pahud invited us - a group of AWS Hero and AWS Builders to use AWS CDK to code around CloudFront Extensions (CloudFront Lambda@Edge). From my long todo list, I found a topic related to OAuth 2.0 that I have always wanted to do. It’s a perfect timing to try and see how to implement a CloudFront Extension solution in AWS CDK (Cloud Development Kit) with
.env environment variable settings, so that you can easily set your favorite IdP (Identity Provider), and then set the parameters generated by the IdP into
.env file. You can use this CloudFront Extension CDK solution to complete the deployment. After practicing, it should be completed within 20 minutes.
This article is organized in order for future education and training material, and is divided into three parts:
- At the beginning, we will introduce use cases, architecture, OAuth 2.0 protocol flow, and Grant Type: Authorization Code process
- Then select and configure a IdP you like (this part is expected to be expanded and updated in the future)
- Finally, “CloudFront Extension OAuth2 Getting Started” takes everyone to actually operate this CDK
1. Use Case
In recent years, the use of static site generators has gradually become a mainstream tool for setting up blogs or document sites. The generated static files, in addition to putting GitHub Pages, another good place is Amazon S3.
Putting Amazon CloudFront as a CDN in front of Amazon S3 is also a common choice.
In some usage scenarios, users are expected to log in before they can view the content of the website or document. In this case, you can request CloudFront Lambda@Edge to help us execute a Lambda program, log in and OAuth 2.0 authorization process with the IdP (Identity Provider) specified by ourselves.
In this case, we will use “Viewer request”, one of the four trigger points of CloudFront Lambda@Edge to trigger the execution of the Lambda program we specify to communicate with the IdP. If the OAuth2.0 Authorization Code is successfully authorized, the user will be allowed to watch the origin - the content of website or document.
Then look at two demo videos (corresponding to different IdPs, but both use standard OAuth 2.0 and OpenID) to quickly understand the use case that this article wants to implement:
- The following figure uses Auth0 (IdP) + OAuth2 Authentication (CloudFront Extension) implemented in this article
- The following figure uses self-built KeyCloak (IdP) + OAuth2 Authentication (CloudFront Extension) implemented in this article
- Also use CDK to quickly deploy KeyCloak
2. Amazon CloudFront Extensions
Amazon CloudFront Extensions is a combination of using Lambda@Edge to extend CloudFront to implement various rich features. Originally implemented using AWS CloudFormation, but this time Pahud invited us to use the AWS CDK method to implement it.
The git repo we implemented this time is placed in Pahud’s home: https://github.com/pahud/cdk-cloudfront-plus
The name of the extension I implemented this time is “OAuth2 Authentication”, project number “SO8131”, directory name “cf-authentication-by-oauth2”.
The goal of implementation is to create a universal package (Lambda@Edge), which can be set to correspond to various parameters provided by IdP (Identity Provider) by setting environment variables, such as client id, client secret, callback URL, etc. And hope to reduce package dependencies and use TypeScript throughout.
3. OAuth 2.0 Grant Type: Authorization Code
RFC6749 defines The OAuth 2.0 Authorization Framework, OpenID implemented OAuth 2.0 and integrated account information. Simply understand that OAuth 2.0 is a theory, and OpenID is one of the implementation methods based on this theory.
OAuth 2.0 defines four roles, six steps, Three round trips. Refer to the following Protocol Flow:
- Client: Authorization Request –> Resource Owner: Authorization Grant
- Client: Authorization Grant –> Authorization Server: Access Token
- Client: Access Token –> Resource Server: Protected Resource
Quick summary: three simple steps: first take a code –> take the code for a (access) token –> take the token for resources.
OAuth 2.0 defines four Authorization Grant Types:
- Authorization Code
- Authorization Code
- Authorization Code with PKCE
- Resource Owner Password Credentials
- Client Credentials
Quick summary: The context in this article is suitable for Authorization Code.
After establishing the process structure and narrowing down the scope of using the Authorization Code, then set up the IdP you choose, create a client in the IdP environment, and obtain various environmental variables of the IdP and the client.
In the process,
we will encounter various IdP hidden magic logic, oh no, I mean IdP, in order to strengthen the verification process, there will be different details that need to be paid attention to. E.g
- The Auth0 document does not mention but the authorize parameter combination must be
scope=openidto get the JWT token. (reference source)
- KeyCloak stipulates which URL the Client comes from at the beginning, and the subsequent specified
redirect_urimust be exactly the same URL before releasing, otherwise KeyCloak will keep spraying
400 Bad Requestwith a mysterious and unknown error log:
[0m[33m11:57:34,772 WARN [org.keycloak.events] (default task-97) type=CODE_TO_TOKEN_ERROR, realmId=RealmDemoCDK, clientId=demo-cloudfront-plus, userId=2ae58a4c-9b3e-4f0e-b58d-b9462e73105a, ipAddress=10.0.9.157, error=invalid_code, grant_type=authorization_code, code_id=fbb08df8-1af1-4960-a9ac-ab80e0b3d377, client_auth_method=client-secret. (reference source)
4.1 IdP Example Configuration: Auth0
- Application Type: Regular Web Application
- Token Endpoint Authentication Method: None
- Allowed Callback URLs: https://abcabcabcabcab.cloudfront.net/callback
- Allowed Web Origins: https://abcabcabcabcab.cloudfront.net
- Get your public key at Advanced Settings –> Certificates tab –> Signing Certificate.
4.2 IdP Example Configuration: KeyCloak
After implementing the Auth0 example, I am planning to connect a few more IdPs to verify that the OAuth 2.0 Authorization Code processes of each provider are consistent. I happened to chat with Pahud about his cdk-keycloak construct, it’s such a coincidence, so I started the integration journey of Keycloak
(aka trip to pit).
First of all, since the cdk-keycloak construct is already available, I only need to assemble a CDK app and execute it, so I made a cdk-keycloak-demo, please refer to repo README.md, there will be a chance to organize it into note articles in the future. For now, I will focus on how to set it up so that it can work with CloudFront Extension OAuth2.
It is recommended not to include blank characters in the name, preferably consecutive alphanumeric characters, with no difference in capitalization.
Then the Realm name will become part of the URL. In this example, it is called
Create a set of keys to generate JWT token in RS256. In this example, it is called
demo-cdk-rsa-key-pair. Please put the content of pressing the button “Public Key” on the right into the CLIENT_PUBLIC_KEY field of the CloudFront Extension OAuth2
CLIENT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQABAQUAA4GNADDCiQKBgQ8EpDw0PDfYYqAwWFnzVFkfC7+diZTkVJob3WwtaeIsY9ygFCjGhOSWgpJkB8pqGFu0kYT8Nz8ZBOetvMwFUAGBBPrOVa6TSocss8fwMmmkQvFxpC2UmzRZY1Oj+0eMGI0KUPJ6I7wTuPdnC0mip+RJdvKxJw7UhOld4yAp1JSQewIAAQAB\n-----END PUBLIC KEY-----"
In this example, it is called
demo-cloudfront-plus. Please put the content in the CLIENT_ID field of the CloudFront Extension OAuth2
Please refer to the figure below to select the corresponding on/off switch, and set the endpoint URL of the static website deployed by the CloudFront Extension OAuth2 demo to Root URL, Valid Redirect URLs, Admin URL and Web Origins, and finally set
* to Web Origins.
Get Client Secret
You can find Client Secret in the “Credentials” tab of Client settings. Please put the content in the CLIENT_SECRET field of the CloudFront Extension OAuth2
Create Client Role
In this example it is called
User. If the Client Role is not established and several subsequent associated actions, it will cause a 401 Unauthorized error.
This step is very flexible, you can use your favorite Username, Email, Last Name and First Name.
For the convenience of testing, I turned on User Enabled and Email Verified.
Setup User Credentials
For the convenience of testing, directly assign a set of passwords to this new User, turn off Temporary, and then press Reset Password. The picture below is the screen after the password has been set.
In this example it is called
Setup Group Role Mapping
Edit the newly created Group, use the Role Mappings tab, set the Client Roles, select the Client
demo-cloudfront-plus we created, and select the Client Role
User just created.
Setup User Group
Back to the User edit screen, use the Groups tab to classify this user into the Group
ClientUsers just created.
In order to enable CloudFront Extension OAuth2 to correctly connect and interact with KeyCloack, please set
Example format of CloudFront Extension OAuth2
5. CloudFront Extension OAuth2 Getting Started
To sum up, we have the process concept of Lambda@Edge, OAuth 2.0 Authorization Code grant type, and set up an IdP of our own choosing. Next, let’s run the CloudFront Extension OAuth2 demo and have a try. After the demo is successfully deployed, there will be a CloudFront distribution endpoint URL can be set back to the IdP Client, let IdP know this set of URLs.
The CloudFront Extension OAuth2 demo is placed in https://github.com/pahud/cdk-cloudfront-plus/tree/main/src/demo/cf-authentication-by-oauth2, you can clone the repo and operate directly in the project root directory. Remember to set up your AWS CLI environment, AWS profile, and CDK environment first.
dotenv/cf-authentication-by-oauth2/.env, and then set
.env according to your IdP environment.
cp dotenv/cf-authentication-by-oauth2/.env-example dotenv/cf-authentication-by-oauth2/.env
Open two terminals. One for yarn watch, and the other for cdk.
On the first terminal:
yarn install cd lambda-assets/extensions/cf-authentication-by-oauth2 yarn install cd ../../.. yarn watch
On the second terminal:
AWS_REGION=us-east-1 cdk --app lib/demo/cf-authentication-by-oauth2/index.js bootstrap AWS_REGION=us-east-1 cdk --app lib/demo/cf-authentication-by-oauth2/index.js diff AWS_REGION=us-east-1 cdk --app lib/demo/cf-authentication-by-oauth2/index.js deploy
Once you deploy successfully, the CDK script will output a CloudFront distribution endpoint URL. Please combine with the callback path you assigned in the
.env file to configurate callback URL at your IdP application/client setting.
On deploy completed, open the CloudFront URL with
If an error occurs during the process, you can go to the AWS Management Console and use the CloudWatch Logs function to track down. Remember to select the AWS Region that occurred to find the corresponding Lambda@Edge execution result, and remember to enable
Origin S3 (Private content)
If everything goes well, you will see the following content :) Replace it with your own web content or document to fit your case.
Hello CloudFront Extension with CDK!!! You have logged in. Enjoy your private content.
- Study Notes: AWS Cloud Development Kit (AWS CDK)
- OpenID Connect (Authorization Code Flow) with Red Hat SSO - all the detailed step-by-step screenshots of KeyCloak.
7. Bottom line
The beginning of this article introduces the usage scenarios, architecture, OAuth 2.0 principle, Grant Type: Authorization Code process, and then takes you to set up your own IdP Client/Application, and finally takes you to actually operate this CDK rapid deployment through “CloudFront Extension OAuth2 Getting Started”.
I have found a few friends for actual testing, and the deployment of CloudFront Extension OAuth2 CDK can be completed in 20 minutes without having issue when setting the IdP.
I hope this CloudFront Extension OAuth2 can save everyone’s time and let everyone focus more on product design and content output. You can try it out :)
If you like this kind of fully implemented articles, please use the form below to subscribe to my newsletter.