Published on

GCP VPC 피어링 실패? RFC1918 IP 충돌 해결법

Authors

서로 다른 프로젝트나 조직의 VPC를 연결하려고 VPC 피어링을 설정했는데, 생성 단계에서 실패하거나 라우팅이 일부만 되는 경우가 있습니다. 이때 가장 흔한 원인은 RFC1918 사설 IP 대역 충돌(Overlap) 입니다.

피어링은 “두 네트워크가 서로의 라우팅 테이블을 신뢰하고 직접 통신한다”는 전제를 갖습니다. 그래서 서브넷 CIDR이 겹치면 어느 쪽으로 패킷을 보내야 할지 결정할 수 없고(또는 결정이 잘못되어) GCP가 아예 연결을 막거나, 연결되더라도 통신이 비정상적으로 보일 수 있습니다.

이 글에서는 다음을 목표로 합니다.

  • 피어링 실패/부분 통신의 증상을 IP 충돌 관점에서 빠르게 진단하기
  • “대역 바꾸면 되죠”가 어려운 현실에서 가능한 우회/대체 아키텍처 정리
  • 운영 중 영향 최소화 관점의 마이그레이션 시나리오 제시

관련해서 네트워크 문제를 진단할 때는 로그와 관찰이 중요합니다. 인프라 장애를 체계적으로 파고드는 방식은 systemd 서비스 재시작 루프 진단 - 로그·유닛·쉘 글의 접근법(증상 수집, 가설, 재현, 검증)도 참고할 만합니다.

VPC 피어링과 IP 충돌이 왜 치명적인가

VPC 피어링은 기본적으로 다음 특성을 가집니다.

  • 비전이적(non-transitive): A 피어 B, B 피어 C여도 A와 C는 자동으로 연결되지 않음
  • 라우팅 기반: 서로의 서브넷 경로를 교환하고 이를 기반으로 통신
  • NAT/프록시가 아님: 패킷이 “직접” 상대 VPC로 라우팅됨

따라서 두 VPC에 같은 대역이 있으면 예를 들어 이런 상황이 생깁니다.

  • VPC A에 10.10.0.0/16 존재
  • VPC B에도 10.10.0.0/16 존재

A에서 10.10.1.10으로 가는 패킷은 “로컬 서브넷으로 가야 한다”와 “피어링으로 가야 한다”가 동시에 성립합니다. 이 모호성 때문에 GCP는 피어링 생성 자체를 거부하거나, 생성되더라도 특정 경로가 설치되지 않는 방식으로 동작합니다.

실패 증상 체크리스트(겹침을 의심해야 할 때)

다음 중 하나라도 해당하면 IP 충돌을 최우선으로 의심하세요.

  • 피어링 생성 시 오류 메시지에 overlap, conflict, subnet ranges overlap 류가 포함됨
  • 피어링은 “ACTIVE”인데 특정 서브넷/특정 VM만 통신이 안 됨
  • 같은 목적지 IP로의 트래픽이 “어떤 인스턴스에서는 되고, 어떤 인스턴스에서는 안 됨”
  • 방화벽 룰/라우트는 멀쩡한데 traceroute가 로컬에서 끝나거나 엉뚱한 곳으로 감

1단계: 서브넷 CIDR 겹침 여부 빠르게 확인하기

가장 먼저 두 VPC의 서브넷 CIDR을 목록으로 뽑아 교집합을 확인합니다.

gcloud로 서브넷 CIDR 덤프

프로젝트 A와 B에서 각각 실행합니다.

# 프로젝트 A
export PROJECT_A="my-project-a"
export NETWORK_A="vpc-a"

gcloud compute networks subnets list \
  --project "$PROJECT_A" \
  --filter="network:($NETWORK_A)" \
  --format="table(name,region,ipCidrRange,secondaryIpRanges)"

# 프로젝트 B
export PROJECT_B="my-project-b"
export NETWORK_B="vpc-b"

gcloud compute networks subnets list \
  --project "$PROJECT_B" \
  --filter="network:($NETWORK_B)" \
  --format="table(name,region,ipCidrRange,secondaryIpRanges)"

여기서 중요한 포인트는 secondary range 입니다. GKE를 쓰는 경우 Pod/Service CIDR이 secondary range로 잡히며, 이것도 피어링 충돌의 원인이 됩니다.

겹침을 로컬에서 계산하기(간단 스크립트)

CIDR 교집합은 눈으로 보기 어렵습니다. 아래는 Python으로 두 목록의 겹침을 찾는 예시입니다.

import ipaddress

