0
votes

I have created two VPCs using Terraform:

resource "aws_vpc" "alpha" {
  cidr_block = "10.16.0.0/16"

  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "Alpha"
  }
}

resource "aws_subnet" "alpha_private_a" {
  vpc_id     = aws_vpc.alpha.id
  cidr_block = "10.16.192.0/24"

  availability_zone = "${var.aws_region}a"

  tags = {
    Name = "Alpha Private A"
  }
}

resource "aws_subnet" "alpha_private_b" {
  vpc_id     = aws_vpc.alpha.id
  cidr_block = "10.16.224.0/24"

  availability_zone = "${var.aws_region}b"

  tags = {
    Name = "Alpha Private B"
  }
}

resource "aws_route_table" "alpha_private" {
  vpc_id = aws_vpc.alpha.id

  tags = {
    Name = "Alpha Private"
  }
}

resource "aws_route_table_association" "alpha_private_a" {
  route_table_id = aws_route_table.alpha_private.id
  subnet_id      = aws_subnet.alpha_private_a.id
}

resource "aws_route_table_association" "alpha_private_b" {
  route_table_id = aws_route_table.alpha_private.id
  subnet_id      = aws_subnet.alpha_private_b.id
}

# The same again for VPC "Bravo"

I also have an RDS in VPC "Alpha":

resource "aws_db_subnet_group" "alpha_rds" {
  subnet_ids = [ aws_subnet.alpha_private_a.id, aws_subnet.alpha_private_b.id ]

  tags = {
    Name = "Alpha RDS"
  }
}

resource "aws_db_instance" "alpha" {
  identifier            = "alpha"
  allocated_storage     = 20
  max_allocated_storage = 1000
  storage_type          = "gp2"
  engine                = "postgres"
  engine_version        = "11.8"
  publicly_accessible   = false
  db_subnet_group_name  = aws_db_subnet_group.alpha_rds.name

  performance_insights_enabled = true
  vpc_security_group_ids       = [ aws_security_group.alpha_rds.id ]

  lifecycle {
    prevent_destroy = true
  }
}

Then I have an Elastic Beanstalk instance inside VPC "Bravo".

What I want to achieve:

  • alpha_rds is accessible to my Elastic Beanstalk instance inside Bravo VPC
  • Nothing else inside Alpha VPC is accessible to Bravo VPC
  • Nothing else inside Bravo VPC is accessible to Alpha VPC

I think VPC Peering is required for this?

How can I implement this in Terraform?


Related but not Terraform:

1

1 Answers

2
votes

You should be able to set it up like this:

  1. Create a VPC Peering Connection between Alpha and Bravo
  2. In the Route table for Alpha add a route for the CIDR range of Bravo and set the destination to the peering connection (pcx-XXXXXX) to Bravo
  3. In the Route table for Bravo add a route for the IP-address(es) of the Database and point it to the peering connection to Alpha

This setup guarantees, that resources in Bravo can only communicate to the Database in Alpha, every other packet to that VPC can't be routed.

The inverse is a little tougher - right now this setup should stop TCP connections from Alpha to Bravo being established, because there is no return path except for the database. UDP traffic could still go through, it's response will be dropped though, unless it comes from the database.

At this point you could set up Network Access Control lists in the Subnets in Bravo to Deny traffic from Alpha except for the database IPs. This depends on your level of paranoia or your requirements in terms of isolation - personally I wouldn't do it, but it's Friday afternoon and I'm in a lazy mood ;-).


Update

As Mark B correctly pointed out in the comments there is a risk, that the private IP addresses of your RDS cluster may change on failover if the underlying host can't be recovered.

To address these concerns, you could create separate subnets in Alpha for your database node(s) and substitute the database IPs in my description above with the CIDRs of these subnets. That should allow for slightly more flexibility and allows you to get around the NACL problem as well, because you can just edit the routing table of the new database subnet(s) and only add the Peering Connection there.