We are Architect

3. AWS: 테라폼으로 구축하는 3티어 아키텍처 구현(2) 본문

Cloud/AWS

3. AWS: 테라폼으로 구축하는 3티어 아키텍처 구현(2)

the best infra 2024. 11. 19. 17:01

 

* 네트워크: vpc, 서브넷, 인터넷 게이트웨이, 라우팅 테이블 구축 + NAT GW + 보안그룹

- 아키텍처를 구축하기 위해서는 네트워크를 먼저 구축해야 한다. 그래야 리소스들을 배포할 수 있다. 

- 우선은 무식하게 일반적으로 main.tf 파일에 모든 리소스를 작성할 예정이다. 

- 이후에는 차차 모듈화 하여 관리하기 쉽게 만들예정이다. 

- 구축을 하다보니 네트워크 관련 서비스들은 같이 배포하면 좋을 거 같아서 NAT게이트웨이 와 보안그룹 코드까지 작성하였다.  

 

 

* terraform, provider 블록  

- terraform: 은 테라폼 자체의 동작을 설정과 AWS프로바이더를 설정.

- provider: 프로바이더의 설정을 정하는블록 

# 테라폼에서 사용할 프로바이더를 명확히 정의
terraform {
  required_providers {
    aws = {
        source = "hashicorp/aws"

        # 안정적인 버전에서만 프로바이더 작동.
        version = "~>5.0"
    }
  }
}

# 제공자 설정
provider "aws" {
  region = "ap-northeast-2"
}

 

 

* 리소스 배포를 위한 네트워크 배포

- alb, 각종 서버들, Nat게이트웨이 등을 배포하기 위해서는 네트워크 영역과 통신을 하게 도와주는 라우팅 테이블이 필요.

- 10.0.0.0/16 대역대의 VPC를 생성.

- 인터넷 게이트웨이: 퍼블릭 IP를 가진 트래픽을 라우팅하는 게이트웨이. 해당 기능을 통해 외부에서 내부 통신이 가능.

- 서브넷: 대역대 별로 네트워크를 나눠서 보안을 보완 및 트래픽 분산. 프레젠테이션 계층, 애플리케이션 계층, 데이터 계층으로 나눔. 

- 라우팅 테이블 및 연동: 해당 네트워크에서 다른 네트워크와 통신을 하게 도와주는 리소스로 서브넷과 연동해서 사용.

# vpc 생성
  resource "aws_vpc" "vpc" {
    cidr_block = "10.0.0.0/16"
  }

# IGW 생성
resource "aws_internet_gateway" "IGW" {
  vpc_id = aws_vpc.vpc.id

    tags = {
        Name = "IGW"
    } 
}

# 퍼블릭 서브넷1 생성
resource "aws_subnet" "Public-SN1" {
  vpc_id = aws_vpc.vpc.id
  cidr_block = "10.0.1.0/24"
  availability_zone = "ap-northeast-2a"

  tags = {
    Name = "Public-SN1"
  }
}

# 퍼블릭 서브넷2 생성
resource "aws_subnet" "Public-SN2" {
  vpc_id = aws_vpc.vpc.id
  cidr_block = "10.0.2.0/24"
  availability_zone = "ap-northeast-2c"

  tags = {
    Name = "Public-SN2"
  }
}

# 프라이빗 서브넷1 생성
resource "aws_subnet" "Private-SN1" {
  vpc_id = aws_vpc.vpc.id
  cidr_block = "10.0.3.0/24"
  availability_zone = "ap-northeast-2a"

  tags = {
    Name = "Private-SN1"
  }
}

# 프라이빗 서브넷2 생성
resource "aws_subnet" "Private-SN2" {
  vpc_id = aws_vpc.vpc.id
  cidr_block = "10.0.4.0/24"
  availability_zone = "ap-northeast-2c"

  tags = {
    Name = "Private-SN2"
  }
}

# 프라이빗 서브넷3 생성
resource "aws_subnet" "Private-SN3" {
  vpc_id = aws_vpc.vpc.id
  cidr_block = "10.0.5.0/24"
  availability_zone = "ap-northeast-2a"

  tags = {
    Name = "Private-SN3"
  }
}

# 프라이빗 서브넷4 생성
resource "aws_subnet" "Private-SN4" {
  vpc_id = aws_vpc.vpc.id
  cidr_block = "10.0.6.0/24"
  availability_zone = "ap-northeast-2c"

  tags = {
    Name = "Private-SN4"
  }
}