cidrs_a = [
    "10.10.0.0/16",
    "10.20.0.0/16",
]

cidrs_b = [
    "10.10.128.0/17",
    "172.16.0.0/16",
]

nets_a = [ipaddress.ip_network(c) for c in cidrs_a]
nets_b = [ipaddress.ip_network(c) for c in cidrs_b]

for a in nets_a:
    for b in nets_b:
        if a.overlaps(b):
            print(f"OVERLAP: {a} with {b}")

출력에 하나라도 뜨면, 피어링은 “정상적 라우팅”을 기대하기 어렵습니다.

2단계: ‘RFC1918라서 괜찮다’ 착각 정리

RFC1918는 사설 주소 범위를 정의할 뿐, “어디서든 마음대로 써도 충돌이 없다”는 의미가 아닙니다.

  • 10.0.0.0/8
  • 172.16.0.0/12
  • 192.168.0.0/16

대부분의 조직이 10.0.0.0/8 안에서 편하게 쪼개 쓰다 보니, M&A나 협력사 연동, 멀티클라우드 연결, 프로젝트 간 피어링에서 충돌이 폭발합니다.

해결 전략 개요: 무엇을 선택해야 하나

IP 충돌 해결은 보통 아래 4가지 중 하나(또는 조합)로 갑니다.

  1. VPC/서브넷 CIDR 재설계(정공법)
  2. NAT 기반 우회(직접 라우팅 대신 변환)
  3. Private Service Connect(PSC)로 서비스 단위 연결
  4. (GKE 등) Pod/Service CIDR만이라도 재조정

아래에서 각각의 장단점과 적용 포인트를 정리합니다.

해결책 1: CIDR 재설계(가장 확실하지만 가장 아픔)

언제 선택해야 하나

  • 장기적으로 네트워크를 계속 확장해야 함
  • 여러 VPC/온프레/타 클라우드를 계속 연결할 예정
  • 지금 당장 고통스럽더라도 “기반 공사”를 해야 하는 상황

접근 방법

  • 새로운 비충돌 대역을 먼저 확보합니다. 예: 기존이 10.0.0.0/8 위주라면 172.16.0.0/12 내에서 조직 표준을 새로 잡거나, 반대로 10.0.0.0/8 안에서도 조직 전체 IPAM 기준으로 겹치지 않게 할당합니다.
  • 기존 워크로드를 새 서브넷으로 점진 이동합니다.

GCP에서 현실적인 마이그레이션 팁

  • VM은 IP가 바뀌면 영향이 크므로, 서비스 디스커버리는 DNS로 흡수합니다.
  • 내부 서비스는 가능하면 Internal Load Balancer 뒤로 숨겨 IP 변경 영향을 줄입니다.
  • 방화벽 룰은 태그/서비스 계정 기반으로 작성해 IP 변경 영향을 최소화합니다.

해결책 2: NAT로 우회(피어링 대신 변환 계층을 둠)

피어링은 “라우팅 공유”라서 대역이 겹치면 답이 없습니다. 이때는 직접 라우팅을 포기하고, 중간에서 주소를 바꾸는 방식이 필요합니다.

대표 선택지

  • Cloud VPN 또는 Cloud Interconnect 경로에서 NAT(온프레 장비나 가상 어플라이언스)
  • 서드파티 방화벽/라우터 어플라이언스에서 SNAT/DNAT

장점

  • 기존 대역을 바꾸지 않고도 연결 가능
  • 협력사/외부 조직과의 연동에서 특히 현실적

단점

  • 운영 복잡도 증가(상태 추적, 포트 고갈, 로그/트러블슈팅 난이도)
  • “원본 IP 보존”이 필요한 보안/감사 요구사항과 충돌 가능

설계 팁

  • 변환 대역은 충돌이 없는 “중간 대역”을 별도로 확보합니다.
  • 관측 가능성을 위해 NAT 로그를 남기고, 연결 추적 테이블 용량을 산정합니다.

해결책 3: PSC로 서비스 단위 연결(네트워크가 아니라 API를 연결)

전체 네트워크를 붙이는 대신, 필요한 서비스만 안전하게 노출하는 방식입니다.

언제 유리한가

  • 상대 VPC의 “일부 서비스”만 필요함(예: 내부 API, DB 프록시, 사내 패키지 레지스트리)
  • 대역 충돌이 심각하고 재설계가 불가능함
  • 보안상 최소 노출이 필요함

핵심 개념

  • 소비자 VPC는 PSC 엔드포인트를 만들고
  • 제공자 VPC는 서비스 첨부를 통해 특정 서비스만 게시합니다.

