Cloudfront can be simply defined as a CDN (Content Delivery Network), caching your static assets in a datacenter nearer to your viewers. But Cloudfront is a lot more complex and versatile than this simple definition. Cloudfront is a “pull” CDN, which means that you don’t push your content to the CDN. The content is pulled into the CDN Edge from the origin at the first request of any piece of content.
In addition to the traditional pull and cache usage, Cloudfront can also be used as:
A Networking Router
A Firewall
A Web Server
An Application Server
Why is using a CDN relevant?
The main reason is to improve the speed of delivery of static content. By caching the content on the CDN edge, you not only reduce the download time from a few seconds to a few milliseconds, but you also reduce the load and amount of requests on your backend (Network, IO, CPU, Memory, …).
Static content can be defined as content not changing between two identical requests done in the same time frame.
Identical can be as simple as the same URI, or as fine grained as down to the authentication header. The time frame can range between 1 second to 1 year. The most common case is caching resources like Javascript or CSS and serving the same file to all users forever. But caching a JSON response tailored to a user (Authentication header) for a few seconds reduces the backend calls when the user has the well-known “frenetic browser reload syndrome”.
Edges, Mid-Tier Caches, and Origins
Cloudfront isn’t “just” some servers in datacenters around the world. The service is a layered network of Edge Locations and Regional Edge Caches (or Mid-Tier Caches).
Edge Locations are distributed around the globe with more than 400 points of presence in over 90 cities across 48 countries. Each Edge Location is connected to one of the 13 Regional Edge Caches.
Regional Edge Caches are transparent to you and your visitors, you can’t configure them or access them directly. Your visitors will interact with the nearest Edge Location, which will connect to the attached Regional Edge Cache and finally to your origin. Therefore, in this article, we will refer to Cloudfront as the combination of Edge Locations and Region Edge Caches.
What Have We Learned?
Cloudfront is more than just a simple “pull-cache-serve” service
You improve delivery speed to your visitors
You can increase resilience by always using a healthy backend
You improve overall speed to your backend by leveraging AWS’s backbone
You can modify any request to tailor the response to your visitor’s device or region
You don’t always need a backend
You protect your backend by reducing the number of calls reaching it
Using CloudFront to distribute your web application is a good practice; by leveraging caching at the Edge, you ensure that your visitors will get the lowest latency possible.
But what if you had a pre-release of your application that isn’t for the whole world to see, but you still want to provide the same experience as you will in production? CloudFront doesn’t propose a solution out-of-the-box for this.
Using SAML Authentication with existing IAM Identity Center
You might have set up your AWS Accounts using Control Tower with Organizations and are managing your members using IAM Identity Center, the successor to AWS Single-Sign-On. Or you might use AWS Identity Center as a standalone tool to centralize your SSO credentials for 3rd party applications.
The Solution:
The application is the SAML Service Provider (SP), and IAM Identity Center is the SAML Identity Provider (IdP).
For each request, the SP validates the encrypted authorization cookie using a Lambda@Edge function in the viewer-request event.
If the Cookie isn’t valid: a. The Lambda@Edge function will create an Authorization Request and redirect the browser to the relevant IdP Endpoint. b. The IdP provides the user with a login page. c. Upon successful login, the IdP generates a SAML Assertion Document and redirects the browser to the SP ACS Endpoint. d. The SP validates the assertion, sets an encrypted authorization cookie in the browser, and redirects the browser to the originally requested URL.
If the Cookie is valid: a. The content is either served from the cache or retrieved from the origin.
Add an Application to the IAM Identity Center
For this, we assume you already have IAM Identity Center setup, perhaps already with some groups and users.
Open the AWS Console
Open IAM Identity Center
On the left menu, expand “Application assignments” and click on “Applications”
Click on the “Add application” button on the right
Choose “Add custom SAML 2.0 application” and click on the “Next” button
Enter a user-friendly Display Name
enter a user-friendly Description
Download the IAM Identity center SAML metadata file, you will need it to configure the solution
Leave Application start URL and Relay state empty
Enter dummy values for the Application ACS URL and the Application SAML audience, we will come back to configure this later
Click on the “Submit” button
Open your application settings
On the “Action” drop-down top right, choose “Edit Attribute Mappings”
Enter the name of your project (this value isn’t used but needs to be filled)
It creates 3 Lambda@Edge functions: 1. Protect: -Attached as viewer-request to the default CloudFront Behavior -Invoked on each request to validate the cookie and redirect the browser to the IdP if needed 2. acs: -Attached as viewer-request to the /saml/acs path -Invoked with POST by the browser with the SAML Assertion Document 3. metadata: -Attached as viewer-request to the /saml/metadata.xml path -Allows to retrieve the SP metadata document to configure the IdP
The region needs to be set to us-east-1, Lambda@Edge functions can only be deployed to this region
Create src/secrets/main.ts:
export const secrets = {
initVector: '1234567890123456', // change me to any 16 Bytes string
privateKey: '12345678901234567890123456789012', // change me to any 32 Bytes string
audience: 'audience string', // change me to my application name
idpMetadata: `XML content of IdP metadata.xml downloaded earlier`
};
Replace WantAuthnRequestsSigned="true" with WantAuthnRequestsSigned="false" in the IdP metadata if it is present.
Access to your distribution requires an authentication
SP initiated and IdP initiated login to your site
Direct access to your bucket is blocked
All visitors share the same cached content
Test it Out
Open http://domainName.s3 − website.{aws_region}.amazonaws.com/page.html: You receive an Access denied
Open https://${domainName}/page.html: You will be redirected to the IAM Identity Center login page and back to your site where the page will display
Clear your cookies
Open your IAM Identity Center start page and log-in
Select your application and click on it. You will be redirected to your site and already logged in
Open https://${domainName}/page2. You will see the content of page2/index.html
Open https://${domainName}/anything. You will see your 404 page
Why Lambda@Edge & Not CloudFront Functions?
CloudFront Functions doesn’t have access to the request body. IAM Identity Center will issue a POST request to the ACS endpoint with the payload in the body.
CloudFront Functions can’t include modules and has some limitations on what Javascript functions can be used
Conclusion
Serving your website using CloudFront is the perfect way to ensure low latency for all your visitors. You want to use the same technology in development as in production, but you want the next version of your application to be a surprise to your members.
You want to allow only certain members of your organization to have access to the next version.
To achieve this, we added an additional layer to CloudFront by protecting all access with a login wall and thus keeping unwanted eyes away from our future release. By adding this to CloudFront (which is our Network Stack), we didn't need to alter our application's code in any way, keeping it identical for development and production.
By leveraging the Identity Provider already used to grant access to AWS resources, we don't have to manage a separate IdP and still have the fine-grained capability of picking which members of the Organization can access our application. No need to send passwords via email and rotate them when we want to revoke access, as it would have been needed with HTTP's Basic Authentication.
We can as easily revoke access by simply removing the user from the relevant group.
Dance like nobody is watching; protect like everyone is.
We hope that you have now all your development work behind a login wall; if you need more information, you can contact the author at: daniel.muller@serverlessguru.com
About the Author
Daniel Muller - Senior Serverless Developer at ServerlessGuru
Daniel Muller has been an AWS and (mainly) a Serverless enthusiast for many years. When not banging on a keyboard, he is online playing games with friends or outside, enjoying life with his family.
Daniel Muller
Senior Serverless Developer at ServerlessGuru
Daniel has has developed multiple large-scale serverless applications for OTT, BigData, and MarTech and is currently a Sr Serverless Dev.