How to setup a serverless blog securely on AWS without WordPress

Posted by Ben Potter on Monday, October 26, 2020

Contents

Introduction

WordPress creates beautiful blog web sites, and is also a cyber security nightmare! What if you can get the same beauty with security, and host it serverless on AWS?

I’m going to show you an outline of how you can setup a blog, but not go into each individual step with screen shots as you can find this elsewhere and it gets outdated quickly. These steps are what I’ve taken to create this blog.

How to choose a blog content management system / platform

The first place to start is to choose a content management system (CMS) or blog platform to use. WordPress is incredibly popular, but as a security specialist it makes me cringe - the amount of vulnerabilities it has (especially all the plugins)! The other downside of WordPress is it needs an instance (server), ideally two or more with a load balancer for high availability, all which costs money. It also needs constant security patches, updates, backing up, and general care. Why not go serverless for a blog, even go completely static? I created the AWS Well-Architected Labs starting in markdown, until we converted them into Hugo as it has rich content management features and outputs a simple static web site in html. Turns out that Hugo has many themes, including blogs!

Create and secure your AWS account

  1. It’s a best practice to use separate accounts for each workload, environment or stage you create - even if it’s personal use! The bonus is you get to use the free tier for each account. I created a new account for this blog, and it will only be used for this blog following these instructions. Note that you need a unique email address for every AWS account, and you can use email aliases. Be sure to use an email address that you check regularly as AWS might need to contact you about your account from time to time.

Once you have a fresh new account there are some foundational steps you need to take to secure it.

  1. Review the IAM best practices. Your root password should be 16 characters or more, use symbols and be randomly generated - do not use the same password for anything else.

  2. Assign a MFA device to root user, virtual is fine however Yubikey is better and can be used on multiple AWS accounts and many other web sites.

  3. You can create an IAM user following the IAM best practices, assign MFA device to that too, however you should not under any circumstances create an access key. That access key is not protected by MFA and you might accidentally lose it, like committing it to GitHub, and lose control of your new account. If you need an access key in the future, e.g. for using the Command Line Interface (CLI), you can enable the AWS Single Sign-On (SSO) service for no cost and it generates a temporary key to you, and integrates with the CLI. It can also help logging in to multiple AWS accounts, and is highly recommend if you have more than a single AWS account.

  4. Enable Amazon GuardDuty for threat detection, you can follow setting up. GuardDuty needs to be configured in each region you will use. You should enable GuardDuty in the US East (N. Virginia) also known as us-east-1 to start with. There is a cost, it’s most likely under $1 / month as it priced on actions in your account.

  5. Enable AWS CloudTrail to record the activity in your AWS account. For example, every time you login to the console it records the time, your IP address, user-agent, and more for every API call.

  6. Enable AWS Config to record the configuration changes in your AWS account. Where CloudTrail records activity, Config records the configuration state.

  7. Enable AWS Security Hub to automatically check your AWS account for configuration issues, and advise how you can improve.

Register and Host New Domain Name in Route53

If you don’t already have a domain, you need to get one! You can register a domain and host the DNS in Amazon Route 53. If you’ve never registered a domain before you should check out How domain registration works.

  1. Register a domain in Route53 by following the first step in Getting started with Amazon Route 53. You can transfer an existing domain, or even use a different registra but then you won’t get the features of Route53 like query logging.

Select and Copy a Hugo Theme

  1. Check out the Hugo themes and pick one that you like the look and features of. Many have a demo option so you can see them in action. Any theme can be customized, it’s up to you how much time and effort you put in.

  2. Follow your chosen theme instructions which is normally a git clone or copy to your local folder. While you can clone the repository, it means any upstream submodules require additional configuration and you cannot edit.

Install and Test Hugo

  1. Use the Quick Start to install Hugo on your computer. This allows you to build and test your blog on your computer.

  2. Follow the instructions to customize your chosen template, most will have a config.toml text file with settings to change.

  3. Start the Hugo server on your computer by running hugo serve in a command prompt at the base directory or folder of your blog.

  4. Navigate to your new site at http://localhost:1313/.

  5. Play with the different settings, images and content to make it look nice :).

Deploy Hugo Site to AWS

Here is where you need to make a decision, do you want a quick deployment with no fuss, or do you like to tinker with settings or need additional security?

AWS Amplify supports Hugo, and you can follow the official guide to deploy Hugo using AWS Amplify from a GitHub repository. It’s best to use the latest Hugo version instructions, as that’s what you will use on your local computer if you just installed it. Amplify is great to get started, however it doesn’t have the security features that I want to use.

I chose to use Amazon CloudFront content delivery network to serve my static content from Amazon S3. The main reason is to simplify the configuration, and the web site logs are not automatically saved in Amplify, logs allow me to see who is visiting and any potential attacks. There is however a workaround in Hugo that allows your own CloudFront distribution to be in front of the one Amplify configures for you. I also want to block unwanted requests using a web application firewall (WAF) in the future, and to set HTTP headers that follow best practices to secure the web site that you can test with Mozilla Observatory.

  1. To follow the path I chose, you need to create a bucket in Amazon S3 to store your content in, and then link it to Amazon CloudFront to deliver it. The easiest way to do this is to follow the Getting started with a secure static website instructions.

  2. Copy the contents of your Hugo /public folder into the bucket, you can do this by dragging into the web console. You shouldn’t see the public folder listed in the bucket, only the contents under it.

  3. Your web site should load, it can take an hour or so if you just created your S3 bucket and CloudFront distribution as it needs to propagate. If you test in the same web browser you have logged into AWS with try a private window.

Additional Configuration

  1. The theme I chose was not providing the right description for RSS so I followed the instructions from this blog to customize the feed by creating an ‘rss.xml’ file.

  2. Hugo uses “pretty” URLs e.g. ones that do not have the file name index.html, and S3 does not automatically serve the index.html through CloudFront so I needed to create a Lambda@Edge function to create a redirect following the instructions from https://faragta.com/aws-cloudfront/rewrite-url.html.

These instructions have been very high level, if you are stuck and need help the best way to contact me is via LinkedIn. I encourage you to learn and be curious.