For those of you who don’t know, Contentful is a headless CMS created in Berlin that has been around for about 10 years, while NextJS is a 5 year old open-source development framework built on top of React.js.
So, we thought it was a good idea to match the kids in 2022 and have fun with them! But of course, the kids will always need a playground. As we are the grown ups, we chose it for them.
Let’s be honest. My first option was, and will always be, The City Museum in St Louis. It is educational (It is a museum… is it?), fun (You can climb around! There are secret passages!), for all ages (Yeah, I am not a kid anymore… am I?), attractive (see pictures) and it has a bus on the rooftop. In any case, always ask for other opinions!
But someone told me it wasn’t a good idea for our particular kids. So, we decided to try something different: AWS Amplify. “AWS Amplify is a set of purpose-built tools and features that lets frontend web and mobile developers quickly and easily build full-stack applications on AWS, with the flexibility to leverage the breadth of AWS services as your use cases evolve”. Well, sounds like Amplify will make our lives easier!
Great, so I have my data (Contentful), I have my application (built in NextJS and stored in Github) and I will put them together on the internet with Amplify. Let’s see how. Also, in case you need it, having the general user guide handy is helpful. But to make things easy I will explain it with my own words.
Create the Playground
1. Sign in to https://aws.amazon.com/console/. You will have to create an account and provide payment information if you don’t have an account.
2. Once you sign in to the AWS Console, look for the “Build a solution section”, and click on the “Host a static web app” link to configure your application.
3. Once in Amplify, click on “New app” and then “Host web app” to add your application.
4. The host wizard will guide you through the process. In our case, we will link the Github account, for what you will need to sign in with your account.
5. Once the Github account is linked, you will need to select the particular repository and branch that will be used.
6. Then, you will be asked to name your app, select or create a new service role, and add environment variables as needed.
7. If it is the first time you configure Amplify, you may need to create or select a new role, so Amplify can access the resources.
Make sure that the role is for Amplify, and that it has AdministratorAccess-Amplify permissions.
Once that is set, select the recently created role in Amplify.
For the Next.js application to work with Contentful, we also need to configure the environment variables. For this, use the Advanced Settings option, adding ids and tokens as needed:
8. Once that is completed, review and save.
Once clicked on the “Save and deploy” button, Amplify will connect to the Github repository, build and deploy the application.
Once the process is completed, the application will be automatically available at an automatically created production branch URL, similar to https://main.q1w2e3r4t5y6u7i8o9p0.amplifyapp.com.
Build the Playground Automatically
Creating the application as explained above will allow for automatic deployment. This means that every time a commit is pushed to the repository, the application will be built.
To check this configuration, go to Actions > App settings:
There, it is possible to enable/disable the continuous integration feature.
However, in my particular case, working with a forked project, it has been noticed that if the Github fork is updated with the code from the original repository, using the fetch-upstream option, the build is not triggered.
You need to actually pull the code locally, commit something and push it, for the trigger to happen.
Name Your Playground
Amplify builds automatically a default URL for the app, but it is possible to add a custom domain with a free SSL certificate to it.
The process seems to be simple, and can be started from the main view or the “Domain management” section from the App settings menu:
Click on add domain to access to the domain management section, where you can add and manage custom domains. Subdomains can be added also for branches if using multiple branch app hosting. Which would be a good idea, right? So you can actually push code to the development environment, test it, merge to main, and have production built automatically.
More information can be found here: https://docs.aws.amazon.com/amplify/latest/userguide/custom-domains.html.
Check that the Playground Works
Once the application is created, it is possible to create multiple environments within the same app, using subdomains that Amplify provides, or custom ones through the custom domain feature.
Create A New Test Environment
For this, click on the “Connect Branch” feature:
Select the branch you want to link (in this case, “develop”), and review and save.
A new hosting environment will be created, built and deployed.
Simple Access Control
Once this environment is created, it is possible to add some access control for it, adding a user and password to be able to access it. For this, click on Access control > Manage access, set the access level for each environment and provide a user and password for access to be granted:
Multiple Backend Environments
Once a second hosting environment has been created linked to a new branch, it is possible to manage environment variables and override them depending on the branch. This way, it should be possible to link the development hosting environment to a different Contentful backend.
Amplify provides the possibility to preview changes from pull requests before merging the code to a branch through the Previews functionality.
This way, the functionality can be visually reviewed before releasing it.
A web preview deploys every pull request made to your GitHub repository to a unique preview URL which is completely different from the URL your main site uses. For apps with backend environments provisioned using the Amplify CLI, every pull request spins up an ephemeral backend that is deleted when the PR is closed.
However, for security purposes, previews only work with private repositories for fullstack apps using the Amplify CLI.
Always Have A Safe Playground!
It is recommended to add a Web Application Firewall (WAF) in front of the API.
So we are going to set an example on how to use WAF to restrict access to particular places of our application. In this case, we are going to limit access to /api/hello (in fact, anything under /api). In our case, hidden in the Github code there is a small API so when you access https://main.q1w2e3r4t5y6u7i8o9p0.amplifyapp.com/api/hello, the application will return a simple json:
Let’s configure WAF to block this!
Identify the Hosting Environment
AWS Amplify leverages the Amazon CloudFront Global Edge Network to distribute the web app globally, so the first step is to identify which one is the Cloudfront ID linked to the hosting we created manually.
There are different ways to identify the Cloudfront ID (all Cloudfront ids linked to hosting environments seem to be displayed in the Rewrites and Redirects section). The method we show in this documentation will help to identify it for a particular hosting environment.
Open the app for which you want to create the WAF (in this case, “contentful-nextjs-demo”).
Select the hosting environment you want to identify. In our case, we are going to be working with the “main” branch hosting. Open the deploy section. The Cloudfront domain id will be displayed there:
Create A Web ACL
Then open the WAF & Shield service. You can search for it in the Services search box at the top of the screen.
Click on Create Web ACL
Describe Web ACL and Associate It to AWS Resources
Name the Web ACL and select Cloudfront distributions
Click on Add AWS resources
You will see the AWS resources linked to your account.
Identify the cloudfront distribution resource you are looking for. In this example, we were looking for d1y39qnl9cwa57. Notice that the distribution ID matches:
Add and associate the distribution to the Web ACL:
Add Rules and Rule groups
You can add a set of pre generated rules, or create new ones. In this example we are going to create a custom one.
Make sure to validate the rule name, as it is restricted!
Create the rule. In this case, if a request uri starts with api (as in https://main.q1w2e3r4t5y6u7i8o9p0.amplifyapp.com/api/hello) we want to block it.
Save and check that all looks good:
Set Rule Priority
Once the rule has been created, we need to set the rule priority. As this is the only rule so far we will keep it by default, and move to the next screen.
Time to configure metrics! For this example, also by default. Just click on Next.
Review and Test
Check that everything looks good, and save. You will see the newly created web ACL in your list.
The only thing remaining is to test it! Check the url and see that a default 403 error is coming up:
If we compare it with the development branch outcome:
And, of course, the rest of the pages can be accessed with no issues:
Let’s suppose that you want to block access to /api* unless there is a particular header in the request. We can do this with a simple update.
Select the Web ACL we just created:
Go to Rules, and click on the rule we just created:
Change the request from “Matches the statement” to “Matches all the statements (AND)”
Negate the new statement, and add a header:
Add your custom header with the value that you expect:
And save the rule. Now test it again. You will see that you still receive the same error message:
However, if you send the Authorization header, i.e. using Postman, you will be granted access to the original result!
And if you don’t send the header:
And that’s all you need to have a playground for the kids!