Cloud/GCP

GCP VPC간 Classic VPN 생성 스크립트

달빛궁전- 2026. 4. 22. 16:13

 

목표

VPN간 테스트를 위해 GCP VPC 간 VPN을 구축하는 스크립트
추가적으로 Private Service Connect (PSC)연결을 위해 PSC IP 라우팅을 추가한 설치 쉘스크립트를 설명합니다.
  1. 사용방법
    소스코드를 Cloud Shell, ADC인증을 받은 local CLI(CMD)에서 실행합니다.

    쉘스크립트는 gcloud 명령을 이용하여, 인증된 GCP 프로젝트의 VPC를 조회하고, 선택된 VPC의 subnet을 조회합니다.
    사용자는 각 VPC, Subnet을 선택합니다.

    PSC를 테스트 할 경우 해당 PSC IP대역을 입력하면 On-premise (VPC2번측)에서 PSC대역으로 찾아가도록 자동으로 GCP VPC 경로를 추가해줍니다.
    아래는 실행시 예제 화면 입니다.
- 스크립트 실행


- 스크립트 실행 완료


- PSC 자동 경로 추가

- VPN 생성확인

2. Shell Script 소스코드

#!/bin/bash

# --- 색상 정의 ---
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m'

echo -e "${BLUE}======================================================${NC}"
echo -e "${BLUE}   GCP VPC간 VPN 테스트를 위한 스크립트 (정적 라우팅 기반)       ${NC}"
echo -e "${BLUE}======================================================${NC}"

# 1. 인프라 정보 수집
PROJECT_ID=$(gcloud config get-value project)
REGION="asia-northeast3"

VPC_LIST=($(gcloud compute networks list --format="value(name)"))
echo -e "\n${YELLOW}--- 1. VPC 네트워크 선택 ---${NC}"
for i in "${!VPC_LIST[@]}"; do echo "[$i] ${VPC_LIST[$i]}"; done
read -p "VPC 1 (Agent측) 번호 선택 [0]: " IDX1
VPC1_NAME=${VPC_LIST[${IDX1:-0}]}
read -p "VPC 2 (Onprem측) 번호 선택 [1]: " IDX2
VPC2_NAME=${VPC_LIST[${IDX2:-1}]}

echo -e "\n${YELLOW}--- 2. VPC 1 서브넷 선택 ---${NC}"
S_CIDRS1=($(gcloud compute networks subnets list --network=$VPC1_NAME --regions=$REGION --format="value(ipCidrRange)"))
S_NAMES1=($(gcloud compute networks subnets list --network=$VPC1_NAME --regions=$REGION --format="value(name)"))
for i in "${!S_CIDRS1[@]}"; do echo "[$i] ${S_NAMES1[$i]} (${S_CIDRS1[$i]})"; done
read -p "VPC 1에서 전파할 서브넷 번호들 (예: 0,1) [0]: " S_IDXS_STR
S_IDXS_STR=${S_IDXS_STR:-0}

SELECTED_CIDRS=()
IFS=',' read -ra ADDR <<< "$S_IDXS_STR"
for idx in "${ADDR[@]}"; do SELECTED_CIDRS+=("${S_CIDRS1[$idx]}") ; done
VPC1_SUBNETS_STR=$(IFS=, ; echo "${SELECTED_CIDRS[*]}")

echo -e "\n${YELLOW}--- 3. VPC 2 서브넷 선택 ---${NC}"
S_CIDRS2=($(gcloud compute networks subnets list --network=$VPC2_NAME --regions=$REGION --format="value(ipCidrRange)"))
for i in "${!S_CIDRS2[@]}"; do echo "[$i] ${S_CIDRS2[$i]}"; done
read -p "VPC 2 서브넷 번호 선택 [0]: " S_IDX2
VPC2_CIDR=${S_CIDRS2[${S_IDX2:-0}]}

echo -e "\n${YELLOW}--- 4. PSC IP 라우팅 설정 ---${NC}"
read -p "Vertex AI PSC IP (예: 100.100.100.254 / 대역 가능): " PSC_IP

# CIDR 형식이 아니면 /32 자동 추가
if [[ -n "$PSC_IP" && "$PSC_IP" != *"/"* ]]; then
    PSC_IP_TF="$PSC_IP/32"
else
    PSC_IP_TF="$PSC_IP"
fi

# 테라폼용 리스트 변환 (["10.1", "10.2"])
VPC1_SUBNETS_TF=$(echo $VPC1_SUBNETS_STR | sed 's/,/","/g' | sed 's/^/["/' | sed 's/$/"]/')

# 2. Terraform 생성 (세미콜론 완전 제거)
echo -e "\n${YELLOW}[3/4] Terraform 소스 생성 중...${NC}"

cat <<EOF > main.tf
terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 5.0"
    }
    random = {
      source  = "hashicorp/random"
      version = "~> 3.0"
    }
  }
}

provider "google" {
  project = "$PROJECT_ID"
  region  = "$REGION"
}

resource "random_string" "shared_secret" {
  length  = 24
  special = false
}

data "google_compute_network" "vpc1" {
  name = "$VPC1_NAME"
}

data "google_compute_network" "vpc2" {
  name = "$VPC2_NAME"
}

