Secure Bastion with Private Infrastructure


Overview

I built a secure AWS environment with a public and private subnet. In the public subnet I used an EC2 instance as a Bastion Host (which can only be accessed by the admin user's IP) to securely SSH into the EC2 instance in the private subnet. I used Security Groups and key pairs to restrict accessed


Cloud Architecture

I used the below architecture (as shown in the diagram above)

  • VPC: built with 2 subnets (public/private)
  • Bastion Host: EC2 with strict inbound rules (only my IP)
  • Private EC2: No public IP, only accessible via Bastion
  • 1 Route Table per subnet
  • An internet gateway
  • 1 availability zone

Software used

  • Terraform for provisioning the resources
  • Github for tracking the version control
  • Bash for storing environment variables, managing key pairs + SSH-ing into EC2 instsances
  • Tmux: for using several bash panes at the same time (1 for git, 1 for terraform, 1 for creating keypairs etc)
  • VSCode editor

Obstacles

This is a fun project for anyone starting out as it seems easy at first, but then you need to ensure many things work together

Environment Variables: You quickly realize for instance that if this code is meant for anyone on github to download it and run in on their local machine, you definitely can't hardcode values into your config (not to mention that its a big security risk). Some variables - like the AWS credentials - can be stored locally. But what about the user's IP and/or their keypair? You quickly realize here that it only makes sense to use environment variables.

Naming Conventions: Given that there are two of everything (two subnets, two route tables, two security groups etc) you need to ensure you're using a naming convention that makes sense. You need to strike a balance between ensuring meaning is conveyed, but perhaps not making the names too long or cumbersome.

Watch out for how you create resources: When creating my EC2s I did it without attaching security groups to them! Once I then created the SGs and applied them to the EC2s, the Terraform output showed it was destroying and then recreating the resources. I learned then and there that if this were in a production environment, that is not what you want. Imagine a server is running and users are depending on it. You can't destroy it. Thus, you must ensure to create your resources properly the first time round. Always work on a clean slate.


Code

You can find the code files on my github. In order to run it you will first need to know the following:

  • You need to know your AWS Credentials
  • You need to create your own Keypair to log into EC2 instances
  • Knowing how to check your own IP address can help

Check out the project's readme file for instructions on how to download it and run it on your machine