Files

163 lines
4.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🚀 Example Terraform EC2 Setup with Hardened Security & Docker
_A demo project showing Terraform provisioning, instance hardening, and Docker setup on AWS._
---
## 📖 Overview
While Im newer to Terraform, this project applies my DevSecOps background to build **hardened**, **reproducible** infrastructure as a teaching artifact.
---
## 🗺️ Architecture at a Glance
```
Terraform --> AWS EC2 (Ubuntu)
|
+--> 🔐 SSH hardened
+--> 🛡️ nftables firewall
+--> 📦 Docker & Compose plugin
+--> 🖥️ Optional Portainer UI
```
---
## ✨ Key Features
- **Terraform-driven infrastructure**: EC2 instance, Security Group, and Key Pair.
- **🔐 Security-first mindset and configuration**:
- Custom SSH port
- Fail2Ban for brute-force protection
- `nftables` firewall rules with least-privilege defaults
- Automatic security updates
- **🐳 Docker-ready**: Installs Docker, Docker Compose plugin, and optional Portainer UI.
- **⚙️ Parameterized & reusable**: All sensitive settings are variables for easy demo → production transitions.
---
## 📋 Prerequisites
- AWS account with IAM user permissions to create EC2, Security Groups, and Key Pairs
- [Terraform](https://developer.hashicorp.com/terraform/downloads) installed (v1.5+ recommended)
- SSH key pair ready
---
## 💡 Finding the latest Ubuntu AMI
Run this in AWS CLI (replace `us-east-1` with your region) to get the most recent Ubuntu 24.04 LTS AMI ID:
```bash
aws ec2 describe-images \
--owners 099720109477 \
--filters "Name=name,Values=ubuntu/images/hvm-ssd/ubuntu-noble-24.04-amd64-server-*" \
"Name=state,Values=available" \
--query 'Images | sort_by(@, &CreationDate)[-1].ImageId' \
--region us-east-1 --output text
```
Canonicals AWS account ID is `099720109477` — this ensures you get the official image.
---
## ⚡ Quick Start — Demo Mode
_Opens ingress for fast testing; **not** productionsafe._
```bash
# 1. Clone and enter the project
git clone https://github.com/patrickbeane/terraform-aws-ec2-hardened.git
cd terraform-aws-ec2-hardened
# 2. Initialize Terraform
terraform init
# 3. Apply with allopen demo settings
terraform apply \
-var='allowed_cidr_blocks=["0.0.0.0/0"]' \
-var='ami_id=ami-0abcdef1234567890' \
-var='public_key_path=~/.ssh/YOUR_PUBLIC_KEY.pub'
```
After apply:
- **SSH** -> `ssh -p <ssh_port> ubuntu@<instance_public_ip>`
- **Portainer** -> `https://<instance_public_ip>:<portainer_port>` (accept cert warning)
---
## 🛡️ Full Setup — ProductionReady
_Locks ingress to trusted CIDRs; HTTPSonly by default._
```bash
# Copy example vars to a working file
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars for your region, IPs, and key path
nano terraform.tfvars
# Then initialize and apply
terraform init
terraform apply
```
See [⚠️ Security Notes](#security-notes) before going live.
---
### Demo vs Production at a Glance
| Setting | Demo Mode | ProductionReady |
|----------------------|-----------------|----------------------------|
| `allowed_cidr_blocks`| `["0.0.0.0/0"]` | `["203.0.113.42/32"]` |
| `enable_http` | true | false |
| Security Group | wide open | CIDRrestricted |
| nftables rules | open ingress | CIDRrestricted ingress |
---
## 🔍 Outputs
After applying, Terraform displays:
```
instance_public_ip = x.x.x.x
```
**Access your instance**:
```bash
ssh -p <ssh_port> ubuntu@<instance_public_ip>
```
**Access Portainer** (if enabled):
```bash
https://<instance_public_ip>:<portainer_port>
```
If you get a certificate warning on first visit, accept the selfsigned cert.
---
## ⚠️ Security Notes
- **Demo mode**: All ingress rules are `0.0.0.0/0` for testing and demonstration.
- **Production**: Restrict SSH/Portainer/HTTP/S ingress to trusted IPs or ranges.
- All key paths, ports, and AMIs are configurable via `variables.tf`.
---
## 📂 user-data Script Highlights
- OS updates & package upgrades
- SSH port change & password auth disabled
- Fail2Ban install & config
- `nftables` rules applied and persisted (demo vs production notes in script)
- Docker install, enabled, and user permissions set
- (Optional) prepull of Portainer
---
## 🚧 Future Enhancements
- Optional TLS for Portainer via Traefik
- Prebaked AMIs with hardened baselines
---
## 📜 License
MIT License