AWS single AZ architecture using Terraform
We are going to create the following architecture using Terraform
My setup includes:
Virtual Private Cloud (VPC) π
- What is it? Itβs like your own private piece of the internet!
- Features: Default tenancy, nice and spacious at
10.0.0.0/16
- Tags: Created with love by Terraform π
1
2
3
4
5
6
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
instance_tenancy = "default"
tags = merge(local.all_tags, tomap({ Name = "main" }))
}
Subnets π
- Private Subnet: A cozy corner for my private stuff
- Public Subnet: Where the world can peek in (but not too much!)
1
2
3
4
5
6
7
8
9
10
11
12
13
resource "aws_subnet" "private-subnet" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = var.az[0]
tags = merge(local.all_tags, tomap({ Name = "private-subnet" }))
}
resource "aws_subnet" "public-subnet" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.2.0/24"
availability_zone = var.az[0]
tags = merge(local.all_tags, tomap({ Name = "public-subnet" }))
}
Gateways and Routes π£οΈ
- Internet Gateway: My bridge to the big, wide internet π
- NAT Gateway: Secretly lets private stuff talk to the internet π
- Route Tables: Making sure my traffic goes where it should π¦
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
resource "aws_internet_gateway" "gw" {
vpc_id = aws_vpc.main.id
tags = merge(local.all_tags, tomap({ Name = "gw" }))
}
resource "aws_eip" "ngw-ip" {
domain = "vpc"
}
resource "aws_nat_gateway" "ngw" {
allocation_id = aws_eip.ngw-ip.allocation_id
subnet_id = aws_subnet.public-subnet.id
tags = merge(local.all_tags, tomap({ Name = "ngw" }))
# To ensure proper ordering, it is recommended to add an explicit dependency
# on the Internet Gateway for the VPC.
depends_on = [aws_internet_gateway.gw]
}
resource "aws_route_table" "private-route-table" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "10.0.0.0/16"
gateway_id = "local"
}
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_nat_gateway.ngw.id
}
tags = merge(local.all_tags, tomap({ Name = "private-route-table" }))
}
resource "aws_route_table" "public-route-table" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "10.0.0.0/16"
gateway_id = "local"
}
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.gw.id
}
tags = merge(local.all_tags, tomap({ Name = "public-route-table" }))
}
resource "aws_route_table_association" "private-route-asso" {
subnet_id = aws_subnet.private-subnet.id
route_table_id = aws_route_table.private-route-table.id
}
resource "aws_route_table_association" "public-route-asso" {
subnet_id = aws_subnet.public-subnet.id
route_table_id = aws_route_table.public-route-table.id
}
Instances π»
- Private EC2 Instance: My workhorse for private tasks π οΈ
- Bastian EC2 Instance: Meet my friendly public face! π€
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
data "aws_ami" "amazon-linux" {
most_recent = true
# name_regex = "^ami-0748249a1ffd1b4d2"
filter {
name = "image-id"
values = ["ami-0748249a1ffd1b4d2"]
}
}
resource "aws_instance" "private-ec2" {
ami = data.aws_ami.amazon-linux.id
instance_type = "t2.micro"
subnet_id = aws_subnet.private-subnet.id
vpc_security_group_ids = [aws_security_group.private-ec2-sg.id]
user_data = file("user-data.sh")
tags = merge(local.all_tags, tomap({ Name = "private-ec2" }))
}
resource "aws_instance" "bastian" {
ami = data.aws_ami.amazon-linux.id
instance_type = "t2.micro"
subnet_id = aws_subnet.public-subnet.id
vpc_security_group_ids = [aws_security_group.bastian-ec2-sg.id]
tags = merge(local.all_tags, tomap({ Name = "bastian" }))
key_name = aws_key_pair.key.key_name
provisioner "local-exec" {
command = "chmod 600 ${local_file.private_key_pem.filename}"
}
}
resource "aws_eip" "ec2-bastian-eip" {
instance = aws_instance.bastian.id
domain = "vpc"
}
Security Stuff π
- Security Groups: Like bouncers for my instances πΆοΈ
- Key Pair: My secret key to access the instances π
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
resource "aws_security_group" "private-ec2-sg" {
name = "private-ec2-sg"
description = "Allow HTTP traffic"
vpc_id = aws_vpc.main.id
tags = merge(local.all_tags, tomap({ Name = "private-ec2-sg" }))
}
resource "aws_vpc_security_group_ingress_rule" "allow_http_ipv4" {
security_group_id = aws_security_group.private-ec2-sg.id
cidr_ipv4 = aws_vpc.main.cidr_block
from_port = 80
ip_protocol = "tcp"
to_port = 80
}
resource "aws_vpc_security_group_egress_rule" "allow_all_traffic_ipv4" {
security_group_id = aws_security_group.private-ec2-sg.id
cidr_ipv4 = "0.0.0.0/0"
ip_protocol = "-1" # semantically equivalent to all ports
}
resource "aws_key_pair" "key" {
public_key = tls_private_key.rsa-2046-bastian.public_key_openssh
key_name = "AWSKey"
}
resource "aws_security_group" "bastian-ec2-sg" {
name = "bastian-ec2-sg"
description = "Allow ssh traffic"
vpc_id = aws_vpc.main.id
tags = merge(local.all_tags, tomap({ Name = "bastian-ec2-sg" }))
}
resource "aws_vpc_security_group_ingress_rule" "bastian-ssh" {
security_group_id = aws_security_group.bastian-ec2-sg.id
cidr_ipv4 = "0.0.0.0/0"
from_port = 22
ip_protocol = "tcp"
to_port = 22
}
resource "aws_vpc_security_group_egress_rule" "bastian-all-traffic" {
security_group_id = aws_security_group.bastian-ec2-sg.id
cidr_ipv4 = "0.0.0.0/0"
ip_protocol = "-1" # semantically equivalent to all ports
}
Fun Extras π
- TLS Private Key: Itβs a secretβ¦ shh! π€«
- Elastic IP: Gives my Bastian instance a cool, fixed address π
- Private Key PEM File: A secret file just for me! π
1
2
3
4
5
6
7
8
9
# RSA key of size 4096 bits
resource "tls_private_key" "rsa-2046-bastian" {
algorithm = "RSA"
rsa_bits = 2046
}
resource "local_file" "private_key_pem" {
content = tls_private_key.rsa-2046-bastian.private_key_pem
filename = "AWSKey.pem"
}
Usage π οΈ
To apply this infrastructure setup to your system, follow these steps:
Clone the Repository: Start by cloning this repository to your local machine. π₯
Set Up AWS Credentials: Ensure you have AWS credentials configured on your system, either by exporting them as environment variables or using AWS CLI configuration. π
Customize Configuration: Modify the
terraform.tfvars
file to match your requirements, including region and availability zones. π οΈInitialize Terraform: Run
terraform init
in your terminal to initialize Terraform and download necessary plugins. πPreview Changes: Use
terraform plan
to see what Terraform plans to create, modify, or destroy. πApply Changes: Once satisfied with the plan, execute
terraform apply
to create the infrastructure on AWS. πEnjoy Your AWS Setup: Voila! Your AWS infrastructure is now up and running. π
SSH into the Public Bastian Host: Use the public IP printed in the output to SSH into the Bastian EC2 instance. π₯οΈ
Get the Private IP of the Host in the Private Subnet: Once logged into the Bastian instance, retrieve the private IP address of the host in the private subnet. π΅οΈββοΈ
Download index.html Using Wget: Try using wget to download the index.html file from the private IP address. You should see the file downloaded onto the Bastian instance. (Example:
wget private_ip:80
) π₯
Remember to manage your infrastructure responsibly and destroy resources when they are no longer needed to avoid unnecessary costs. β»οΈ
Thatβs it! Have fun exploring my awesome setup! If you need anything, just give me a shout! π