개발 과정을 용이하게 하기 위해서 위와 같이 VPC 하위에 단일 Routing Table을 두어 Internet Gateway로 web, app의 ALB에 접근이 가능하도록 한다.
# Use AWS Provider
provider "aws" {
region = "ap-northeast-2"
}
############ Gateway ##############
# Internet gateway
resource "aws_internet_gateway" "goorm_internet_gw" {
vpc_id = aws_vpc.goorm_vpc.id
tags = {
Name = "goorm_internet_gw"
}
}
# Route table
resource "aws_route_table" "goorm_route_table" {
vpc_id = aws_vpc.goorm_vpc.id
tags = {
Name = "goorm_route_table"
}
}
# Route
resource "aws_route" "goorm_route" {
route_table_id = aws_route_table.goorm_route_table.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.goorm_internet_gw.id
}
resource "aws_route_table_association" "goorm_rtb_sub_a_aasosiation" {
subnet_id = aws_subnet.goorm_subnet_a.id
route_table_id = aws_route_table.goorm_route_table.id
}
# Route table association
resource "aws_route_table_association" "goorm_rtb_sub_c_aasosiation" {
subnet_id = aws_subnet.goorm_subnet_c.id
route_table_id = aws_route_table.goorm_route_table.id
}
############# VPC ###############
# VPC resource
resource "aws_vpc" "goorm_vpc" {
cidr_block = "172.16.0.0/16"
tags = {
Name = "goorm_vpc"
}
}
# Subnet-a resource
resource "aws_subnet" "goorm_subnet_a" {
vpc_id = aws_vpc.goorm_vpc.id
cidr_block = "172.16.0.0/24"
availability_zone = "ap-northeast-2a"
map_public_ip_on_launch = true
tags = {
Name = "goorm_subnet_a"
}
}
# Subnet-c resource
resource "aws_subnet" "goorm_subnet_c" {
vpc_id = aws_vpc.goorm_vpc.id
cidr_block = "172.16.10.0/24"
availability_zone = "ap-northeast-2c"
map_public_ip_on_launch = true
tags = {
Name = "goorm_subnet_c"
}
}
web 리소스들까지 terraform apply
로 인한 생성을 방지하기 위해 위와 같이 /network.tf
파일을 분리하며 app 리소스를 따로 생성하도록 구조화한다.
+---app-res
| app-alb-asg.tf
| network.tf
|
+---main-res
| main.tf
| network.tf
|
+---web-res
web-alb-asg.tf
web-ec2.tf
현재는 테스트를 용이하게 하기 위해 public sg와 동일하게 sg를 설정하고 ALB, ASG 모두 public web과 동일하게 구성한다.
resource "aws_launch_configuration" "goorm-app-launch-config" {
name = "goorm-app-launchconfig"
image_id = "ami-01123b84e2a4fba05"
instance_type = "t2.micro"
security_groups = [aws_security_group.app_server_sg.id]
user_data = <<-EOF
#! /bin/bash
sudo yum update
sudo yum install nginx -y
sudo su
cd /usr/share/nginx/html/
sudo rm index.html
echo "<h1>Hello, World! You are now in private app<h1/>" > index.html
cd ~
sudo service nginx start
sudo chkconfig nginx on
sudo service nginx status
EOF
lifecycle {
create_before_destroy = true
}
}
하지만 각 ALB의 구분을 위해 app은 nginx index를 변경하여 메세지를 노출한다.
하지만 terraform이 다른 폴더에서 VPC를 생성하면 분리되는 문제가 발생
+---GOORM_ASSIGN
| | app-alb-asg.tf
| | main.tf
| | network.tf
| | web-alb-asg.tf
| | web-ec2.tf
위와 같이 구조를 재정립한 이후 모든 리소스를 수동으로 제거하고 리소스 재생성
또한 Terraform은 멱등성을 보장하여 apply
할 때 수정된 사항만 add 한다.
따라서 VPC 등 네트워크 리소스를 분리할 필요가 없다.
ALB, ASG 모두 정상적으로 생성된 것을 확인한 이후 현재는 private하지 않은 APP ALB에 접근하여 정상적으로 app instance가 ASG를 통해 생성된 것을 볼 수 있다.
이전까지는 Public, Private 인스턴스들이 같은 subnet에 위치했던 것과는 달리 각각 라우팅 테이블을 통해 서브넷으로 라우팅하고 IGW의 연결을 끊은 뒤 Private APP ALB에 Web 인스턴스로부터의 요청을 허용하여 위와 같은 아키텍처를 구축한다.
https://docs.aws.amazon.com
NAT 게이트웨이는 NAT(네트워크 주소 변환) 서비스입니다. 프라이빗 서브넷의 인스턴스가 VPC 외부의 서비스에 연결할 수 있지만 외부 서비스에서 이러한 인스턴스와의 연결을 시작할 수 없도록 NAT 게이트웨이를 사용할 수 있습니다.
# Private-Subnet-a resource
resource "aws_subnet" "goorm_private_subnet_a" {
vpc_id = aws_vpc.goorm_vpc.id
cidr_block = "172.16.20.0/24"
availability_zone = "ap-northeast-2a"
map_public_ip_on_launch = true
tags = {
Name = "goorm_private_subnet_a"
}
}
# Private-Subnet-c resource
resource "aws_subnet" "goorm_private_subnet_c" {
vpc_id = aws_vpc.goorm_vpc.id
cidr_block = "172.16.30.0/24"
availability_zone = "ap-northeast-2c"
map_public_ip_on_launch = true
tags = {
Name = "goorm_private_subnet_c"
}
}
NAT Gateway를 구축하기 위해서 private 서브넷을 별도로 할당한다.
이때 availability_zone
을 통해 각 서브넷을 분리한다.
########### Network gateway ###########
# Network Gateway for public web subnet
resource "aws_eip" "goorm-ngw-eip-a" {
vpc = true
}
resource "aws_eip" "goorm-ngw-eip-c" {
vpc = true
}
# NAT Gateway
resource "aws_nat_gateway" "goorm-ngw-a" {
allocation_id = aws_eip.goorm-ngw-eip-a.id
subnet_id = aws_subnet.goorm_subnet_a.id
tags = {
Name = "goorm-ngw-a"
}
}
resource "aws_nat_gateway" "goorm-ngw-c" {
allocation_id = aws_eip.goorm-ngw-eip-c.id
subnet_id = aws_subnet.goorm_subnet_c.id
tags = {
Name = "goorm-ngw-c"
}
}
이후 각 NGW에 대한 EIP를 할당하고 NGW 별로 private subnet을 할당한다.
# NGW-a to Private Subnet Route Table
resource "aws_route_table" "goorm_private_route_table_a" {
vpc_id = aws_vpc.goorm_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_nat_gateway.goorm-ngw-a.id
}
tags = {
Name = "goorm_private_route_table_a"
}
}
resource "aws_route_table_association" "goorm_rtb_private_sub_a_asoc" {
subnet_id = aws_subnet.goorm_private_subnet_a.id
route_table_id = aws_route_table.goorm_private_route_table_a.id
}
# NGW-c to Private Subnet Route Table
resource "aws_route_table" "goorm_private_route_table_c" {
vpc_id = aws_vpc.goorm_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_nat_gateway.goorm-ngw-c.id
}
tags = {
Name = "goorm_private_route_table_c"
}
}
resource "aws_route_table_association" "goorm_rtb_private_sub_c_asoc" {
subnet_id = aws_subnet.goorm_private_subnet_c.id
route_table_id = aws_route_table.goorm_private_route_table_c.id
}
이후 각 NGW들에 대한 Route Table을 생성하고 route를 통해 포워딩을 해준 이후 명시적 subnet을 지정해주면 VPC 네트워크가 생성된다.
# Application Load Balancer SG
resource "aws_security_group" "goorm_app_alb_security_group" {
name = "goorm_app_alb_security_group"
description = "ALB Security Group"
vpc_id = aws_vpc.goorm_vpc.id
ingress {
description = "HTTP from Web Instance"
from_port = 80
to_port = 80
protocol = "tcp"
# cidr_blocks = ["0.0.0.0/0"]
security_groups = [aws_security_group.web_server_sg.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "goorm_app_alb_security_group"
}
}
Private ALB은 web instance, web_server_sg
로만 http 요청을 받도록 설정하고
############ App Instance SG ##############
resource "aws_security_group" "app_server_sg" {
name = "app_server_sg"
description = "allow 22, 80"
vpc_id = aws_vpc.goorm_vpc.id
# ingress {
# from_port = 80
# to_port = 80
# protocol = "tcp"
# cidr_blocks = ["0.0.0.0/0"]
# }
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
security_groups = [aws_security_group.goorm_app_alb_security_group.id]
}
}
resource "aws_security_group_rule" "appsg_ssh" {
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.app_server_sg.id
description = "ssh"
}
resource "aws_security_group_rule" "appsg_outbound" {
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.app_server_sg.id
description = "outbound"
}
Private APP은 Private ALB로만 요청을 받도록 설정한다.
이때 테스트를 용이하게 하기 위해 SSH 접속은 일시적으로 허용한다.
이후 web ec2 인스턴스에서 app ALB로 통신되는 것을 확인할 수 있다.