Components of a Static Web Site on AWS
ACM.227 Route 53, TLS, S3, API Gateway, CloudFront, WAF, and triggering Lambda Functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
⚙️ Check out my series on Automating Cybersecurity Metrics. The Code.
🔒 Related Stories: Cybersecurity | AWS Security | Appsec | Secure Code
💻 Free Content on Jobs in Cybersecurity | ✉️ Sign up for the Email List
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In the last post I wrote about automating the creation of a role profile. I’ve been using this in automated AMI creation scripts. Perhaps I’ll write more about that later.
I’m doing things out of order again but sometimes you have to do what you have to do. Someone hired me for a pentest and I need to migrate some setup to my new account. I have a particular infrastructure that I use for things like stored cross-site scripting (XSS), request smuggling, insecure redirects, and related attacks. I also have some websites I need to move.
I have already written this code but going to move it into my repository so it’s in a common, shared spot for future use.
Here are the things we’ll be deploying:
An AWS Account for Web Sites
At this point, I’m going to keep it simple and create one account for my static web sites to test this out. However, in an actual secure environment, you would most likely want different accounts, OUs, and service control policies as explained here:
For now, I’m going to run these commands from my sandbox account and create a website-sandbox account for testing purposes.
Adding this account is simple. For now I’m just going to add one more line to my script that deploys governance accounts:
Then run that script and my new account gets deployed.
An Apps folder for application stacks
I created a new folder for application stacks in my repository named apps.
I created a new folder within my apps folder named staticweb.
So in my GitHub repository you’ll find this folder: Apps/StaticWebsite.
I’m going have al the code to create what is necessary to manage static websites in this folder.
I moved the code to deploy the Sandbox-Web account to that folder.
Private GitHub Repository
A GitHub repository to store static content for a web site. I have future plans for this but for now it will be a simple, private repository.
This post explains how I automated the creation of private GitHub repositories for static web sites.
A Cross-Account IAM Role to Administer the Sandbox-Web account
I am going to create a cross account role in the SandBox-Web account and allow a WebAdmin assume the role from another account.
I used the functions created in this post.
But I fixed some bugs and simplified them a bit.
And created a test script.
And a refresh script.
More on IAM including how I created the role, group, and user templates and scripts here:
Domain Name Registration
I already have domain names set up. Some are registered in Route53 and some are registered elsewhere. Registration is a one-off process with some searching involved so I’m not going to automate that for the moment. This portion of the series presumes you have already registered a domain name.
I explained subdomains here and some risky configurations.
A Route 53 Hosted Zone
The hosted zone for my websites specifies the DNS records associated with the domain. Your records configure things like email, websites and some of the DNS security I wrote about in prior posts.
I provided scripts to deploy a Route 53 DNS Hosted Zone here.
I explained why I tagged the resources.
Updating Name Server Records
I went through a series of steps to get to a point where I could add the code to my script to update the Name Server records on an AWS Route 53 domain — with governance and security in mind.
I wrote about a multi-person process for NS record modifications for website deployments in large organizations:
Next, I realized I needed a change to my function that gets AWS account numbers.
Here’s a function for moving Accounts between organizational units.
Setting up a user and role in the domains account with permission to update NS records.
Automated creation of NS record on a primary domain hosted zone or a subdomain in a separate account using the AWS CLI.
More on DNS Security here, including manually setting up DNSSec on a domain (which I will fully automate in a subsequent post):
A TLS certificate from AWS certificate manager
Have you ever been involved in an incident where a web application is failing and no one can figure out why? Eventually they figure out it is a TLS (formerly SSL) certificate that has expired. I have. It took the lead person creating the UI for a big project off my team for a day. The other case I heard of was a large travel company losing $40,000 in one day to an issue like this. Welcome to automated certificate management — a dream come true — almost. The AWS certificate deployment process is a bit interesting. I’ll step you through it and provide the code to automate it.
Considering HSTS and other headers:
How a MITM attack relates to HSTS headers.
KMS Keys for static websites and logs
Do we need a key for a static website? Consider this and find out how I altered my KMS CloudFormation key template to accommodate static websites in different environments.
An S3 bucket for our website static content
I already showed you how to create a template for an S3 bucket but we’ll need some additional configuration, aligned with our Route 53 hosted zone.
Our bucket includes an access log bucket. We’ll dive into that deeper in subsequent posts after we get our bucket deployed.
More about AWS S3:
Trigger deployment when static content gets updated in GitHub
Somehow it would be nice to trigger a deployment when code is pushed to GitHub. There are various mechanisms by which we could achieve this feat. Here are a few.
Had to fix a couple of things to complete this section.
Public and Private Subnet in a VPC
Trying to create a batch job to clone code from GitHub to AWS CodeCommit via a batch job that requires MFA.
Phew. This took a lot longer than I expected.
Lambda didn’t work…it won’t let me use an assumed role saying the role doesn’t have permissions when it does. I keep thinking I must have done something wrong but I couldn’t get this to work. Maybe I’ll revisit it again later. I like the ultimate solution better for security anyway. We may still use Lambda and containers as figured out above for other purposes.
I attempted to use AWS Batch…it was overly complex and too expensive for my needs. I could have tried to use ECS alone — which is what Batch uses under the hood — but that seemed like overkill. Fargate has encryption issues as noted. Maybe those will be addressed by AWS one of these days and Fargate may become a viable solution, but it’s still quite complex.
Here I finally sorted out the roles Batch requires.
Regrouping and why.
This random post came about because I was looking at my bill after deploying a NAT, VPC Endpoints, and a Transit Gateway. I explain that the costs need to be relative to the rest of the deployment. I hope these costs are reduced by the time you read this.
Here, I’m switching gears. I’m going to run a batch job on the smallest possible EC2 instance that allows me to run a container on start up with a role that requires MFA and then shut down. All the parts and pieces to this solution are in the posts below but it’s not fully fleshed out. This is taking way too long so going to show how it can work and get back to the web site deployment.
In this post, I finally cracked the nut — run a batch job that requires MFA. Whether it works consistently requires further testing.
I am down a huge rabbit hole rebuilding my environment for what I really wanted to do long term …catch up here:
Once I’ve got the environment rebuilt I need to finish this deployment.
[TODO]
CloudFront
What is CloudFront anyway? It has various benefits including allowing you to create a global policy to disallow public S3 buckets.
In order to use CloudFront we’ll need to deploy it and an S3 bucket policy that allows CloudFront to access the contents in our S3 bucket.
Strategies to lower S3 bucket and KMS costs for static content hosted in S3.
An AWS Lambda function to respond to a web form
Although this is about static websites, a static website can call a Lambda function. I have some code to automatically deploy a lambda function. I already added that to the GitHub repository I provided to you. I’ll add to that and show you how to trigger a Lambda function from your static website.
Remember to keep it secure!
If you configure CloudFront correctly, you never need a public S3 bucket.
Ever.
API Gateway — Maybe
If I recall correctly I have some code to front an API Gateway. It might be something like this, but will be integrated, reusable code in my framework.
AWS WAF — At some point
I have some code to deploy an AWS WAF I gave students in classes. I’ll eventually add that to the repository. There are a couple of ways you can deploy AWS WAF. One is integrated with CloudFront.
Using CloudFormation…
As always I’ll be providing scripts using CloudFormation.
Follow for updates.
Teri Radichel | © 2nd Sight Lab 2023
About Teri Radichel:
~~~~~~~~~~~~~~~~~~~~
⭐️ Author: Cybersecurity Books
⭐️ Presentations: Presentations by Teri Radichel
⭐️ Recognition: SANS Award, AWS Security Hero, IANS Faculty
⭐️ Certifications: SANS ~ GSE 240
⭐️ Education: BA Business, Master of Software Engineering, Master of Infosec
⭐️ Company: Penetration Tests, Assessments, Phone Consulting ~ 2nd Sight Lab
Need Help With Cybersecurity, Cloud, or Application Security?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
🔒 Request a penetration test or security assessment
🔒 Schedule a consulting call
🔒 Cybersecurity Speaker for Presentation
Follow for more stories like this:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
❤️ Sign Up my Medium Email List
❤️ Twitter: @teriradichel
❤️ LinkedIn: https://www.linkedin.com/in/teriradichel
❤️ Mastodon: @teriradichel@infosec.exchange
❤️ Facebook: 2nd Sight Lab
❤️ YouTube: @2ndsightlab