From 67a3e1d85c1c2cb2d270311ad379f4b12677b02a Mon Sep 17 00:00:00 2001 From: eedo_y Date: Sat, 4 Apr 2026 19:41:02 +0900 Subject: [PATCH 1/6] =?UTF-8?q?fix:=20K8s=20=EC=9B=8C=EC=BB=A4=20=EB=85=B8?= =?UTF-8?q?=EB=93=9C=20=EC=84=9C=EB=B8=8C=EB=84=B7=20=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=EC=95=88=EB=90=98=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(#7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terraform/environments/prod/compute.tf | 3 ++- terraform/environments/prod/storage.tf | 4 ++-- terraform/environments/prod/vpc.tf | 2 +- terraform/modules/compute/main.tf | 4 ++++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/terraform/environments/prod/compute.tf b/terraform/environments/prod/compute.tf index 9056812..f5fe8d9 100644 --- a/terraform/environments/prod/compute.tf +++ b/terraform/environments/prod/compute.tf @@ -45,7 +45,8 @@ module "k8s_master_nodes" { module "k8s_worker_nodes" { source = "../../modules/compute" - name_prefix = "${var.project}-${var.environment}-k8s-worker" + # 서브넷 이동은 MIG 인플레이스 업데이트가 불가하므로 새 이름으로 교체합니다. + name_prefix = "${var.project}-${var.environment}-k8s-workers" network = module.vpc.vpc_self_link subnetwork = module.vpc.subnets["app"].self_link diff --git a/terraform/environments/prod/storage.tf b/terraform/environments/prod/storage.tf index 8029c27..45e4853 100644 --- a/terraform/environments/prod/storage.tf +++ b/terraform/environments/prod/storage.tf @@ -20,8 +20,8 @@ module "storage" { storage_class = "STANDARD" uniform_bucket_level_access = true versioning_enabled = true - force_destroy = false # 운영 버킷은 강제 삭제를 사용하지 않습니다. - public_access_prevention = "enforced" # 공개 액세스를 차단합니다. + force_destroy = false + public_access_prevention = "enforced" # 365일이 지난 정적 파일은 Nearline 클래스로 이동합니다. lifecycle_rules = [ diff --git a/terraform/environments/prod/vpc.tf b/terraform/environments/prod/vpc.tf index fd1cf76..b376337 100644 --- a/terraform/environments/prod/vpc.tf +++ b/terraform/environments/prod/vpc.tf @@ -67,7 +67,7 @@ module "vpc" { ports = ["22"] } ] - source_ranges = var.ssh_source_ranges # 프로덕션에서는 반드시 관리된 IP 대역만 허용해야 합니다. + source_ranges = var.ssh_source_ranges target_tags = ["k8s-master", "k8s-worker"] priority = 1000 } diff --git a/terraform/modules/compute/main.tf b/terraform/modules/compute/main.tf index ed50b39..a76f8cb 100644 --- a/terraform/modules/compute/main.tf +++ b/terraform/modules/compute/main.tf @@ -189,6 +189,10 @@ resource "google_compute_instance_group_manager" "instance_group" { max_surge_fixed = var.max_surge_fixed max_unavailable_fixed = var.max_unavailable_fixed } + + lifecycle { + create_before_destroy = true + } } # ======================================== From 34044f376d35199eaf0f40420da8abf4577c5fc0 Mon Sep 17 00:00:00 2001 From: eedo_y Date: Sat, 4 Apr 2026 19:41:43 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20K8s=20=EC=9C=A0=EC=A0=80=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=A6=BD=ED=8A=B8=20=EC=9E=91=EC=84=B1=20(#7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../prod/scripts/k8s-master-init.sh | 77 +++++++++++++++++++ .../prod/scripts/k8s-worker-init.sh | 77 +++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100755 terraform/environments/prod/scripts/k8s-master-init.sh create mode 100755 terraform/environments/prod/scripts/k8s-worker-init.sh diff --git a/terraform/environments/prod/scripts/k8s-master-init.sh b/terraform/environments/prod/scripts/k8s-master-init.sh new file mode 100755 index 0000000..df9d435 --- /dev/null +++ b/terraform/environments/prod/scripts/k8s-master-init.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +set -euxo pipefail + +# ======================================== +# 기본 환경 점검 +# ======================================== +if [ "$(id -u)" -ne 0 ]; then + echo "이 스크립트는 root 권한으로 실행해야 합니다." + exit 1 +fi + +export DEBIAN_FRONTEND=noninteractive + +# ======================================== +# Ubuntu 기본 패키지 업데이트 +# ======================================== +apt-get update -y +apt-get upgrade -y +apt-get install -y apt-transport-https ca-certificates curl gpg containerd + +# ======================================== +# swap 비활성화 +# ======================================== +swapoff -a +sed -ri '/\sswap\s/s/^#?/#/' /etc/fstab + +# ======================================== +# Kubernetes 네트워크용 커널 모듈 및 sysctl 설정 +# ======================================== +mkdir -p /etc/modules-load.d /etc/sysctl.d /etc/apt/keyrings /etc/containerd + +cat <<'EOF' >/etc/modules-load.d/k8s.conf +overlay +br_netfilter +EOF + +modprobe overlay +modprobe br_netfilter + +cat <<'EOF' >/etc/sysctl.d/99-kubernetes-cri.conf +net.bridge.bridge-nf-call-iptables = 1 +net.bridge.bridge-nf-call-ip6tables = 1 +net.ipv4.ip_forward = 1 +EOF + +sysctl --system + +# ======================================== +# containerd 설정 +# ======================================== +containerd config default >/etc/containerd/config.toml +sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml +systemctl daemon-reload +systemctl enable --now containerd + +# ======================================== +# Kubernetes apt 저장소 설정 +# ======================================== +curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg +echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.35/deb/ /' >/etc/apt/sources.list.d/kubernetes.list + +# ======================================== +# Kubernetes 패키지 설치 +# ======================================== +apt-get update -y +apt-get install -y kubelet kubeadm kubectl +apt-mark hold kubelet kubeadm kubectl + +# ======================================== +# 서비스 활성화 +# ======================================== +systemctl enable --now kubelet + +# ======================================== +# 후속 작업 안내 +# ======================================== +echo "마스터 노드 초기 설정이 완료되었습니다. 이후 kubeadm init 및 CNI 설치를 진행하세요." diff --git a/terraform/environments/prod/scripts/k8s-worker-init.sh b/terraform/environments/prod/scripts/k8s-worker-init.sh new file mode 100755 index 0000000..f949efa --- /dev/null +++ b/terraform/environments/prod/scripts/k8s-worker-init.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +set -euxo pipefail + +# ======================================== +# 기본 환경 점검 +# ======================================== +if [ "$(id -u)" -ne 0 ]; then + echo "이 스크립트는 root 권한으로 실행해야 합니다." + exit 1 +fi + +export DEBIAN_FRONTEND=noninteractive + +# ======================================== +# Ubuntu 기본 패키지 업데이트 +# ======================================== +apt-get update -y +apt-get upgrade -y +apt-get install -y apt-transport-https ca-certificates curl gpg containerd + +# ======================================== +# swap 비활성화 +# ======================================== +swapoff -a +sed -ri '/\sswap\s/s/^#?/#/' /etc/fstab + +# ======================================== +# Kubernetes 네트워크용 커널 모듈 및 sysctl 설정 +# ======================================== +mkdir -p /etc/modules-load.d /etc/sysctl.d /etc/apt/keyrings /etc/containerd + +cat <<'EOF' >/etc/modules-load.d/k8s.conf +overlay +br_netfilter +EOF + +modprobe overlay +modprobe br_netfilter + +cat <<'EOF' >/etc/sysctl.d/99-kubernetes-cri.conf +net.bridge.bridge-nf-call-iptables = 1 +net.bridge.bridge-nf-call-ip6tables = 1 +net.ipv4.ip_forward = 1 +EOF + +sysctl --system + +# ======================================== +# containerd 설정 +# ======================================== +containerd config default >/etc/containerd/config.toml +sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml +systemctl daemon-reload +systemctl enable --now containerd + +# ======================================== +# Kubernetes apt 저장소 설정 +# ======================================== +curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg +echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.35/deb/ /' >/etc/apt/sources.list.d/kubernetes.list + +# ======================================== +# Kubernetes 패키지 설치 +# ======================================== +apt-get update -y +apt-get install -y kubelet kubeadm +apt-mark hold kubelet kubeadm + +# ======================================== +# 서비스 활성화 +# ======================================== +systemctl enable --now kubelet + +# ======================================== +# 후속 작업 안내 +# ======================================== +echo "워커 노드 초기 설정이 완료되었습니다. 이후 kubeadm join 명령을 실행하세요." From 6ec632d25d47cc18eaa9724cbf54e28bc2c56244 Mon Sep 17 00:00:00 2001 From: eedo_y Date: Sat, 4 Apr 2026 19:43:04 +0900 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20K8s=20=EC=9C=A0=EC=A0=80=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=A6=BD=ED=8A=B8=20=EC=B4=88=EA=B8=B0=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20(#7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terraform/environments/prod/compute.tf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/terraform/environments/prod/compute.tf b/terraform/environments/prod/compute.tf index f5fe8d9..d9c5075 100644 --- a/terraform/environments/prod/compute.tf +++ b/terraform/environments/prod/compute.tf @@ -24,6 +24,7 @@ module "k8s_master_nodes" { boot_disk_size_gb = var.k8s_node_boot_disk_size_gb boot_disk_type = "pd-balanced" enable_external_ip = false + startup_script = file("${path.module}/scripts/k8s-master-init.sh") tags = ["k8s-master", var.environment] # 태그 @@ -69,6 +70,7 @@ module "k8s_worker_nodes" { boot_disk_size_gb = var.k8s_node_boot_disk_size_gb boot_disk_type = "pd-balanced" enable_external_ip = false + startup_script = file("${path.module}/scripts/k8s-worker-init.sh") tags = ["k8s-worker", var.environment] # 태그 From 4bbd4c265491ad2f53a8c620461b7ea59a452f9b Mon Sep 17 00:00:00 2001 From: eedo_y Date: Sun, 5 Apr 2026 01:00:57 +0900 Subject: [PATCH 4/6] =?UTF-8?q?refactor:=20IAP=20=EB=B0=8F=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EB=B6=84=EB=A6=AC=20(#7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terraform/.gitignore | 4 +- terraform/environments/prod/compute.tf | 8 +- terraform/environments/prod/firewall.tf | 177 ++++++++++++++++++ terraform/environments/prod/iap.tf | 13 ++ terraform/environments/prod/outputs.tf | 28 +++ .../prod/terraform.tfvars.example | 36 ++-- terraform/environments/prod/variables.tf | 50 ++++- terraform/environments/prod/vpc.tf | 57 +----- terraform/modules/iap-access/main.tf | 72 +++++++ terraform/modules/iap-access/outputs.tf | 12 ++ terraform/modules/iap-access/variables.tf | 34 ++++ 11 files changed, 417 insertions(+), 74 deletions(-) create mode 100644 terraform/environments/prod/firewall.tf create mode 100644 terraform/environments/prod/iap.tf create mode 100644 terraform/modules/iap-access/main.tf create mode 100644 terraform/modules/iap-access/outputs.tf create mode 100644 terraform/modules/iap-access/variables.tf diff --git a/terraform/.gitignore b/terraform/.gitignore index 3564016..7894eff 100644 --- a/terraform/.gitignore +++ b/terraform/.gitignore @@ -27,5 +27,5 @@ terraform.rc # Ignore backup files *.backup -# Ignore lock files (optional - 팀에서 결정) -# .terraform.lock.hcl +# Ignore lock files +.terraform.lock.hcl diff --git a/terraform/environments/prod/compute.tf b/terraform/environments/prod/compute.tf index d9c5075..cdff2f0 100644 --- a/terraform/environments/prod/compute.tf +++ b/terraform/environments/prod/compute.tf @@ -24,8 +24,12 @@ module "k8s_master_nodes" { boot_disk_size_gb = var.k8s_node_boot_disk_size_gb boot_disk_type = "pd-balanced" enable_external_ip = false - startup_script = file("${path.module}/scripts/k8s-master-init.sh") - tags = ["k8s-master", var.environment] + startup_script = templatefile("${path.module}/scripts/k8s-master-init.sh", { + k8s_pod_cidr = var.k8s_pod_cidr + k8s_service_cidr = var.k8s_service_cidr + calico_version = var.calico_version + }) + tags = ["k8s-master", var.environment] # 태그 common_tags = merge(var.common_tags, { diff --git a/terraform/environments/prod/firewall.tf b/terraform/environments/prod/firewall.tf new file mode 100644 index 0000000..886fd3e --- /dev/null +++ b/terraform/environments/prod/firewall.tf @@ -0,0 +1,177 @@ +# ======================================== +# 프로덕션 방화벽 값 +# ======================================== +locals { + prod_firewall_rules = merge( + { + # 워커 노드가 외부 HTTP 트래픽을 받을 수 있도록 허용합니다. + allow_http = { + name = "${var.vpc_name}-allow-http" + allow = [ + { + protocol = "tcp" + ports = ["80"] + } + ] + source_ranges = ["0.0.0.0/0"] + target_tags = ["k8s-worker"] + priority = 1000 + } + + # 워커 노드가 외부 HTTPS 트래픽을 받을 수 있도록 허용합니다. + allow_https = { + name = "${var.vpc_name}-allow-https" + allow = [ + { + protocol = "tcp" + ports = ["443"] + } + ] + source_ranges = ["0.0.0.0/0"] + target_tags = ["k8s-worker"] + priority = 1000 + } + + # 마스터와 워커 노드가 Kubernetes API 서버에 접근할 수 있도록 허용합니다. + allow_k8s_api_from_nodes = { + name = "${var.vpc_name}-allow-k8s-api-from-nodes" + allow = [ + { + protocol = "tcp" + ports = ["6443"] + } + ] + source_tags = ["k8s-master", "k8s-worker"] + target_tags = ["k8s-master"] + priority = 1000 + } + + # 마스터 노드 간 etcd와 컨트롤 플레인 포트를 허용합니다. + allow_k8s_control_plane = { + name = "${var.vpc_name}-allow-k8s-control-plane" + allow = [ + { + protocol = "tcp" + ports = ["2379-2380", "10250", "10257", "10259"] + } + ] + source_tags = ["k8s-master"] + target_tags = ["k8s-master"] + priority = 1000 + } + + # 마스터 노드가 워커 노드 kubelet에 접근할 수 있도록 허용합니다. + allow_kubelet_from_control_plane = { + name = "${var.vpc_name}-allow-kubelet-from-control-plane" + allow = [ + { + protocol = "tcp" + ports = ["10250"] + } + ] + source_tags = ["k8s-master"] + target_tags = ["k8s-worker"] + priority = 1000 + } + + # 노드 간 kube-proxy 헬스 및 프록시 포트를 허용합니다. + allow_kube_proxy_from_nodes = { + name = "${var.vpc_name}-allow-kube-proxy-from-nodes" + allow = [ + { + protocol = "tcp" + ports = ["10256"] + } + ] + source_tags = ["k8s-master", "k8s-worker"] + target_tags = ["k8s-worker"] + priority = 1000 + } + + # Calico BGP 피어링에 필요한 TCP 179 포트를 허용합니다. + allow_calico_bgp = { + name = "${var.vpc_name}-allow-calico-bgp" + allow = [ + { + protocol = "tcp" + ports = ["179"] + } + ] + source_tags = ["k8s-master", "k8s-worker"] + target_tags = ["k8s-master", "k8s-worker"] + priority = 1000 + } + + # Calico IP-in-IP 터널링 트래픽을 허용합니다. + allow_calico_ipip = { + name = "${var.vpc_name}-allow-calico-ipip" + allow = [ + { + protocol = "ipip" + } + ] + source_tags = ["k8s-master", "k8s-worker"] + target_tags = ["k8s-master", "k8s-worker"] + priority = 1000 + } + + # Pod CIDR 대역에서 노드로 들어오는 Calico 워크로드 트래픽을 허용합니다. + allow_calico_pod_cidr = { + name = "${var.vpc_name}-allow-calico-pod-cidr" + allow = [ + { + protocol = "tcp" + ports = ["0-65535"] + }, + { + protocol = "udp" + ports = ["0-65535"] + }, + { + protocol = "icmp" + } + ] + source_ranges = [var.k8s_pod_cidr] + target_tags = ["k8s-master", "k8s-worker"] + priority = 1000 + } + }, + var.enable_iap_ssh ? { + # IAP TCP 터널을 통한 SSH 접근을 허용합니다. + allow_iap_ssh = { + name = "${var.vpc_name}-allow-iap-ssh" + allow = [ + { + protocol = "tcp" + ports = ["22"] + } + ] + source_ranges = var.iap_ssh_source_ranges + target_tags = var.management_target_tags + priority = 1000 + } + } : {}, + { + # Kubernetes 노드 태그를 가진 인스턴스끼리 내부 통신을 허용합니다. + allow_internal = { + name = "${var.vpc_name}-allow-internal" + allow = [ + { + protocol = "tcp" + ports = ["0-65535"] + }, + { + protocol = "udp" + ports = ["0-65535"] + }, + { + protocol = "icmp" + } + ] + source_tags = ["k8s-master", "k8s-worker"] + target_tags = ["k8s-master", "k8s-worker"] + priority = 65534 + } + } + ) +} diff --git a/terraform/environments/prod/iap.tf b/terraform/environments/prod/iap.tf new file mode 100644 index 0000000..3e564ff --- /dev/null +++ b/terraform/environments/prod/iap.tf @@ -0,0 +1,13 @@ +# ======================================== +# IAP SSH 접근 모듈 +# ======================================== +module "iap_access" { + source = "../../modules/iap-access" + + project_id = var.project_id + + enable_iap_ssh = var.enable_iap_ssh + iap_ssh_members = var.iap_ssh_members + iap_ssh_admin_members = var.iap_ssh_admin_members + service_account_email = var.service_account_email +} diff --git a/terraform/environments/prod/outputs.tf b/terraform/environments/prod/outputs.tf index 693ef74..e6ba301 100644 --- a/terraform/environments/prod/outputs.tf +++ b/terraform/environments/prod/outputs.tf @@ -64,3 +64,31 @@ output "load_balancer_ip" { description = "로드 밸런서 IP 주소입니다." value = var.create_load_balancer ? module.load_balancer[0].forwarding_rule_ip_address : null } + +# ======================================== +# IAP 접근 출력값 +# ======================================== +output "iap_ssh_configuration" { + description = "IAP SSH 접근 구성 정보입니다." + value = { + enabled = var.enable_iap_ssh + source_ranges = var.enable_iap_ssh ? var.iap_ssh_source_ranges : [] + target_tags = var.management_target_tags + members = module.iap_access.iap_access_members + admin_members = module.iap_access.iap_admin_members + direct_ssh_ranges = var.ssh_source_ranges + } +} + +# ======================================== +# Kubernetes 네트워크 출력값 +# ======================================== +output "k8s_network_configuration" { + description = "Kubernetes 및 Calico 네트워크 구성 정보입니다." + value = { + pod_cidr = var.k8s_pod_cidr + service_cidr = var.k8s_service_cidr + calico_version = var.calico_version + encapsulation = "IPIP" + } +} diff --git a/terraform/environments/prod/terraform.tfvars.example b/terraform/environments/prod/terraform.tfvars.example index 0180814..df49eed 100644 --- a/terraform/environments/prod/terraform.tfvars.example +++ b/terraform/environments/prod/terraform.tfvars.example @@ -2,6 +2,7 @@ # 프로젝트 기본 값 # ======================================== project_id = "your-prod-gcp-project-id" +project = "pinhouse" # ======================================== # 배포 환경 기본 값 @@ -12,30 +13,40 @@ environment = "prod" # ======================================== # VPC 관련 값 # ======================================== -vpc_name = "prod-vpc" -ssh_source_ranges = ["203.0.113.10/32"] -enable_nat = true +vpc_name = "prod-vpc" + +# 직접 SSH를 열지 않고 IAP만 사용할 경우 빈 배열로 둡니다. +ssh_source_ranges = [] + +enable_iap_ssh = true +iap_ssh_members = ["group:platform@example.com"] +iap_ssh_admin_members = ["group:sre-admin@example.com"] + +enable_nat = true # ======================================== -# 컴퓨트 관련 값 +# Kubernetes 컴퓨트 관련 값 # ======================================== -use_instance_group = true -create_web_instances = true -instance_group_size = 2 +k8s_master_instance_group_size = 1 +k8s_worker_instance_group_size = 2 -# 오토스케일링 기본 값입니다. enable_autoscaling = true autoscaling_min_replicas = 2 autoscaling_max_replicas = 5 -web_machine_type = "e2-standard-2" -web_source_image = "ubuntu-os-cloud/ubuntu-2204-lts" -web_machine_ssd = 30 +k8s_master_machine_type = "e2-standard-2" +k8s_worker_machine_type = "e2-standard-2" +k8s_node_boot_disk_size_gb = 50 +k8s_node_source_image = "ubuntu-os-cloud/ubuntu-2204-lts" +k8s_pod_cidr = "192.168.0.0/16" +k8s_service_cidr = "10.96.0.0/12" +calico_version = "v3.31.4" + # ======================================== # 스토리지 관련 값 # ======================================== create_storage_buckets = true -storage_location = "ASIA" +storage_location = "ASIA-NORTHEAST3" # CORS 허용 Origin allowed_cors_origins = [ @@ -47,4 +58,3 @@ allowed_cors_origins = [ # 로드 밸런서 관련 값 # ======================================== create_load_balancer = true -lb_type = "NETWORK" diff --git a/terraform/environments/prod/variables.tf b/terraform/environments/prod/variables.tf index 4ef8b07..c230cb0 100644 --- a/terraform/environments/prod/variables.tf +++ b/terraform/environments/prod/variables.tf @@ -35,7 +35,37 @@ variable "vpc_name" { } variable "ssh_source_ranges" { - description = "SSH 접근을 허용할 CIDR 목록입니다." + description = "직접 SSH 접근을 허용할 CIDR 목록입니다. 비워두면 IAP만 허용합니다." + type = list(string) + default = [] +} + +variable "enable_iap_ssh" { + description = "IAP TCP 터널 기반 SSH 접근 허용 여부입니다." + type = bool + default = true +} + +variable "iap_ssh_source_ranges" { + description = "IAP TCP 터널이 인스턴스로 접근할 때 허용할 Google 관리 소스 CIDR 목록입니다." + type = list(string) + default = ["35.235.240.0/20"] +} + +variable "management_target_tags" { + description = "SSH 및 IAP 관리 접근을 허용할 인스턴스 태그 목록입니다." + type = list(string) + default = ["k8s-master", "k8s-worker"] +} + +variable "iap_ssh_members" { + description = "IAP 터널과 일반 OS Login 권한을 부여할 IAM 주체 목록입니다." + type = list(string) + default = [] +} + +variable "iap_ssh_admin_members" { + description = "IAP 터널과 관리자 OS Login 권한을 부여할 IAM 주체 목록입니다." type = list(string) default = [] } @@ -103,6 +133,24 @@ variable "k8s_node_source_image" { default = "ubuntu-os-cloud/ubuntu-2204-lts" } +variable "k8s_pod_cidr" { + description = "Kubernetes Pod CIDR 대역입니다. Calico IPPool과 kubeadm podSubnet에 동일하게 사용합니다." + type = string + default = "192.168.0.0/16" +} + +variable "k8s_service_cidr" { + description = "Kubernetes Service CIDR 대역입니다." + type = string + default = "10.96.0.0/12" +} + +variable "calico_version" { + description = "초기 설치에 사용할 Calico 오픈소스 릴리스 버전입니다." + type = string + default = "v3.31.4" +} + variable "service_account_email" { description = "인스턴스에 연결할 서비스 계정 이메일입니다." type = string diff --git a/terraform/environments/prod/vpc.tf b/terraform/environments/prod/vpc.tf index b376337..74b2086 100644 --- a/terraform/environments/prod/vpc.tf +++ b/terraform/environments/prod/vpc.tf @@ -34,62 +34,7 @@ module "vpc" { } # 방화벽 규칙 정의 - firewall_rules = { - allow_http = { - name = "${var.vpc_name}-allow-http" - allow = [ - { - protocol = "tcp" - ports = ["80"] - } - ] - source_ranges = ["0.0.0.0/0"] - target_tags = ["k8s-worker"] - priority = 1000 - } - allow_https = { - name = "${var.vpc_name}-allow-https" - allow = [ - { - protocol = "tcp" - ports = ["443"] - } - ] - source_ranges = ["0.0.0.0/0"] - target_tags = ["k8s-worker"] - priority = 1000 - } - allow_ssh = { - name = "${var.vpc_name}-allow-ssh" - allow = [ - { - protocol = "tcp" - ports = ["22"] - } - ] - source_ranges = var.ssh_source_ranges - target_tags = ["k8s-master", "k8s-worker"] - priority = 1000 - } - allow_internal = { - name = "${var.vpc_name}-allow-internal" - allow = [ - { - protocol = "tcp" - ports = ["0-65535"] - }, - { - protocol = "udp" - ports = ["0-65535"] - }, - { - protocol = "icmp" - } - ] - source_ranges = ["10.2.0.0/16"] - priority = 65534 - } - } + firewall_rules = local.prod_firewall_rules # Cloud NAT 설정 enable_nat = var.enable_nat diff --git a/terraform/modules/iap-access/main.tf b/terraform/modules/iap-access/main.tf new file mode 100644 index 0000000..7200bab --- /dev/null +++ b/terraform/modules/iap-access/main.tf @@ -0,0 +1,72 @@ +# ======================================== +# IAP 접근 공통 로컬 값 +# ======================================== +locals { + iap_access_members = setunion(toset(var.iap_ssh_members), toset(var.iap_ssh_admin_members)) + service_account_user_members = local.iap_access_members +} + +# ======================================== +# IAP 및 OS Login API 활성화 +# ======================================== +resource "google_project_service" "iap_api" { + count = var.enable_iap_ssh ? 1 : 0 + + project = var.project_id + service = "iap.googleapis.com" + + disable_on_destroy = false +} + +resource "google_project_service" "oslogin_api" { + count = var.enable_iap_ssh ? 1 : 0 + + project = var.project_id + service = "oslogin.googleapis.com" + + disable_on_destroy = false +} + +# ======================================== +# IAP SSH 프로젝트 IAM 권한 +# ======================================== +resource "google_project_iam_member" "iap_tunnel_resource_accessor" { + for_each = var.enable_iap_ssh ? local.iap_access_members : toset([]) + + project = var.project_id + role = "roles/iap.tunnelResourceAccessor" + member = each.value + + depends_on = [google_project_service.iap_api] +} + +resource "google_project_iam_member" "os_login" { + for_each = var.enable_iap_ssh ? toset(var.iap_ssh_members) : toset([]) + + project = var.project_id + role = "roles/compute.osLogin" + member = each.value + + depends_on = [google_project_service.oslogin_api] +} + +resource "google_project_iam_member" "os_admin_login" { + for_each = var.enable_iap_ssh ? toset(var.iap_ssh_admin_members) : toset([]) + + project = var.project_id + role = "roles/compute.osAdminLogin" + member = each.value + + depends_on = [google_project_service.oslogin_api] +} + +# ======================================== +# 서비스 계정 위임 권한 +# ======================================== +resource "google_service_account_iam_member" "service_account_user" { + for_each = var.enable_iap_ssh && var.service_account_email != null ? local.service_account_user_members : toset([]) + + service_account_id = "projects/${var.project_id}/serviceAccounts/${var.service_account_email}" + role = "roles/iam.serviceAccountUser" + member = each.value +} diff --git a/terraform/modules/iap-access/outputs.tf b/terraform/modules/iap-access/outputs.tf new file mode 100644 index 0000000..ab83bb9 --- /dev/null +++ b/terraform/modules/iap-access/outputs.tf @@ -0,0 +1,12 @@ +# ======================================== +# IAP 접근 출력값 +# ======================================== +output "iap_access_members" { + description = "IAP 터널 접근 권한이 부여된 IAM 주체 목록입니다." + value = sort(tolist(local.iap_access_members)) +} + +output "iap_admin_members" { + description = "관리자 OS Login 권한이 부여된 IAM 주체 목록입니다." + value = sort(tolist(toset(var.iap_ssh_admin_members))) +} diff --git a/terraform/modules/iap-access/variables.tf b/terraform/modules/iap-access/variables.tf new file mode 100644 index 0000000..01c4218 --- /dev/null +++ b/terraform/modules/iap-access/variables.tf @@ -0,0 +1,34 @@ +# ======================================== +# 프로젝트 기본 변수 +# ======================================== +variable "project_id" { + description = "IAP 및 OS Login IAM 권한을 적용할 GCP 프로젝트 ID입니다." + type = string +} + +variable "enable_iap_ssh" { + description = "IAP TCP 터널 기반 SSH 접근 구성 여부입니다." + type = bool + default = true +} + +variable "service_account_email" { + description = "접속 대상 인스턴스에 연결된 서비스 계정 이메일입니다." + type = string + default = null +} + +# ======================================== +# IAP 접근 주체 변수 +# ======================================== +variable "iap_ssh_members" { + description = "IAP 터널과 일반 OS Login 권한을 부여할 IAM 주체 목록입니다." + type = list(string) + default = [] +} + +variable "iap_ssh_admin_members" { + description = "IAP 터널과 관리자 OS Login 권한을 부여할 IAM 주체 목록입니다." + type = list(string) + default = [] +} From 877e9652389d84a83a3d23c3cf9339ba808235d4 Mon Sep 17 00:00:00 2001 From: eedo_y Date: Sun, 5 Apr 2026 01:01:07 +0900 Subject: [PATCH 5/6] =?UTF-8?q?chore:=20k8s=20=EC=9C=A0=EC=A0=80=20?= =?UTF-8?q?=EC=8A=A4=ED=81=AC=EB=A6=BD=ED=8A=B8=20=EC=88=98=EC=A0=95=20(#7?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../prod/scripts/k8s-master-init.sh | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/terraform/environments/prod/scripts/k8s-master-init.sh b/terraform/environments/prod/scripts/k8s-master-init.sh index df9d435..306186a 100755 --- a/terraform/environments/prod/scripts/k8s-master-init.sh +++ b/terraform/environments/prod/scripts/k8s-master-init.sh @@ -71,7 +71,51 @@ apt-mark hold kubelet kubeadm kubectl # ======================================== systemctl enable --now kubelet +# ======================================== +# kubeadm 및 Calico 초기 설정 파일 생성 +# ======================================== +cat </root/kubeadm-config.yaml +apiVersion: kubeadm.k8s.io/v1beta4 +kind: ClusterConfiguration +networking: + podSubnet: ${k8s_pod_cidr} + serviceSubnet: ${k8s_service_cidr} +--- +apiVersion: kubelet.config.k8s.io/v1beta1 +kind: KubeletConfiguration +cgroupDriver: systemd +EOF + +cat </root/calico-custom-resources.yaml +apiVersion: operator.tigera.io/v1 +kind: Installation +metadata: + name: default +spec: + calicoNetwork: + ipPools: + - blockSize: 26 + cidr: ${k8s_pod_cidr} + encapsulation: IPIP + natOutgoing: Enabled + nodeSelector: all() +EOF + +cat </root/install-calico.sh +#!/usr/bin/env bash +set -euxo pipefail + +kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/${calico_version}/manifests/operator-crds.yaml +kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/${calico_version}/manifests/tigera-operator.yaml +kubectl create -f /root/calico-custom-resources.yaml +EOF + +chmod +x /root/install-calico.sh + # ======================================== # 후속 작업 안내 # ======================================== -echo "마스터 노드 초기 설정이 완료되었습니다. 이후 kubeadm init 및 CNI 설치를 진행하세요." +echo "마스터 노드 초기 설정이 완료되었습니다." +echo "1. kubeadm init --config /root/kubeadm-config.yaml --upload-certs" +echo "2. mkdir -p \$HOME/.kube && cp /etc/kubernetes/admin.conf \$HOME/.kube/config && chown \$(id -u):\$(id -g) \$HOME/.kube/config" +echo "3. /root/install-calico.sh" From 22771afc17529c8548621b261a7e377244f50900 Mon Sep 17 00:00:00 2001 From: eedo_y Date: Sun, 5 Apr 2026 01:01:26 +0900 Subject: [PATCH 6/6] =?UTF-8?q?chore:=20Calico=20helm=20=EC=A0=81=EC=9A=A9?= =?UTF-8?q?=20(#7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- k8s-helm/.gitignore | 18 ++++++++++++++++++ k8s-helm/releases/calico/values-nonprod.yaml | 8 ++++++++ k8s-helm/releases/calico/values-prod.yaml | 8 ++++++++ 3 files changed, 34 insertions(+) create mode 100644 k8s-helm/.gitignore create mode 100644 k8s-helm/releases/calico/values-nonprod.yaml create mode 100644 k8s-helm/releases/calico/values-prod.yaml diff --git a/k8s-helm/.gitignore b/k8s-helm/.gitignore new file mode 100644 index 0000000..61494e4 --- /dev/null +++ b/k8s-helm/.gitignore @@ -0,0 +1,18 @@ +# ======================================== +# 로컬 시크릿 매니페스트 +# ======================================== +releases/**/secrets/*.yaml +!releases/**/secrets/*.yaml.example + +# ======================================== +# 로컬 오버라이드 파일 +# ======================================== +*.local.yaml +*.local.yml +*.secret.yaml +*.secret.yml + +# ======================================== +# 릴리스 로컬 문서 +# ======================================== +releases/*/README.md diff --git a/k8s-helm/releases/calico/values-nonprod.yaml b/k8s-helm/releases/calico/values-nonprod.yaml new file mode 100644 index 0000000..f3e2e1f --- /dev/null +++ b/k8s-helm/releases/calico/values-nonprod.yaml @@ -0,0 +1,8 @@ +installation: + calicoNetwork: + bgp: Disabled + ipPools: + - cidr: 192.168.0.0/16 + encapsulation: VXLAN + natOutgoing: Enabled + nodeSelector: all() diff --git a/k8s-helm/releases/calico/values-prod.yaml b/k8s-helm/releases/calico/values-prod.yaml new file mode 100644 index 0000000..f3e2e1f --- /dev/null +++ b/k8s-helm/releases/calico/values-prod.yaml @@ -0,0 +1,8 @@ +installation: + calicoNetwork: + bgp: Disabled + ipPools: + - cidr: 192.168.0.0/16 + encapsulation: VXLAN + natOutgoing: Enabled + nodeSelector: all()