# 프라이빗 서브넷5 생성
resource "aws_subnet" "Private-SN5" {
  vpc_id = aws_vpc.vpc.id
  cidr_block = "10.0.7.0/24"
  availability_zone = "ap-northeast-2a"

  tags = {
    Name = "Private-SN5"
  }
}

# 프라이빗 서브넷6 생성
resource "aws_subnet" "Private-SN6" {
  vpc_id = aws_vpc.vpc.id
  cidr_block = "10.0.8.0/24"
  availability_zone = "ap-northeast-2c"

  tags = {
    Name = "Private-SN6"
  }
}

# PublicRT 생성
resource "aws_route_table" "Public-RT" {
  vpc_id = aws_vpc.vpc.id

  route  {
    cidr_block = "0.0.0.0/0"
      gateway_id = aws_internet_gateway.IGW.id
  }

  tags = {
    Name = "Public-SN"
  }
}

# PubicRT + PublicSN1 
resource "aws_route_table_association" "Public-a" {
  subnet_id = aws_subnet.Public-SN1.id
  route_table_id = aws_route_table.Public-RT.id
}

# PubicRT + PublicSN2 
resource "aws_route_table_association" "Public-c" {
  subnet_id = aws_subnet.Public-SN2.id
  route_table_id = aws_route_table.Public-RT.id
}

# Prviate RT 생성
resource "aws_route_table" "Prviate-RT" {
  vpc_id = aws_vpc.vpc.id

  route {
    cidr_block = "0.0.0.0/0"
      nat_gateway_id = aws_nat_gateway.NatGW.id
  } 

  tags = {
    Name = "Prviate-RT"
  }
}

# PrivateRT + PrivateSN1: Private-web-a
resource "aws_route_table_association" "Private-web-a" {
  subnet_id = aws_subnet.Private-SN1.id
  route_table_id = aws_route_table.Prviate-RT.id
}

# PrivateRT + PrivateSN2: Private-web-c
resource "aws_route_table_association" "Private-web-c" {
  subnet_id = aws_subnet.Private-SN2.id
  route_table_id = aws_route_table.Prviate-RT.id
}

# PrivateRT + PrivateSN3: Private-WAS-a
resource "aws_route_table_association" "Private-WAS-a" {
  subnet_id = aws_subnet.Private-SN3.id
  route_table_id = aws_route_table.Prviate-RT.id
}

# PrivateRT + PrivateSN4: Private-WAS-c
resource "aws_route_table_association" "Private-WAS-c" {
  subnet_id = aws_subnet.Private-SN4.id
  route_table_id = aws_route_table.Prviate-RT.id
}

# PrivateRT + PrivateSN5: Private-DB-a
resource "aws_route_table_association" "Private-DB-a" {
  subnet_id = aws_subnet.Private-SN5.id
  route_table_id = aws_route_table.Prviate-RT.id
}

# PrivateRT + PrivateSN6: Private-DB-c
resource "aws_route_table_association" "Private-DB-c" {
  subnet_id = aws_subnet.Private-SN6.id
  route_table_id = aws_route_table.Prviate-RT.id
}

 

 

* NAT 게이트웨이 설정

- 외부에는 내부로 들어올때 로드밸런서의 DNS주소로 트래픽이 진입하며 internet 게이트웨이로 내부로 들어온다. 

- 내부에서 외부로 통신 할 때는 Nat라는 기능을 가진 리소스가 필요.

- Nat란 Network Address Translation 이라는 기능으로 어떤 IP를 다른 IP로 변환시키는 기능으로 해당 사설 네트워크에 접근하거나 외부로 나가기 위해서 설정하는 기능.  

- 원래 온프래미스에서는 라우터라는 네트워크장비에 해당 기능이 있음.

- AWS에서는 Nat 게이트웨이 라는 리소스가 따로 존재. 외부와 통신해야 하기 때문에 퍼블릭 IP가 필요.

# NatGW 용 EIP
resource "aws_eip" "nat-eip" {
  domain = "vpc"
}

# NatGW 생성
resource "aws_nat_gateway" "NatGW" {
  allocation_id = aws_eip.nat-eip.id
  subnet_id = aws_subnet.Public-SN1.id

  tags = {
    Name = "Nat-GW1"
  }
}

 

 

* 보안 그룹

- 인터넷 트래픽을 규칙에 따라 차단 시키거나 허용 기키는 리소스.

- 방화벽의 역할을 주로 담당하는 리소스. 

- 리소스에 적용 시킬수 있으며 *화이트 리스트 방식으로 작동.  