이 방식은 “전체 라우팅 공유”가 아니라 “서비스 엔드포인트 소비”에 가깝기 때문에, 피어링의 CIDR 충돌 문제를 회피하는 데 도움이 됩니다.

해결책 4: GKE secondary range 충돌만 정리해도 되는 경우

피어링 충돌이 “VPC 기본 서브넷”이 아니라 GKE Pod/Service CIDR에서만 발생하는 케이스가 많습니다.

예를 들어:

  • VPC A 서브넷은 10.50.0.0/16
  • VPC B 서브넷은 10.60.0.0/16
  • 그런데 VPC A의 GKE Pod secondary range가 10.60.0.0/14 같은 형태로 잡혀 있음

이 경우 피어링이 막히거나, 특정 목적지 라우트가 설치되지 않을 수 있습니다.

권장 패턴

  • 클러스터별로 Pod CIDR을 넉넉히 잡되, “조직 전체에서 유일”하게 관리합니다.
  • 클러스터 생성 전에 IP 계획을 먼저 확정합니다.

점검 포인트

  • 서브넷의 secondaryIpRanges 목록에 있는 CIDR까지 포함해 겹침을 계산
  • 멀티클러스터라면 클러스터 간 Pod CIDR 겹침도 확인

운영에서 자주 놓치는 함정들

1) 라우트 교환 옵션과 커스텀 라우트

피어링은 기본적으로 서브넷 라우트는 교환하지만, 커스텀 라우트/서로의 라우트를 어디까지 가져올지는 설정에 따라 달라집니다. “겹침이 없는데도 통신이 안 된다”면, 겹침 다음으로 이 옵션을 보세요.

  • Import custom routes
  • Export custom routes

단, 이건 겹침 문제를 해결해주지는 못합니다. 겹침이면 옵션을 바꿔도 본질은 같습니다.

2) 방화벽 룰은 되는데도 안 되는 이유

방화벽은 통과인데 라우팅이 잘못되면 패킷이 아예 목적지에 도달하지 않습니다. 이때는 방화벽보다 먼저 경로 선택이 문제입니다.

3) “일부만 된다”는 가장 위험한 신호

겹침이 부분 대역(예: /17/16 안에 포함)일 때, 특정 IP는 로컬로, 특정 IP는 피어로 잡히는 식의 비일관성이 생깁니다. 이런 상태로 운영하면 장애가 간헐적으로 터집니다.

실전 시나리오: 가장 현실적인 해결 순서

조직에서 흔히 선택하는 우선순위는 다음과 같습니다.

  1. 겹치는 CIDR 범위를 정확히 특정한다(서브넷 + secondary range)
  2. “바꿀 수 있는 쪽”을 정한다(신규/비핵심/마이그레이션 쉬운 VPC 또는 GKE)
  3. 전체 재설계가 어렵다면 서비스 단위는 PSC, 네트워크 단위는 NAT 우회를 검토
  4. 장기적으로는 IPAM과 표준 대역 정책을 수립해 재발을 막는다

장애 대응 관점의 체크리스트

  • 두 VPC의 모든 CIDR(서브넷, secondary range)을 수집했는가
  • 겹침이 “완전 동일”인지, “부분 포함”인지 구분했는가
  • 피어링이 ACTIVE여도 라우트가 실제로 설치되었는지 확인했는가
  • 임시 우회(NAT/PSC)로 비즈니스 영향부터 줄일 수 있는가

마무리

GCP VPC 피어링 실패의 상당수는 복잡한 설정 문제가 아니라 IP 대역 설계의 충돌에서 시작합니다. 특히 RFC1918 대역은 어디서나 흔하게 쓰이기 때문에, “우리만의 표준”이 없으면 언젠가 반드시 겹칩니다.

가장 좋은 해결은 CIDR 재설계지만, 현실적으로 어렵다면 NAT로 우회하거나 PSC로 필요한 서비스만 연결하는 방식이 실전에서 자주 쓰입니다. 중요한 건 “겹침을 방치한 채 피어링을 억지로 살리는 것”이 아니라, 라우팅 모호성을 제거해 예측 가능한 네트워크로 만드는 것입니다.

추가로 클라우드 환경에서 권한/정책/네트워크 경계 때문에 트러블슈팅이 꼬이는 경우도 많습니다. 접근 제어 관점의 진단 흐름은 S3 AccessDenied 403 진단 - 버킷 정책·SCP·VPCE 글의 사고방식도 같이 참고하면, “원인이 라우팅인지 정책인지”를 분리하는 데 도움이 됩니다.