Skip to content

Commit

Permalink
Merge pull request #39 from git-ival/byo-aws-vpc
Browse files Browse the repository at this point in the history
  • Loading branch information
moio authored Jan 23, 2025
2 parents c3ab765 + c033f3a commit 4844f25
Show file tree
Hide file tree
Showing 11 changed files with 182 additions and 78 deletions.
8 changes: 4 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
.DS_Store

# tofu related
tofu/main/*/.terraform
tofu/main/*/.terraform.lock.hcl
tofu/main/*/terraform.tfstate
tofu/main/*/terraform.tfstate.*
tofu/**/*/.terraform
tofu/**/*/.terraform.lock.hcl
tofu/**/*/terraform.tfstate
tofu/**/*/terraform.tfstate.*
tofu/main/*/*config
*.tfvars

Expand Down
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ To recreate environments:
- `dartboard reapply` runs `destroy` and then `apply`, tearing down and recreating test configuration infrastructure without any software (Rancher, load generation, moniroting...)
- `dartboard redeploy` runs `destroy` and then `deploy`, tearing down and recreating the full environment, infrastructure and software (use this if unsure)

### "Bring Your Own" AWS VPC
There is some manual configuration required in order to use an existing AWS VPC instead of having the tofu modules create a full set of networking resources.

1. Have an existing VPC with a DHCP options set configured so that DNS = "AmazonProvidedDNS".
2. Create three subnets, requirements are as follows:
1. One subnet should contain the substring "public" (case-sensitive), and should be tagged with `Tier = Public` (case-sensitive)
2. One subnet should contain the substring "private" (case-sensitive), and should be tagged with `Tier = Private` (case-sensitive)
3. One subnet should contain the substring "secondary-private" (case-sensitive), and should be tagged with `Tier = SecondaryPrivate` (case-sensitive)
4. Each subnet should be assigned to the VPC you intend to use

Once these resources are manually setup, you can set the `existing_vpc_name` tofu variable in your Dart file and deploy as you normally would.

## Installation

Download and unpack a [release](https://github.com/rancher/dartboard/releases/), it's a self-contained binary.
Expand Down Expand Up @@ -80,7 +92,7 @@ pkill -f 'ssh .*-o IgnoreUnknown=TofuCreatedThisTunnel.*'
If an Azure VM is not accessible via SSH, try the following:
- add the `boot_diagnostics = true` option in `inputs.tf`
- apply or re-deploy
- in the Azure Portal, click on Home -> Virtual Machines -> <name> -> Help -> Reset Password
- in the Azure Portal, click on Home -> Virtual Machines -> <name> -> Help -> Reset Password
- then Home -> Virtual Machines -> <name> -> Help -> Serial Console

That should give you access to the VM's console, where you can log in with the new password and troubleshoot.
Expand Down
1 change: 1 addition & 0 deletions tofu/main/aws/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module "network" {
project_name = var.project_name
region = var.region
availability_zone = var.availability_zone
existing_vpc_name = var.existing_vpc_name
bastion_host_ami = length(var.bastion_host_ami) > 0 ? var.bastion_host_ami : null
ssh_bastion_user = var.ssh_bastion_user
ssh_public_key_path = var.ssh_public_key_path
Expand Down
6 changes: 6 additions & 0 deletions tofu/main/aws/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ variable "availability_zone" {
default = "us-east-1a"
}

variable "existing_vpc_name" {
description = "Name of existing VPC to use. If null, a new VPC will be created"
type = string
default = null
}

variable "bastion_host_ami" {
description = "AMI ID"
default = "ami-0e55a8b472a265e3f"
Expand Down
51 changes: 51 additions & 0 deletions tofu/modules/aws/network/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Data source to look up existing VPC
data "aws_vpc" "existing" {
count = local.create_vpc ? 0 : 1

filter {
name = "tag:Name"
values = [var.existing_vpc_name]
}
}

data "aws_internet_gateway" "existing" {
count = local.create_vpc ? 0 : 1
filter {
name = "attachment.vpc-id"
values = [local.vpc_id]
}
}

# Data sources to look up existing subnets
data "aws_subnet" "public" {
count = local.create_vpc ? 0 : 1
vpc_id = one(data.aws_vpc.existing[*].id)
availability_zone = var.availability_zone

tags = {
Name = "*public*",
Tier = "Public"
}
}

data "aws_subnet" "private" {
count = local.create_vpc ? 0 : 1
vpc_id = one(data.aws_vpc.existing[*].id)
availability_zone = var.availability_zone

tags = {
Name = "*private*"
Tier = "Private"
}
}

data "aws_subnet" "secondary_private" {
count = local.create_vpc && var.secondary_availability_zone != null ? 0 : 1
vpc_id = one(data.aws_vpc.existing[*].id)
availability_zone = var.secondary_availability_zone

tags = {
Name = "*secondary*private*"
Tier = "SecondaryPrivate"
}
}
150 changes: 80 additions & 70 deletions tofu/modules/aws/network/main.tf
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
/*
This module sets up a class B VPC sliced into three subnets, one public and one or two private.
The public network has an Internet Gateway and accepts SSH connections only.
The private networks have Internet access but do not accept any connections.
A secondary private connection is optional, and is used to support RDS use cases.
*/

