diff --git a/apps/infra/production/network/README.md b/apps/infra/production/network/README.md
index 52f40a990b..d8b2e30e26 100644
--- a/apps/infra/production/network/README.md
+++ b/apps/infra/production/network/README.md
@@ -1,3 +1,79 @@
# Network
Project for Network
+
+코드당 인프라의 네트워크의 설정을 담은 프로젝트로 route53, cloudfront, subnet, nat 등을 관리합니다.
+public network의 경우에는 본 프로젝트에서 관리하고, private network의 경우에는 각 리소스를 사용하는 서비스(프로젝트)에서 생성 및 사용하고, 본 프로젝트에서는 route table만 관리합니다.
+
+
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [aws](#requirement\_aws) | ~> 5.52 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | 5.52.0 |
+| [aws.us-east-1](#provider\_aws.us-east-1) | 5.52.0 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_acm_certificate.codedang](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate) | resource |
+| [aws_acm_certificate_validation.for_all_domains](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate_validation) | resource |
+| [aws_cloudfront_distribution.codedang](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_distribution) | resource |
+| [aws_eip.for_nat](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource |
+| [aws_internet_gateway.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/internet_gateway) | resource |
+| [aws_nat_gateway.public_subnet1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway) | resource |
+| [aws_route53_record.certificate](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |
+| [aws_route53_record.codedang](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |
+| [aws_route53_zone.codedang](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_zone) | resource |
+| [aws_route_table.private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource |
+| [aws_route_table.public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource |
+| [aws_route_table_association.admin_api1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource |
+| [aws_route_table_association.admin_api2](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource |
+| [aws_route_table_association.client_api1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource |
+| [aws_route_table_association.client_api2](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource |
+| [aws_route_table_association.iris1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource |
+| [aws_route_table_association.iris2](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource |
+| [aws_route_table_association.public_subnet1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource |
+| [aws_route_table_association.public_subnet2](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource |
+| [aws_subnet.public_subnet1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource |
+| [aws_subnet.public_subnet2](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource |
+| [aws_vpc.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) | resource |
+| [aws_cloudfront_cache_policy.disable](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/cloudfront_cache_policy) | data source |
+| [aws_cloudfront_origin_request_policy.allow_all](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/cloudfront_origin_request_policy) | data source |
+| [aws_cloudfront_origin_request_policy.exclude_host_header](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/cloudfront_origin_request_policy) | data source |
+| [aws_lb.admin_api](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source |
+| [aws_lb.client_api](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source |
+| [aws_subnet.private_admin_api1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet) | data source |
+| [aws_subnet.private_admin_api2](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet) | data source |
+| [aws_subnet.private_client_api1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet) | data source |
+| [aws_subnet.private_client_api2](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet) | data source |
+| [aws_subnet.private_iris1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet) | data source |
+| [aws_subnet.private_iris2](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [private\_admin\_api1\_id](#input\_private\_admin\_api1\_id) | n/a | `any` | n/a | yes |
+| [private\_admin\_api2\_id](#input\_private\_admin\_api2\_id) | n/a | `any` | n/a | yes |
+| [private\_client\_api1\_id](#input\_private\_client\_api1\_id) | n/a | `any` | n/a | yes |
+| [private\_client\_api2\_id](#input\_private\_client\_api2\_id) | n/a | `any` | n/a | yes |
+| [private\_iris1\_id](#input\_private\_iris1\_id) | n/a | `any` | n/a | yes |
+| [private\_iris2\_id](#input\_private\_iris2\_id) | n/a | `any` | n/a | yes |
+
+## Outputs
+
+No outputs.
+
diff --git a/apps/infra/production/network/cloudfront.tf b/apps/infra/production/network/cloudfront.tf
new file mode 100644
index 0000000000..37951c2b3a
--- /dev/null
+++ b/apps/infra/production/network/cloudfront.tf
@@ -0,0 +1,104 @@
+data "aws_lb" "client_api" {
+ name = "Codedang-Client-Api-LB"
+}
+
+data "aws_lb" "admin_api" {
+ name = "Codedang-Admin-Api-LB"
+}
+
+data "aws_cloudfront_cache_policy" "disable" {
+ name = "Managed-CachingDisabled"
+}
+
+data "aws_cloudfront_origin_request_policy" "allow_all" {
+ name = "Managed-AllViewer"
+}
+
+data "aws_cloudfront_origin_request_policy" "exclude_host_header" {
+ name = "Managed-AllViewerExceptHostHeader"
+}
+
+resource "aws_cloudfront_distribution" "codedang" {
+ origin {
+ domain_name = "amplify.codedang.com"
+ origin_id = "frontend" # TODO: Add unique ID of Amplify
+
+ custom_origin_config {
+ http_port = 80
+ https_port = 443
+ origin_protocol_policy = "https-only"
+ origin_ssl_protocols = ["TLSv1.2"]
+ }
+ }
+
+ origin {
+ domain_name = data.aws_lb.client_api.dns_name
+ origin_id = data.aws_lb.client_api.id
+
+ custom_origin_config {
+ http_port = 80
+ https_port = 443
+ origin_protocol_policy = "http-only" # TODO: allow HTTPS only
+ origin_ssl_protocols = ["TLSv1.2"]
+ }
+ }
+
+ origin {
+ domain_name = data.aws_lb.admin_api.dns_name
+ origin_id = data.aws_lb.admin_api.id
+
+ custom_origin_config {
+ http_port = 80
+ https_port = 443
+ origin_protocol_policy = "http-only"
+ origin_ssl_protocols = ["TLSv1.2"]
+ }
+ }
+
+ enabled = true
+ comment = "Codedang"
+ http_version = "http2and3"
+
+ aliases = ["codedang.com"]
+
+ default_cache_behavior {
+ allowed_methods = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"]
+ cached_methods = ["GET", "HEAD", "OPTIONS"]
+ target_origin_id = "frontend" # TODO: do not hard-code origin_id
+ viewer_protocol_policy = "redirect-to-https"
+ cache_policy_id = data.aws_cloudfront_cache_policy.disable.id
+ origin_request_policy_id = data.aws_cloudfront_origin_request_policy.exclude_host_header.id
+ }
+
+ ordered_cache_behavior {
+ path_pattern = "/api/*"
+ allowed_methods = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"]
+ cached_methods = ["GET", "HEAD", "OPTIONS"]
+ target_origin_id = data.aws_lb.client_api.id
+ viewer_protocol_policy = "redirect-to-https"
+ cache_policy_id = data.aws_cloudfront_cache_policy.disable.id
+ origin_request_policy_id = data.aws_cloudfront_origin_request_policy.allow_all.id
+ }
+
+ ordered_cache_behavior {
+ path_pattern = "/graphql"
+ allowed_methods = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"]
+ cached_methods = ["GET", "HEAD", "OPTIONS"]
+ target_origin_id = data.aws_lb.admin_api.id
+ viewer_protocol_policy = "redirect-to-https"
+ cache_policy_id = data.aws_cloudfront_cache_policy.disable.id
+ origin_request_policy_id = data.aws_cloudfront_origin_request_policy.allow_all.id
+ }
+
+ restrictions {
+ geo_restriction {
+ restriction_type = "none"
+ }
+ }
+
+ viewer_certificate {
+ acm_certificate_arn = aws_acm_certificate_validation.for_all_domains.certificate_arn
+ ssl_support_method = "sni-only"
+ minimum_protocol_version = "TLSv1.2_2021"
+ }
+}
diff --git a/apps/infra/production/network/main.tf b/apps/infra/production/network/main.tf
index 111fb80883..be1016d9f6 100644
--- a/apps/infra/production/network/main.tf
+++ b/apps/infra/production/network/main.tf
@@ -16,5 +16,5 @@ terraform {
}
provider "aws" {
- region = var.region
+ region = "ap-northeast-2"
}
diff --git a/apps/infra/production/network/private_network.tf b/apps/infra/production/network/private_network.tf
new file mode 100644
index 0000000000..f188b0a1c4
--- /dev/null
+++ b/apps/infra/production/network/private_network.tf
@@ -0,0 +1,42 @@
+resource "aws_route_table" "private" {
+ vpc_id = aws_vpc.main.id
+
+ route {
+ cidr_block = "0.0.0.0/0"
+ nat_gateway_id = aws_nat_gateway.public_subnet1.id
+ }
+
+ tags = {
+ Name = "Codedang-Private-RT"
+ }
+}
+
+resource "aws_route_table_association" "admin_api1" {
+ subnet_id = var.private_admin_api1_subnet_id
+ route_table_id = aws_route_table.private.id
+}
+
+resource "aws_route_table_association" "admin_api2" {
+ subnet_id = var.private_admin_api2_subnet_id
+ route_table_id = aws_route_table.private.id
+}
+
+resource "aws_route_table_association" "iris1" {
+ subnet_id = var.private_iris1_subnet_id
+ route_table_id = aws_route_table.private.id
+}
+
+resource "aws_route_table_association" "iris2" {
+ subnet_id = var.private_iris2_subnet_id
+ route_table_id = aws_route_table.private.id
+}
+
+resource "aws_route_table_association" "client_api1" {
+ subnet_id = var.private_client_api1_subnet_id
+ route_table_id = aws_route_table.private.id
+}
+
+resource "aws_route_table_association" "client_api2" {
+ subnet_id = var.private_client_api2_subnet_id
+ route_table_id = aws_route_table.private.id
+}
diff --git a/apps/infra/production/network/public_network.tf b/apps/infra/production/network/public_network.tf
new file mode 100644
index 0000000000..f4b16b7a6d
--- /dev/null
+++ b/apps/infra/production/network/public_network.tf
@@ -0,0 +1,79 @@
+resource "aws_internet_gateway" "main" {
+ vpc_id = aws_vpc.main.id
+
+ tags = {
+ Name = "Codedang-InternetFacing"
+ }
+}
+
+resource "aws_eip" "for_nat" {
+ domain = "vpc"
+
+ lifecycle {
+ create_before_destroy = true
+ }
+
+ depends_on = [aws_internet_gateway.main]
+
+ tags = {
+ Name = "Codedang-NatEIP"
+ }
+}
+
+# TODO: public_subnet2에도 할당 필요 (-> vpc endpoint로 수정하는 방향으로 진행하기)
+resource "aws_nat_gateway" "public_subnet1" {
+ allocation_id = aws_eip.for_nat.id
+ subnet_id = aws_subnet.public_subnet1.id
+
+ tags = {
+ Name = "Codedang-NatGateway-1"
+ }
+}
+
+resource "aws_route_table" "public" {
+ vpc_id = aws_vpc.main.id
+
+ route {
+ cidr_block = "0.0.0.0/0"
+ gateway_id = aws_internet_gateway.main.id
+ }
+
+ route {
+ ipv6_cidr_block = "::/0"
+ gateway_id = aws_internet_gateway.main.id
+ }
+
+ tags = {
+ Name = "Codedang-Public-RT"
+ }
+}
+
+resource "aws_subnet" "public_subnet1" {
+ vpc_id = aws_vpc.main.id
+ cidr_block = "10.0.90.0/24"
+ availability_zone = "ap-northeast-2a"
+
+ tags = {
+ Name = "Codedang-Public-Nat-Subnet1"
+ }
+}
+
+resource "aws_subnet" "public_subnet2" {
+ vpc_id = aws_vpc.main.id
+ cidr_block = "10.0.91.0/24"
+ availability_zone = "ap-northeast-2c"
+
+ tags = {
+ Name = "Codedang-Public-Nat-Subnet2"
+ }
+}
+
+resource "aws_route_table_association" "public_subnet1" {
+ subnet_id = aws_subnet.public_subnet1.id
+ route_table_id = aws_route_table.public.id
+}
+
+resource "aws_route_table_association" "public_subnet2" {
+ subnet_id = aws_subnet.public_subnet2.id
+ route_table_id = aws_route_table.public.id
+}
diff --git a/apps/infra/production/network/route53.tf b/apps/infra/production/network/route53.tf
new file mode 100644
index 0000000000..4a4df005af
--- /dev/null
+++ b/apps/infra/production/network/route53.tf
@@ -0,0 +1,52 @@
+provider "aws" {
+ alias = "us_east_1"
+ region = "us-east-1"
+}
+
+resource "aws_route53_zone" "codedang" {
+ name = "codedang.com"
+}
+
+resource "aws_route53_record" "codedang" {
+ name = "codedang.com"
+ type = "A"
+ zone_id = aws_route53_zone.codedang.zone_id
+
+ alias {
+ name = aws_cloudfront_distribution.codedang.domain_name
+ zone_id = aws_cloudfront_distribution.codedang.hosted_zone_id
+ evaluate_target_health = false
+ }
+}
+
+resource "aws_acm_certificate" "codedang" {
+ domain_name = "codedang.com"
+ validation_method = "DNS"
+ provider = aws.us_east_1
+}
+
+resource "aws_route53_record" "certificate" {
+ for_each = {
+ for dvo in aws_acm_certificate.codedang.domain_validation_options : dvo.domain_name => {
+ name = dvo.resource_record_name
+ zone_id = aws_route53_zone.codedang.zone_id
+ type = dvo.resource_record_type
+ value = dvo.resource_record_value
+ }
+ }
+
+ allow_overwrite = true
+ name = each.value.name
+ records = [each.value.value]
+ ttl = 60
+ type = each.value.type
+ zone_id = each.value.zone_id
+}
+
+resource "aws_acm_certificate_validation" "for_all_domains" {
+ provider = aws.us_east_1
+ certificate_arn = aws_acm_certificate.codedang.arn
+ validation_record_fqdns = [
+ for record in aws_route53_record.certificate : record.fqdn
+ ]
+}
diff --git a/apps/infra/production/network/variables.tf b/apps/infra/production/network/variables.tf
index 5f8881bb65..4fc1834f13 100644
--- a/apps/infra/production/network/variables.tf
+++ b/apps/infra/production/network/variables.tf
@@ -1,5 +1,6 @@
-variable "region" {
- type = string
- description = "The region for provider"
- default = "ap-northeast-2"
-}
+variable "private_admin_api1_subnet_id" {}
+variable "private_admin_api2_subnet_id" {}
+variable "private_iris1_subnet_id" {}
+variable "private_iris2_subnet_id" {}
+variable "private_client_api1_subnet_id" {}
+variable "private_client_api2_subnet_id" {}
diff --git a/apps/infra/production/network/vpc.tf b/apps/infra/production/network/vpc.tf
new file mode 100644
index 0000000000..14f130ec07
--- /dev/null
+++ b/apps/infra/production/network/vpc.tf
@@ -0,0 +1,7 @@
+resource "aws_vpc" "main" {
+ cidr_block = "10.0.0.0/16"
+
+ tags = {
+ Name = "Codedang-VPC"
+ }
+}