본문 바로가기

AWS Cloud

[AWS - Terraform] Network Setting (VPC, Subnet, IGW, NGW, Routing table, Security Group)

반응형

* 참조 사항
- 필자는 학습을 목적으로 main.tf에 전체 인프라 구축 코드를 작성하였으며, 이에 대해 각기 설명함
- .tf 파일을 resource 별로 분할할 시, 필자와 코드가 다를 수 있음
- Terraform 기초부터 순차적으로 보길 권장 (1번 게시물의 이해가 매우 중요)

1. Architecture Create : https://isc9511.tistory.com/163

2. Bucket 생성 및 파일 업로드 : https://isc9511.tistory.com/164

3. IAM Role 생성 및 정책 Attachment : https://isc9511.tistory.com/165

 

 

 

* AWS Networking
(이번엔 코드도 길고 Resource 종류도 많다)

1. VPC (Virtual Private Cloud) : 사용자 지정 가상 클라우드 네트워크

2. Subnet : VPC에 할당 되는 IP 주소 범위 영역

3. Internet-GateWay (IGW) : VPC와 인터넷 간 통신이 가능하게 해주는 게이트웨이

4. NAT-GateWay (NGW) : Private Subnet의 인스턴스가 VPC 외부(Public)의 서비스와 연결하는데 사용되는 NAT(네트워크 주소 변환) 게이트웨이
- 단, 외부(Public) 서비스에서 Private Subnet 영역으로 연결할 수 없도록 사용하는 등 보안을 목적으로도 사용

5. Routing Table : AWS Resource 중 트래픽 경로 지정이 필요한 경우 설정
- VPC -> IGW로 전체 트래픽이 전송되어 외부로 트래픽 전달 되도록 Routing Table 설정
- NGW <> Private Subnet간 트래픽을 주고 받을 수 있도록 설정

6. Security Group : 특정 리소스에 한정하여 In/Out 트래픽을 세부적으로 제어할 수 있도록 지원하는 설정 사항

 

 

 

* Code 내용
- 아래는 Three Tier Architecture 설정을 위해 2개의 AZ(가용 영역)과 Public(Web) - Private(App) - Private(DB)로 네트워크 세팅을 위해 사용된 코드

- 코드가 길지만, 순차적으로 보면 이해하는데 어렵지 않을 것

- 단, VPC 생성 시 자동으로 생성이 되는 Default Routing Table과 별도로 Routing Table을 생성하는 Case의 혼동이 있을 수 있어 별도로 정리

########## Network Setting in AWS ##############
  # Network 세팅에 해당하는 부분은 순차적으로 읽으면 구성 사항 이해 가능(Three-Tier 구조이므로 순차적으로 이해 가능)
# VPC 생성
resource "aws_vpc" "three-tier-vpc" {
  cidr_block = "192.168.0.0/16"

  tags = {
    Name = "three-tier-vpc"
  }
}

# Subnet 생성 (6EA)
resource "aws_subnet" "public-subnet-az1" {
    cidr_block = "192.168.10.0/24"
    vpc_id = aws_vpc.three-tier-vpc.id
    availability_zone = "ap-northeast-2a"
    map_public_ip_on_launch = true # 해당 서브넷 선택 인스턴스는 퍼블릭 IP 주소 할당
    tags = {
      Name = "public-subnet-az1"
  }
}

resource "aws_subnet" "private-subnet-az1" {
    cidr_block = "192.168.20.0/24"
    vpc_id = aws_vpc.three-tier-vpc.id
    availability_zone = "ap-northeast-2a"
    tags = {
      Name = "private-subnet-az1"
  }
}

resource "aws_subnet" "private-db-subnet-az1" {
    cidr_block = "192.168.30.0/24"
    vpc_id = aws_vpc.three-tier-vpc.id
    availability_zone = "ap-northeast-2a"
    tags = {
      Name = "private-db-subnet-az1"
  }
}

resource "aws_subnet" "public-subnet-az2" {
    cidr_block = "192.168.40.0/24"
    vpc_id = aws_vpc.three-tier-vpc.id
    availability_zone = "ap-northeast-2c"
    map_public_ip_on_launch = true # 해당 서브넷 선택 인스턴스는 퍼블릭 IP 주소 할당
    tags = {
      Name = "public-subnet-az2"
  }
}

