IaC AWS 아키텍처 구축 - 2

SangYeon Min·2023년 11월 30일
0

STUDY-DevOps

목록 보기
3/7
post-thumbnail

Private APP 리소스 구축

개발 과정을 용이하게 하기 위해서 위와 같이 VPC 하위에 단일 Routing Table을 두어 Internet Gateway로 web, app의 ALB에 접근이 가능하도록 한다.

ALB, ASG 리소스 구축

# 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를 변경하여 메세지를 노출한다.

Trouble Shooting

하지만 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를 통해 생성된 것을 볼 수 있다.


VPC Network 재구축

이전까지는 Public, Private 인스턴스들이 같은 subnet에 위치했던 것과는 달리 각각 라우팅 테이블을 통해 서브넷으로 라우팅하고 IGW의 연결을 끊은 뒤 Private APP ALB에 Web 인스턴스로부터의 요청을 허용하여 위와 같은 아키텍처를 구축한다.

NAT Gateway 구현

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 네트워크가 생성된다.

Private APP ALB 구축

# 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로 통신되는 것을 확인할 수 있다.

0개의 댓글