Как маршрутизировать между двумя подсетями в AWS VPC w / Terraform?
обновление: Работал над этим и над другими вещами. Не удается получить рабочую конфигурацию с двумя подсетями и бастионом SSH. Размещение баунти для полного .TF файл конфигурации, что: * создает две частные подсети * создает Бастион * запускает экземпляр ec2 в каждой подсети, настроенной через Бастион (выполните произвольную команду оболочки через Бастион) * настроен интернет-шлюз * имеет шлюз nat для хостов в частных подсетях * сконфигурированы маршруты и группы безопасности соответственно
Оригинал поста: Я пытаюсь изучить Terraform и построить прототип. У меня есть AWS VPC, настроенный через Terraform. В дополнение к подсети DMZ у меня есть общедоступная подсеть "web", которая получает трафик из интернета. У меня есть частное приложение подсети, которое недоступно из интернета. Я пытаюсь настроить хост бастиона, чтобы terraform мог предоставлять экземпляры в частной подсети "app". Я еще не смог заставить это работать.
когда я ssh в бастионе я не могу SSH от хоста бастиона к любым экземплярам в частной подсети. Я подозреваю, что есть проблема маршрутизации. Я строил этот прототип с помощью нескольких доступных примеров и документации. Во многих примерах используются несколько иные методы и определения маршрутизации terraform через провайдера aws.
может ли кто-нибудь предоставить идеальный или правильный способ определить эти три подсети (публичный "веб", публичный " dmz "с бастионом и частное "приложение"), поэтому что экземпляры в подсети " web "могут получить доступ к подсети" app "и что узел бастиона в DMZ может предоставлять экземпляры в частной подсети "app"?
СНиП моих конфигураций ниже:
resource "aws_subnet" "dmz" {
vpc_id = "${aws_vpc.vpc-poc.id}"
cidr_block = "${var.cidr_block_dmz}"
}
resource "aws_route_table" "dmz" {
vpc_id = "${aws_vpc.vpc-poc.id}"
route {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.gateway.id}"
}
}
resource "aws_route_table_association" "dmz" {
subnet_id = "${aws_subnet.dmz.id}"
route_table_id = "${aws_route_table.dmz.id}"
}
resource "aws_subnet" "web" {
vpc_id = "${aws_vpc.vpc-poc.id}"
cidr_block = "10.200.2.0/24"
}
resource "aws_route_table" "web" {
vpc_id = "${aws_vpc.vpc-poc.id}"
route {
cidr_block = "0.0.0.0/0"
instance_id = "${aws_instance.bastion.id}"
}
}
resource "aws_route_table_association" "web" {
subnet_id = "${aws_subnet.web.id}"
route_table_id = "${aws_route_table.web.id}"
}
resource "aws_subnet" "app" {
vpc_id = "${aws_vpc.vpc-poc.id}"
cidr_block = "10.200.3.0/24"
}
resource "aws_route_table" "app" {
vpc_id = "${aws_vpc.vpc-poc.id}"
route {
cidr_block = "0.0.0.0/0"
instance_id = "${aws_instance.bastion.id}"
}
}
resource "aws_route_table_association" "app" {
subnet_id = "${aws_subnet.app.id}"
route_table_id = "${aws_route_table.app.id}"
}
5 ответов
вот фрагмент, который может помочь вам. Это было непроверено, но было извлечено из одного из моих файлов terraform, где я предоставляю VMs в частной подсети. Я знаю, что это работает с одной частной подсетью, я попытался реализовать два здесь, как ваш первоначальный вопрос.
Я прыгаю через мои экземпляры NAT, чтобы ударить и обеспечить частные подсети с помощью Terraform. Если ваши группы безопасности настроены правильно, это работает. Мне потребовались некоторые эксперименты.
/* VPC creation */
resource "aws_vpc" "vpc_poc" {
cidr_block = "10.200.0.0/16"
}
/* Internet gateway for the public subnets */
resource "aws_internet_gateway" "gateway" {
vpc_id = "${aws_vpc.vpc_poc.id}"
}
/* DMZ subnet - public */
resource "aws_subnet" "dmz" {
vpc_id = "${aws_vpc.vpc_poc.id}"
cidr_block = "10.200.1.0/24"
/* may help to be explicit here */
map_public_ip_on_launch = true
/* this is recommended in the docs */
depends_on = ["aws_internet_gateway.gateway"]
}
resource "aws_route_table" "dmz" {
vpc_id = "${aws_vpc.vpc_poc.id}"
route {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.gateway.id}"
}
}
resource "aws_route_table_association" "dmz" {
subnet_id = "${aws_subnet.dmz.id}"
route_table_id = "${aws_route_table.dmz.id}"
}
/* Web subnet - public */
resource "aws_subnet" "web" {
vpc_id = "${aws_vpc.vpc_poc.id}"
cidr_block = "10.200.2.0/24"
map_public_ip_on_launch = true
depends_on = ["aws_internet_gateway.gateway"]
}
resource "aws_route_table" "web" {
vpc_id = "${aws_vpc.vpc_poc.id}"
route {
cidr_block = "0.0.0.0/0"
/* your public web subnet needs access to the gateway */
/* this was set to bastion before so you had a circular arg */
gateway_id = "${aws_internet_gateway.gateway.id}"
}
}
resource "aws_route_table_association" "web" {
subnet_id = "${aws_subnet.web.id}"
route_table_id = "${aws_route_table.web.id}"
}
/* App subnet - private */
resource "aws_subnet" "app" {
vpc_id = "${aws_vpc.vpc_poc.id}"
cidr_block = "10.200.3.0/24"
}
/* Create route for DMZ Bastion */
resource "aws_route_table" "app" {
vpc_id = "${aws_vpc.vpc_poc.id}"
route {
cidr_block = "0.0.0.0/0"
/* this send traffic to the bastion to pass off */
instance_id = "${aws_instance.nat_dmz.id}"
}
}
/* Create route for App Bastion */
resource "aws_route_table" "app" {
vpc_id = "${aws_vpc.vpc_poc.id}"
route {
cidr_block = "0.0.0.0/0"
/* this send traffic to the bastion to pass off */
instance_id = "${aws_instance.nat_web.id}"
}
}
resource "aws_route_table_association" "app" {
subnet_id = "${aws_subnet.app.id}"
route_table_id = "${aws_route_table.app.id}"
}
/* Default security group */
resource "aws_security_group" "default" {
name = "default-sg"
description = "Default security group that allows inbound and outbound traffic from all instances in the VPC"
vpc_id = "${aws_vpc.vpc_poc.id}"
ingress {
from_port = "0"
to_port = "0"
protocol = "-1"
self = true
}
egress {
from_port = "0"
to_port = "0"
protocol = "-1"
self = true
}
}
/* Security group for the nat server */
resource "aws_security_group" "nat" {
name = "nat-sg"
description = "Security group for nat instances that allows SSH and VPN traffic from internet. Also allows outbound HTTP[S]"
vpc_id = "${aws_vpc.vpc_poc.id}"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
/* this your private subnet cidr */
cidr_blocks = ["10.200.3.0/24"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
/* this is your private subnet cidr */
cidr_blocks = ["10.200.3.0/24"]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = -1
to_port = -1
protocol = "icmp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 22
to_port = 22
protocol = "tcp"
/* this is the vpc cidr block */
cidr_blocks = ["10.200.0.0/16"]
}
egress {
from_port = -1
to_port = -1
protocol = "icmp"
cidr_blocks = ["0.0.0.0/0"]
}
}
/* Security group for the web */
resource "aws_security_group" "web" {
name = "web-sg"
description = "Security group for web that allows web traffic from internet"
vpc_id = "${aws_vpc.vpc_poc.id}"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
/* Install deploy key for use with all of our provisioners */
resource "aws_key_pair" "deployer" {
key_name = "deployer-key"
public_key = "${file("~/.ssh/id_rsa")}"
}
/* Setup NAT in DMZ subnet */
resource "aws_instance" "nat_dmz" {
ami = "ami-67a54423"
availability_zone = "us-west-1a"
instance_type = "m1.small"
key_name = "${aws_key_pair.deployer.id}"
/* Notice we are assigning the security group here */
security_groups = ["${aws_security_group.nat.id}"]
/* this puts the instance in your public subnet, but translate to the private one */
subnet_id = "${aws_subnet.dmz.id}"
/* this is really important for nat instance */
source_dest_check = false
associate_public_ip_address = true
}
/* Give NAT EIP In DMZ */
resource "aws_eip" "nat_dmz" {
instance = "${aws_instance.nat_dmz.id}"
vpc = true
}
/* Setup NAT in Web subnet */
resource "aws_instance" "nat_web" {
ami = "ami-67a54423"
availability_zone = "us-west-1a"
instance_type = "m1.small"
key_name = "${aws_key_pair.deployer.id}"
/* Notice we are assigning the security group here */
security_groups = ["${aws_security_group.nat.id}"]
/* this puts the instance in your public subnet, but translate to the private one */
subnet_id = "${aws_subnet.web.id}"
/* this is really important for nat instance */
source_dest_check = false
associate_public_ip_address = true
}
/* Give NAT EIP In DMZ */
resource "aws_eip" "nat_web" {
instance = "${aws_instance.nat_web.id}"
vpc = true
}
/* Install server in private subnet and jump host to it with terraform */
resource "aws_instance" "private_box" {
ami = "ami-d1315fb1"
instance_type = "t2.large"
key_name = "${aws_key_pair.deployer.id}"
subnet_id = "${aws_subnet.api.id}"
associate_public_ip_address = false
/* this is what gives the box access to talk to the nat */
security_groups = ["${aws_security_group.nat.id}"]
connection {
/* connect through the nat instance to reach this box */
bastion_host = "${aws_eip.nat_dmz.public_ip}"
bastion_user = "ec2-user"
bastion_private_key = "${file("keys/terraform_rsa")}"
/* connect to box here */
user = "ec2-user"
host = "${self.private_ip}"
private_key = "${file("~/.ssh/id_rsa")}"
}
}
Если этот хост бастиона также не действует как NAT (я бы не советовал вам объединять роли в одном экземпляре), то подсети web и app не будут иметь исходящего веб-доступа, но в противном случае это выглядит прекрасной маршрутизацией, поскольку TF автоматически добавит локальную запись маршрутизации для VPC.
пока у вас есть эта локальная запись маршрутизации, которая покрывает ваш диапазон VPC, маршрутизация должна быть в порядке. Возьмите файл конфигурации Terraform (и добавьте необходимый минимум ресурсы) позволяет мне создавать некоторые базовые экземпляры во всех 3 подсетях и успешно маршрутизировать между ними, поэтому вы, вероятно, пропустите что-то еще, например группы безопасности или NACLs.
вы не дали свой полный Terraform, но вам нужно будет разрешить SSH в ваши экземпляры VPC "app" с IP-адреса бастиона или блока CIDR вашего хоста бастиона, поэтому что - то вроде этого:
resource "aws_security_group" "allow_ssh" {
name = "allow_ssh"
description = "Allow inbound SSH traffic"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["${aws_instance.bastion.private_ip}/32"]
}
}
затем в ресурсах экземпляра "приложения" вы захотите добавить группу безопасности:
...
vpc_security_group_ids = ["${aws_security_group.allow_ssh.id}"]
...
https://www.terraform.io/docs/providers/aws/r/security_group_rule.html
вы должны проверить сетевые проблемы с tcpdump и другими инструментами отладки. Пожалуйста, проверьте это:
- ИПС reacheble и настройки сети правильные (например, 10.200.2.X может достигать ip хоста бастиона)
- что iptables/другой брандмауэр не блокирует ваш трафик
- сервер ssh слушает (ssh к ip этих хостов от этих хостов)
- у вас есть правильные группы безопасности для хостов (вы можете увидеть это в выступах EC2 экземпляры)
- попробуйте понюхать трафик с tcpdump
Я не вижу причин для хоста бастиона.
у меня есть что-то подобное с помощью saltstack, я просто контролирую остальные, используя главный сервер внутри VPC, назначаю ему определенную группу безопасности, чтобы разрешить доступ.
CIDR X/24
subnetX.0/26- subnet for control server. <aster server ip EC2-subnet1/32
subnetX.64/26 - private minions
subentX.128/26 - public minions
subnetX.192/26- private minions
затем создайте одну таблицу маршрутов для каждой подсети для вашей любви к изоляции Присоедините каждый маршрут к отдельной подсети. Е. Г.
rt-1 - subnetX.0/26
rt-2 - subnetX.64/26
rt-3 - subnetX.128/26
rt-4 - subnetX.192/26
убедитесь, что в таблице маршрутов есть что-то подобное, поэтому маршрут возможен для подключения экземпляра rt-1 для всех
destination: CIDR X/24 Target: local
затем ограничьте подключение через входящую группу безопасности.например. разрешить SSH из EC2-subnet1 / 32
как только я сделаю всю работу с сервером управления, я могу удалить конкретный маршрут, который говорит cidr x/24 Target: local в моей общедоступной подсети, поэтому он больше не может маршрутизировать трафик на мой локальный CIDR.
У меня нет причин создавать сложный Бастион, так как я уже дал возможность удалить маршрут в элементе управления сервер.