resource "aws_subnet" "private-subnet-az2" {
    cidr_block = "192.168.50.0/24"
    vpc_id = aws_vpc.three-tier-vpc.id
    availability_zone = "ap-northeast-2c"
    tags = {
      Name = "private-subnet-az2"
  }
}

resource "aws_subnet" "private-db-subnet-az2" {
    cidr_block = "192.168.60.0/24"
    vpc_id = aws_vpc.three-tier-vpc.id
    availability_zone = "ap-northeast-2c"
    tags = {
      Name = "private-db-subnet-az2"
  }
}

# Internet Gateway(IGW) 생성
resource "aws_internet_gateway" "three-tier-igw" {
    vpc_id = aws_vpc.three-tier-vpc.id
    tags = {
      Name = "three-tier-igw"
    }
}

# NAT Gateway용 EIP 생성(2ea) - 공인 IP Release에 시간이 2~3분 가량 소요되는 점 참조
resource "aws_eip" "ngw-eip1" {
    vpc = true
}

resource "aws_eip" "ngw-eip2" {
    vpc = true
}

# NAT Gateway 생성(2ea)
resource "aws_nat_gateway" "ngw-az1" {
    allocation_id = aws_eip.ngw-eip1.id
    subnet_id = aws_subnet.public-subnet-az1.id
    tags = {
        Name = "ngw-public-az1"
    }
}

resource "aws_nat_gateway" "ngw-az2" {
    allocation_id = aws_eip.ngw-eip2.id
    subnet_id = aws_subnet.public-subnet-az2.id
    tags = {
        Name = "ngw-public-az2"
    }
}

# IGW로 전체 트래픽이 가도록 Default Routing Table CIDR 수정 및 명시적 서브넷 설정
# Default Routing table ID 획득
locals {
  default_route_table_id = aws_vpc.three-tier-vpc.default_route_table_id
}
# Default Routing table의 Route 설정 추가
resource "aws_route" "default-rt-to-igw" {
  route_table_id = local.default_route_table_id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id = aws_internet_gateway.three-tier-igw.id
}
# 명시적 서브넷 설정
resource "aws_route_table_association" "public-subnet-az1" {
  subnet_id = aws_subnet.public-subnet-az1.id
  route_table_id = local.default_route_table_id
}
# 명시적 서브넷 설정
resource "aws_route_table_association" "public-subnet-az2" {
  subnet_id = aws_subnet.public-subnet-az2.id
  route_table_id = local.default_route_table_id
}

# NGW1 <> Private Subnet AZ1으로 통신 되도록 Routing Table 생성 및 설정
resource "aws_route_table" "private-rt-az1" {
  vpc_id = aws_vpc.three-tier-vpc.id
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_nat_gateway.ngw-az1.id
  }
  tags = {
    Name = "private-rt-az1"
  }
}
# 명시적 서브넷 설정
resource "aws_route_table_association" "private-subnet-az1" {
  subnet_id = aws_subnet.private-subnet-az1.id
  route_table_id = aws_route_table.private-rt-az1.id
}

# NGW2 <> Private Subnet AZ2으로 통신 되도록 Routing Table 생성 및 설정
resource "aws_route_table" "private-rt-az2" {
  vpc_id = aws_vpc.three-tier-vpc.id
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_nat_gateway.ngw-az2.id
  }
  tags = {
    Name = "private-rt-az2"
  }
}
# 명시적 서브넷 설정
resource "aws_route_table_association" "private-subnet-az2" {
  subnet_id = aws_subnet.private-subnet-az2.id
  route_table_id = aws_route_table.private-rt-az2.id
}

# Security Group 생성 (5ea)
# External ALB 보안 그룹 생성
resource "aws_security_group" "external-alb-sg" {
  name = "external-alb-sg"
  description = "Internet facing ALB SG"
  vpc_id = aws_vpc.three-tier-vpc.id

  ingress {
    from_port = 80
    to_port = 80
    protocol = "tcp"
    cidr_blocks = ["별도 ip 주소/32"]
  }

  egress { # 보안 그룹 생성 시, Outbound 허용을 직접 지정해줘야 통신 가능(관리 콘솔은 자동 생성 / 테라폼은 지정 필수)
    from_port = 0
    to_port = 0
    protocol = "-1" # Protocol -1은 전체 프로토콜을 의미
    cidr_blocks = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }

  tags = {
    Name = "external-alb-sg"
  }
}

