메인 콘텐츠로 이동하기
  1. Posts/

NAT instance란?

·422 자
Aws

서론 #

해당 블로그 Bastion Host글에 따르면, 이제 우리는 public/private 서브넷 각각을 구성할 수 있으며 Bastion Host를 사용하여 개인 인스턴스에 접근할 수 있습니다. 그러나 private 인스턴스에서 라이브러리나 패키지등을 다운로드하려고 할 때, public internet에서 접근할 수 있어야합니다. 그래서 public 서브넷에 NAT 게이트웨이를 생성하여 인터넷 게이트웨이와 통신할 수 있도록 하고, private 인스턴스가 NAT 게이트웨이를 통해 public internet에 접근할 수 있게 합니다.

NAT 게이트웨이 #

resource "aws_eip" "default_nat_gateway_static_ip" {
  vpc = true
  lifecycle {
    create_before_destroy = true
  }
}
resource "aws_nat_gateway" "default_nat_gateway" {
  allocation_id = aws_eip.default_nat_gateway_static_ip.id
  subnet_id = aws_subnet.public_subnet.id
  tags = {
    Name = "NAT-Gateway"
  }
}

# add nat_gateway to private_route_table
resource "aws_route" "nat_gateway_association" {
  route_table_id = aws_route_table.private_route_table.id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id = aws_nat_gateway.default_nat_gateway.id
}

NAT 인스턴스 #

igw

AWS는 간단하고 자동으로 확장 가능한 NAT 게이트웨이 서비스를 제공합니다. 하지만 NAT 게이트웨이의 월간 비용은 개인이 사용하기에 상당한 부담이 될 수 있습니다. 그래서 NAT 게이트웨이 대신 NAT 인스턴스를 생성하는 것도 가능합니다 (AWS 공식문서에 따르면, NAT 인스턴스보다는 NAT 게이트웨이를 추천합니다).

resource "aws_security_group" "nat_instance_security_group" {
  name       = "nat_instance_security_group"
  description = "Allow all traffic"
  vpc_id      = aws_vpc.default_vpc.id

  ingress {
    description = "Allow SSH"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    description = "Allow HTTP in private subnet"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = [aws_subnet.private_subnet.cidr_block]
  }
  ingress {
    description = "Allow HTTPS in private subnet"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = [aws_subnet.private_subnet.cidr_block]
  }
  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"]
  }
}

resource "aws_instance" "nat_instance" {
  # NAT 인스턴스용 Linux AMI
  ami = "ami-0abd4c49376ea5dbb"
  instance_type = "t2.micro"
  key_name      = aws_key_pair.vpn_key.key_name
  network_interface {
    device_index = 0
    network_interface_id = aws_network_interface.nat_instance_network_interface.id
  }
  tags = {
    Name = "nat_instance"
  }
}
resource "aws_network_interface" "nat_instance_network_interface" {
  subnet_id = aws_subnet.public_subnet.id
  security_groups = [aws_security_group.nat_instance_security_group.id]
  # 인스턴스를 NAT 인스턴스로 설정하기 위해 false로 설정 필요
  source_dest_check = false
  tags = {
    Name = "nat_instance_network_interface"
  }
}

# NAT 인스턴스에 대한 elastic IP 할당
resource "aws_eip" "nat_instance_static_ip" {
  instance = aws_instance.nat_instance.id
  network_interface = aws_network_interface.nat_instance_network_interface.id
  vpc = true
}

NAT 인스턴스를 설정하기 위해서는 여러 설정이 필요하지만, NAT 인스턴스 전용 AMI(Amazon Machine Image)를 사용하면 이러한 단계들을 건너뛸 수 있습니다. 또한 인스턴스의 source_dest_check는 false여야 합니다. source/dst 검사는 트래픽의 소스 또는 목적지가 인스턴스 자체여야 함을 보장합니다. 그러나 NAT 인스턴스는 source 혹은 destination이 자신이 아닌 경우에도 트래픽을 보내고 받을 수 있어야 합니다.

마지막으로, NAT 인스턴스의 ENI(Elastic Network Interface)를 private_route_table에 추가합니다.

resource "aws_route" "nat_instance_association" {
  route_table_id = aws_route_table.private_route_table.id
  destination_cidr_block = "0.0.0.0/0"
  network_interface_id =
	  aws_network_interface.nat_instance_network_interface.id
  # instance_id = aws_instance.nat_instance.id
}