Skip to content
This repository was archived by the owner on Jul 20, 2024. It is now read-only.

Commit d2d35cb

Browse files
committed
Initial commit
1 parent f115c5f commit d2d35cb

File tree

4 files changed

+125
-13
lines changed

4 files changed

+125
-13
lines changed

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,16 @@
33
This is a Terraform module which provisions a NAT instance using an auto scaling group and spot request.
44

55

6+
## How it works
7+
8+
This provisions an EC2 instance for NAT.
9+
10+
The instance does the following things on startup:
11+
12+
1. Attach the ENI to `eth1`.
13+
1. Enable IP forwarding.
14+
1. Set to ignore ICMP redirect packets.
15+
1. Enable IP masquerade.
16+
1. Tear down `eth0`.
17+
18+
See [init.sh](data/init.sh) for more.

data/init.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/bin/bash -x
2+
3+
# Attach the ENI
4+
region="$(/opt/aws/bin/ec2-metadata -z | sed 's/placement: \(.*\).$/\1/')"
5+
instance_id="$(/opt/aws/bin/ec2-metadata -i | cut -d' ' -f2)"
6+
aws --region "$region" ec2 attach-network-interface \
7+
--instance-id "$instance_id" \
8+
--device-index 1 \
9+
--network-interface-id "${eni_id}"
10+
11+
# Wait for network initialization
12+
sleep 10
13+
14+
# Enable IP forwarding and NAT
15+
sysctl -q -w net.ipv4.ip_forward=1
16+
sysctl -q -w net.ipv4.conf.eth1.send_redirects=0
17+
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
18+
19+
# Switch the default route to eth1
20+
ip route del default dev eth0

main.tf

Lines changed: 82 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
resource "aws_security_group" "this" {
22
name_prefix = var.name
33
vpc_id = var.vpc_id
4+
description = "Security group for NAT instance ${var.name}"
5+
tags = {
6+
Name = "nat-instance-${var.name}"
7+
}
48
}
59

6-
resource "aws_security_group_rule" "this_egress" {
10+
resource "aws_security_group_rule" "egress" {
711
security_group_id = aws_security_group.this.id
812
type = "egress"
913
cidr_blocks = ["0.0.0.0/0"]
@@ -12,7 +16,7 @@ resource "aws_security_group_rule" "this_egress" {
1216
protocol = "tcp"
1317
}
1418

15-
resource "aws_security_group_rule" "this_ingress" {
19+
resource "aws_security_group_rule" "ingress" {
1620
security_group_id = aws_security_group.this.id
1721
type = "ingress"
1822
cidr_blocks = var.private_subnets_cidr_blocks
@@ -21,15 +25,64 @@ resource "aws_security_group_rule" "this_ingress" {
2125
protocol = "tcp"
2226
}
2327

28+
resource "aws_security_group_rule" "ssh" {
29+
count = var.key_name == "" ? 0 : 1
30+
security_group_id = aws_security_group.this.id
31+
type = "ingress"
32+
cidr_blocks = ["0.0.0.0/0"]
33+
from_port = 22
34+
to_port = 22
35+
protocol = "tcp"
36+
}
37+
38+
resource "aws_network_interface" "this" {
39+
security_groups = [aws_security_group.this.id]
40+
subnet_id = var.public_subnet
41+
source_dest_check = false
42+
description = "ENI for NAT instance ${var.name}"
43+
tags = {
44+
Name = "nat-instance-${var.name}"
45+
}
46+
}
47+
48+
resource "aws_eip" "this" {
49+
network_interface = aws_network_interface.this.id
50+
tags = {
51+
Name = "nat-instance-${var.name}"
52+
}
53+
}
54+
55+
resource "aws_route" "this" {
56+
count = length(var.private_route_table_ids)
57+
route_table_id = var.private_route_table_ids[count.index]
58+
destination_cidr_block = "0.0.0.0/0"
59+
network_interface_id = aws_network_interface.this.id
60+
}
61+
2462
resource "aws_launch_template" "this" {
2563
name_prefix = var.name
2664
image_id = var.image_id
65+
key_name = var.key_name
66+
2767
iam_instance_profile {
2868
arn = aws_iam_instance_profile.this.arn
2969
}
70+
3071
network_interfaces {
3172
associate_public_ip_address = true
3273
security_groups = [aws_security_group.this.id]
74+
delete_on_termination = true
75+
}
76+
77+
user_data = base64encode(
78+
templatefile("${path.module}/data/init.sh", {
79+
eni_id = aws_network_interface.this.id
80+
})
81+
)
82+
83+
description = "Launch template for NAT instance ${var.name}"
84+
tags = {
85+
Name = "nat-instance-${var.name}"
3386
}
3487
}
3588

@@ -38,7 +91,7 @@ resource "aws_autoscaling_group" "this" {
3891
desired_capacity = 1
3992
min_size = 1
4093
max_size = 1
41-
vpc_zone_identifier = var.public_subnets
94+
vpc_zone_identifier = [var.public_subnet]
4295

4396
mixed_instances_policy {
4497
instances_distribution {
@@ -58,6 +111,12 @@ resource "aws_autoscaling_group" "this" {
58111
}
59112
}
60113

114+
tag {
115+
key = "Name"
116+
value = "nat-instance-${var.name}"
117+
propagate_at_launch = true
118+
}
119+
61120
lifecycle {
62121
create_before_destroy = true
63122
}
@@ -86,7 +145,26 @@ resource "aws_iam_role" "this" {
86145
EOF
87146
}
88147

89-
resource "aws_iam_role_policy_attachment" "this_ssm" {
148+
resource "aws_iam_role_policy_attachment" "ssm" {
90149
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
91150
role = aws_iam_role.this.name
92151
}
152+
153+
resource "aws_iam_role_policy" "eni" {
154+
role = aws_iam_role.this.name
155+
name_prefix = var.name
156+
policy = <<EOF
157+
{
158+
"Version": "2012-10-17",
159+
"Statement": [
160+
{
161+
"Effect": "Allow",
162+
"Action": [
163+
"ec2:AttachNetworkInterface"
164+
],
165+
"Resource": "*"
166+
}
167+
]
168+
}
169+
EOF
170+
}

variables.tf

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,30 @@ variable "vpc_id" {
66
description = "ID of the VPC"
77
}
88

9-
variable "public_subnets" {
10-
description = "List of ID of the public subnets"
9+
variable "public_subnet" {
10+
description = "ID of the public subnet for the NAT instance"
1111
}
1212

1313
variable "private_subnets_cidr_blocks" {
1414
description = "List of CIDR blocks of the private subnets"
1515
}
1616

17+
variable "private_route_table_ids" {
18+
default = []
19+
}
20+
1721
variable "image_id" {
1822
description = "AMI of the NAT instance"
1923
# amzn-ami-vpc-nat-hvm-2018.03.0.20181116-x86_64-ebs
20-
default = "ami-0b840e8a1ce4cdf15"
24+
#default = "ami-0b840e8a1ce4cdf15"
25+
# Amazon Linux 2 AMI (HVM), SSD Volume Type
26+
default = "ami-04b762b4289fba92b"
2127
}
2228

2329
variable "instance_types" {
2430
description = "Candidates of instance type of the NAT instance"
2531
default = ["t3.nano", "t3a.nano"]
2632
}
2733

28-
variable "volume_size" {
29-
default = "8"
30-
}
31-
32-
variable "volume_type" {
33-
default = "gp2"
34+
variable "key_name" {
3435
}

0 commit comments

Comments
 (0)