resource "google_compute_address" "ip1" {
  name   = "vpn-ip-1"
  region = "$REGION"
}

resource "google_compute_address" "ip2" {
  name   = "vpn-ip-2"
  region = "$REGION"
}

resource "google_compute_vpn_gateway" "gw1" {
  name    = "vpn-gw-1"
  network = data.google_compute_network.vpc1.id
  region  = "$REGION"
}

resource "google_compute_vpn_gateway" "gw2" {
  name    = "vpn-gw-2"
  network = data.google_compute_network.vpc2.id
  region  = "$REGION"
}

resource "google_compute_forwarding_rule" "fr1_esp" {
  name        = "fr1-esp"
  region      = "$REGION"
  ip_protocol = "ESP"
  ip_address  = google_compute_address.ip1.address
  target      = google_compute_vpn_gateway.gw1.id
}

resource "google_compute_forwarding_rule" "fr1_u500" {
  name        = "fr1-u500"
  region      = "$REGION"
  ip_protocol = "UDP"
  port_range  = "500"
  ip_address  = google_compute_address.ip1.address
  target      = google_compute_vpn_gateway.gw1.id
}

resource "google_compute_forwarding_rule" "fr1_u4500" {
  name        = "fr1-u4500"
  region      = "$REGION"
  ip_protocol = "UDP"
  port_range  = "4500"
  ip_address  = google_compute_address.ip1.address
  target      = google_compute_vpn_gateway.gw1.id
}

resource "google_compute_forwarding_rule" "fr2_esp" {
  name        = "fr2-esp"
  region      = "$REGION"
  ip_protocol = "ESP"
  ip_address  = google_compute_address.ip2.address
  target      = google_compute_vpn_gateway.gw2.id
}

resource "google_compute_forwarding_rule" "fr2_u500" {
  name        = "fr2-u500"
  region      = "$REGION"
  ip_protocol = "UDP"
  port_range  = "500"
  ip_address  = google_compute_address.ip2.address
  target      = google_compute_vpn_gateway.gw2.id
}

resource "google_compute_forwarding_rule" "fr2_u4500" {
  name        = "fr2-u4500"
  region      = "$REGION"
  ip_protocol = "UDP"
  port_range  = "4500"
  ip_address  = google_compute_address.ip2.address
  target      = google_compute_vpn_gateway.gw2.id
}

resource "google_compute_vpn_tunnel" "t1_to_2" {
  name                    = "tunnel1-to-2"
  region                  = "$REGION"
  peer_ip                 = google_compute_address.ip2.address
  shared_secret           = random_string.shared_secret.result
  target_vpn_gateway      = google_compute_vpn_gateway.gw1.id
  ike_version             = 2
  local_traffic_selector  = ["0.0.0.0/0"]
  remote_traffic_selector = ["0.0.0.0/0"]
  depends_on              = [
    google_compute_forwarding_rule.fr1_esp,
    google_compute_forwarding_rule.fr1_u500,
    google_compute_forwarding_rule.fr1_u4500
  ]
}

resource "google_compute_vpn_tunnel" "t2_to_1" {
  name                    = "tunnel2-to-1"
  region                  = "$REGION"
  peer_ip                 = google_compute_address.ip1.address
  shared_secret           = random_string.shared_secret.result
  target_vpn_gateway      = google_compute_vpn_gateway.gw2.id
  ike_version             = 2
  local_traffic_selector  = ["0.0.0.0/0"]
  remote_traffic_selector = ["0.0.0.0/0"]
  depends_on              = [
    google_compute_forwarding_rule.fr2_esp,
    google_compute_forwarding_rule.fr2_u500,
    google_compute_forwarding_rule.fr2_u4500
  ]
}

resource "google_compute_route" "r1_to_2" {
  name                = "route-1-to-2"
  network             = data.google_compute_network.vpc1.name
  dest_range          = "$VPC2_CIDR"
  priority            = 1000
  next_hop_vpn_tunnel = google_compute_vpn_tunnel.t1_to_2.id
}

resource "google_compute_route" "r2_to_1_subnets" {
  for_each            = toset($VPC1_SUBNETS_TF)
  name                = "route-2-to-1-sub-\${replace(each.value, "/[/.]/", "-")}"
  network             = data.google_compute_network.vpc2.name
  dest_range          = each.value
  priority            = 1000
  next_hop_vpn_tunnel = google_compute_vpn_tunnel.t2_to_1.id
}

resource "google_compute_route" "r2_to_1_psc" {
  count               = "$PSC_IP_TF" != "" ? 1 : 0
  name                = "route-2-to-1-psc"
  network             = data.google_compute_network.vpc2.name
  dest_range          = "$PSC_IP_TF"
  priority            = 500
  next_hop_vpn_tunnel = google_compute_vpn_tunnel.t2_to_1.id
}
EOF

echo -e "\n${YELLOW}[4/4] Terraform 시작...${NC}"
terraform init && terraform apply -auto-approve

echo -e "\n${GREEN}=== 모든 작업이 완료되었습니다. ===${NC}"
echo -e "테스트 종료 후 삭제방안: ${YELLOW}terraform destroy -auto-approve${NC}"