# Web Tier Instance 보안 그룹 생성
resource "aws_security_group" "web-tier-instance-sg" {
  name = "web-tier-instance-sg"
  description = "web instance sg"
  vpc_id = aws_vpc.three-tier-vpc.id

  ingress {
    from_port = 80
    to_port = 80
    protocol = "tcp"
    cidr_blocks = ["별도 ip 주소/32"]
  }

  ingress {
    from_port = 80
    to_port = 80
    protocol = "tcp"
    security_groups = [aws_security_group.external-alb-sg.id]
    # 처음에 생성한 External ALB SG를 Inbound로 허용하도록 구성
  }

  egress { # 보안 그룹 생성 시, Outbound 허용을 직접 지정해줘야 통신 가능(관리 콘솔은 자동 생성 / 테라폼은 지정 필수)
    from_port = 0
    to_port = 0
    protocol = "-1" # Protocol -1은 전체 프로토콜을 의미
    cidr_blocks = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }

  tags = {
    Name = "web-tier-instance-sg"
  }
}

# Internal ALB 보안 그룹 생성
resource "aws_security_group" "internal-alb-sg" {
  name = "internal-alb-sg"
  description = "Internal ALB Between Web-App"
  vpc_id = aws_vpc.three-tier-vpc.id

  ingress {
    from_port = 80
    to_port = 80
    protocol = "tcp"
    security_groups = [aws_security_group.web-tier-instance-sg.id]
    # web-tier-instance-sg에서 인바운드 되는 트래픽 허용
  }

  egress { # 보안 그룹 생성 시, Outbound 허용을 직접 지정해줘야 통신 가능(관리 콘솔은 자동 생성 / 테라폼은 지정 필수)
    from_port = 0
    to_port = 0
    protocol = "-1" # Protocol -1은 전체 프로토콜을 의미
    cidr_blocks = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }

  tags = {
    Name = "internal-alb-sg"
  }
}

# Private Instance(App Instance) 보안 그룹 생성
resource "aws_security_group" "private-instance-sg" {
  name = "private-instance-sg"
  description = "App tier instance sg"
  vpc_id = aws_vpc.three-tier-vpc.id

  ingress {
    from_port = 4000
    to_port = 4000
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port = 4000
    to_port = 4000
    protocol = "tcp"
    security_groups = [aws_security_group.internal-alb-sg.id]
    # 내부 ALB SG와 전체 주소 허용이 된, 4000TCP 포트로 트래픽 수신 설정
    # 해당 4000번 포트는 ALB LB Target Group Register Port로 설정 사항에 따라 변동 가능
  }

  egress { # 보안 그룹 생성 시, Outbound 허용을 직접 지정해줘야 통신 가능(관리 콘솔은 자동 생성 / 테라폼은 지정 필수)
    from_port = 0
    to_port = 0
    protocol = "-1" # Protocol -1은 전체 프로토콜을 의미
    cidr_blocks = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }

  tags = {
    Name = "private-instance-sg"
  }  
}

# DB 보안 그룹 생성
resource "aws_security_group" "db-sg" {
  name = "db-sg"
  description = "database security group"
  vpc_id = aws_vpc.three-tier-vpc.id

  ingress {
    from_port = 3306
    to_port = 3306
    protocol = "tcp"
    security_groups = [aws_security_group.private-instance-sg.id]
    # 처음에 생성한 External ALB SG를 Inbound로 허용하도록 구성
  }

  egress { # 보안 그룹 생성 시, Outbound 허용을 직접 지정해줘야 통신 가능(관리 콘솔은 자동 생성 / 테라폼은 지정 필수)
    from_port = 0
    to_port = 0
    protocol = "-1" # Protocol -1은 전체 프로토콜을 의미
    cidr_blocks = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }

  tags = {
    Name = "db-sg"
  }
}

 

 

 

* 주의 사항

1. Default Routing Table 생성별도의 Routing Table 생성 코드에 차이가 존재

aws_route (default routing table) / aws_route_table (별도 routing table)

2. 보안 그룹 (Security Group) 생성 시, Terraform에서는 Egress (Outbound)도 반드시 별도 지정 필요
- 보통 AWS Management Console에서 생성 시, 자동으로 0.0.0.0/0 전체 허용으로 생성
- 단, Terraform Code는 이를 직접 지정해줘야함 (이런줄 모르고 통신 안되서 삽질한 이력 존재)

 

 

 

반응형