# VPC resource created only when existing_vpc_name is null
resource "aws_vpc" "main" {
count = local.create_vpc ? 1 : 0
cidr_block = "172.16.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
Expand All @@ -16,7 +11,21 @@ resource "aws_vpc" "main" {
}
}

# Update locals to use coalescing for resource selection
locals {
vpc_id = coalesce(one(aws_vpc.main[*].id), one(data.aws_vpc.existing[*].id))
vpc_cidr_block = coalesce(one(aws_vpc.main[*].cidr_block), one(data.aws_vpc.existing[*].cidr_block))
internet_gateway_id = coalesce(one(aws_internet_gateway.main[*].id), one(data.aws_internet_gateway.existing[*].id))

public_subnet_id = coalesce(one(aws_subnet.public[*].id), one(data.aws_subnet.public[*].id))
private_subnet_id = coalesce(one(aws_subnet.private[*].id), one(data.aws_subnet.private[*].id))
secondary_private_subnet_id = coalesce(one(aws_subnet.secondary_private[*].id), one(data.aws_subnet.secondary_private[*].id))

create_vpc = var.existing_vpc_name == null
}

resource "aws_internet_gateway" "main" {
count = local.create_vpc ? 1 : 0
vpc_id = local.vpc_id

tags = {
Expand All @@ -25,12 +34,8 @@ resource "aws_internet_gateway" "main" {
}
}

locals {
vpc_id = aws_vpc.main.id
vpc_cidr_block = aws_vpc.main.cidr_block
}

resource "aws_eip" "nat_eip" {

tags = {
Project = var.project_name
Name = "${var.project_name}-nat-eip"
Expand All @@ -39,27 +44,62 @@ resource "aws_eip" "nat_eip" {

resource "aws_nat_gateway" "nat" {
allocation_id = aws_eip.nat_eip.id
subnet_id = aws_subnet.public.id
subnet_id = local.public_subnet_id

depends_on = [aws_internet_gateway.main]
depends_on = [data.aws_internet_gateway.existing, aws_internet_gateway.main]

tags = {
Project = var.project_name
Name = "${var.project_name}-nat"
}
}

resource "aws_route_table" "public" {
vpc_id = local.vpc_id
resource "aws_subnet" "public" {
count = local.create_vpc ? 1 : 0
availability_zone = var.availability_zone
vpc_id = local.vpc_id
cidr_block = "172.16.0.0/24"
map_public_ip_on_launch = true

route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
tags = {
Project = var.project_name
Name = "${var.project_name}-public-subnet"
}
}

resource "aws_subnet" "private" {
count = local.create_vpc ? 1 : 0
availability_zone = var.availability_zone
vpc_id = local.vpc_id
cidr_block = "172.16.1.0/24"
map_public_ip_on_launch = false

tags = {
Project = var.project_name
Name = "${var.project_name}-private-subnet"
}
}

resource "aws_subnet" "secondary_private" {
count = local.create_vpc && var.secondary_availability_zone != null ? 1 : 0
availability_zone = var.secondary_availability_zone
vpc_id = local.vpc_id
cidr_block = "172.16.2.0/24"
map_public_ip_on_launch = false

tags = {
Project = var.project_name
Name = "${var.project_name}-public-route-table"
Name = "${var.project_name}-secondary-private-subnet"
}
}

resource "aws_key_pair" "key_pair" {
key_name = "${var.project_name}-key-pair"
public_key = file(var.ssh_public_key_path)

tags = {
Project = var.project_name
Name = "${var.project_name}-ssh-key-pair"
}
}

Expand All @@ -68,74 +108,52 @@ resource "aws_main_route_table_association" "vpc_internet" {
route_table_id = aws_route_table.public.id
}

resource "aws_route_table" "private" {
resource "aws_route_table" "public" {
vpc_id = local.vpc_id

route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.nat.id
cidr_block = "0.0.0.0/0"
gateway_id = local.internet_gateway_id
}

tags = {
Project = var.project_name
Name = "${var.project_name}-private-route-table"
Name = "${var.project_name}-public-route-table"
}
}

resource "aws_subnet" "public" {
availability_zone = var.availability_zone
vpc_id = local.vpc_id
cidr_block = "172.16.0.0/24"
map_public_ip_on_launch = true
resource "aws_route_table" "private" {
vpc_id = local.vpc_id

route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.nat.id
}

tags = {
Project = var.project_name
Name = "${var.project_name}-public-subnet"
Name = "${var.project_name}-private-route-table"
}
}

resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
subnet_id = local.public_subnet_id
route_table_id = aws_route_table.public.id
}

resource "aws_subnet" "private" {
availability_zone = var.availability_zone
vpc_id = local.vpc_id
cidr_block = "172.16.1.0/24"
map_public_ip_on_launch = false

tags = {
Project = var.project_name
Name = "${var.project_name}-private-subnet"
}
}

resource "aws_route_table_association" "private" {
subnet_id = aws_subnet.private.id
subnet_id = local.private_subnet_id
route_table_id = aws_route_table.private.id
}

resource "aws_subnet" "secondary_private" {
count = var.secondary_availability_zone != null ? 1 : 0
availability_zone = var.secondary_availability_zone
vpc_id = local.vpc_id
cidr_block = "172.16.2.0/24"
map_public_ip_on_launch = false

tags = {
Project = var.project_name
Name = "${var.project_name}-secondary-private-subnet"
}
}

resource "aws_route_table_association" "secondary_private" {
count = var.secondary_availability_zone != null ? 1 : 0
subnet_id = aws_subnet.secondary_private[0].id
route_table_id = aws_route_table.private.id
}

resource "aws_vpc_dhcp_options" "dhcp_options" {
count = local.create_vpc ? 1 : 0
domain_name = var.region == "us-east-1" ? "ec2.internal" : "${var.region}.compute.internal"
domain_name_servers = ["AmazonProvidedDNS"]

Expand All @@ -146,8 +164,9 @@ resource "aws_vpc_dhcp_options" "dhcp_options" {
}

resource "aws_vpc_dhcp_options_association" "vpc_dhcp_options" {
count = local.create_vpc ? 1 : 0
vpc_id = local.vpc_id
dhcp_options_id = aws_vpc_dhcp_options.dhcp_options.id
dhcp_options_id = aws_vpc_dhcp_options.dhcp_options[0].id
}

resource "aws_security_group" "public" {
Expand Down Expand Up @@ -222,16 +241,7 @@ resource "aws_security_group" "private" {
}
}

resource "aws_key_pair" "key_pair" {
key_name = "${var.project_name}-key-pair"
public_key = file(var.ssh_public_key_path)

tags = {
Project = var.project_name
Name = "${var.project_name}-ssh-key-pair"
}
}

# Update the bastion module configuration
module "bastion" {
source = "../node"
project_name = var.project_name
Expand All @@ -247,8 +257,8 @@ module "bastion" {
}
network_config = {
availability_zone : var.availability_zone,
public_subnet_id : aws_subnet.public.id
private_subnet_id : aws_subnet.private.id
public_subnet_id : local.public_subnet_id
private_subnet_id : local.private_subnet_id
secondary_private_subnet_id : var.secondary_availability_zone != null ? aws_subnet.secondary_private[0].id : null
public_security_group_id : aws_security_group.public.id
private_security_group_id : aws_security_group.private.id
Expand Down
6 changes: 3 additions & 3 deletions tofu/modules/aws/network/outputs.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
output "config" {
value = {
availability_zone : var.availability_zone,
public_subnet_id : aws_subnet.public.id,
private_subnet_id : aws_subnet.private.id,
secondary_private_subnet_id : var.secondary_availability_zone != null ? aws_subnet.secondary_private[0].id : null,
public_subnet_id : local.public_subnet_id,
private_subnet_id : local.private_subnet_id,
secondary_private_subnet_id : var.secondary_availability_zone != null ? local.secondary_private_subnet_id : null,
public_security_group_id : aws_security_group.public.id,
private_security_group_id : aws_security_group.private.id,
ssh_key_name : aws_key_pair.key_pair.key_name,
Expand Down
7 changes: 7 additions & 0 deletions tofu/modules/aws/network/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,10 @@ variable "bastion_host_instance_type" {
description = "EC2 instance type"
default = "t4g.small"
}

# Variables for existing VPC configuration
variable "existing_vpc_name" {
description = "Name of existing VPC to use. If null, a new VPC will be created"
type = string
default = null
}
Loading

0 comments on commit 4844f25

Please sign in to comment.