- 화이트 리스트 방식: 허용하고자 하는 대상만 리스트에 작성시키는 방식.

- 허용 하고자하는 프로토콜, 포트, ip범위 설정가능.

# ALB(internal): 외부에서 들어온 트래픽을 받아서 백엔드 서비스로 전달하기 위해서 설정.
resource "aws_security_group" "alb-sg" {
  name = "alb-sg"
  description = "alb-sg security group for Terraform"
  vpc_id = aws_vpc.vpc.id

  # 인바운드 규칙 (Ingress)
  ingress {
    description = "Allow HTTP traffic"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"] # 모든 IP 허용
  }

  # 아웃바운드 규칙 (Egress)
  egress {
    description = "Allow all outbound traffic"
    from_port   = 0
    to_port     = 0
    protocol    = "-1" # 모든 프로토콜 허용
    cidr_blocks = ["0.0.0.0/0"]
  }

  # 태그 추가
  tags = {
    Name = "Public-ALB-sg"
  }
}

#NLB(external)
resource "aws_security_group" "Private-nlb-sg" {
  name = "Private-nlb-sg"
  description = "nlb-sg security group for Terraform"
  vpc_id = aws_vpc.vpc.id

  # 인바운드 규칙 (Ingress)
  ingress {
    description = "Allow Port 8080 traffic"
    from_port   = 8080
    to_port     = 8080
    protocol    = "tcp"
    security_groups   = [aws_security_group.Web-srv-sg.id] # Web-srv에서의 8080 허용
  }

  # 아웃바운드 규칙 (Egress)
  egress {
    description = "Outbound Traffic from WAS-Srv"
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # 태그 추가
  tags = {
    Name = "Private-NLB-sg"
  }
}

# 웹 서버: 로드벨런서로 부터 들어는 허용된 트래픽만 허용하기 위해서 설정.
resource "aws_security_group" "Web-srv-sg" {
  name = "Web-srv-sg"
  description = "Allow traffic form ALB to Web-srv"
  vpc_id = aws_vpc.vpc.id

  # 인바운드 규칙
  ingress {
    description = "Allow traffic from ALB"
    from_port = 80
    to_port = 80
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

   # Bastion Host에서의 SSH 허용
  ingress {
    from_port         = 22
    to_port           = 22
    protocol          = "tcp"
    security_groups   = [aws_security_group.bastion-srv-sg.id]
  }

  # 아웃 바운드 규칙
  egress {
    description = "Outbound Traffic from Web-Srv"
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# WAS 서버
resource "aws_security_group" "WAS-srv-sg" {
  name = "WAS-srv-sg"
  description = "Allow traffic form ALB to WAS-srv"
  vpc_id = aws_vpc.vpc.id

  # 인바운드 규칙
  ingress {
    description = "Allow traffic from Web-srv"
    from_port = 8080
    to_port = 8080
    protocol = "tcp"
    security_groups   = [aws_security_group.Private-nlb-sg.id] # Private-nlb에서의 8080 허용
  }

  ingress {
    from_port         = 22
    to_port           = 22
    protocol          = "tcp"
    security_groups   = [aws_security_group.bastion-srv-sg.id] # Bastion Host에서의 SSH 허용
  }

  # 아웃 바운드 규칙
  egress {
    description = "Outbound Traffic from WAS-Srv"
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# db서버
resource "aws_security_group" "DB-srv-sg" {
  name = "DB-srv-sg"
  description = "Allow traffic from WAS-srv"
  vpc_id = aws_vpc.vpc.id

  # 인바운드 규칙
  ingress {
    from_port = 3306
    to_port = 3306
    protocol = "tcp"

    # WAS-Srv에서 오는 트래픽 허용.
    security_groups = [aws_security_group.WAS-srv-sg.id]
  }

  ingress {
    from_port         = 22
    to_port           = 22
    protocol          = "tcp"
    security_groups   = [aws_security_group.bastion-srv-sg.id] # Bastion Host에서의 SSH 허용
  }

  # 아웃바운드 규칙 
  egress {
    description = "Outbound Traffic from DB-Srv"
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# 베스천 호스트 서버
resource "aws_security_group" "bastion-srv-sg" {
  name = "bastion-srv-sg"
  description = "Allow traffic from admin"
  vpc_id = aws_vpc.vpc.id

  # 인바운드 규칙
  ingress {
    from_port = 22
    to_port = 22
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # 아웃바운드 규칙 
  egress {
    description = "Outbound Traffic from bastion-Srv"
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}