Loading...
태그
    cloudflarecloudflare-tunnelcloud-securitydevopsreverse-proxy

Cloudflare Tunnel로 GCP VM 웹 서비스 보안 구축

최종수정일
2026년 02월 15일
4분걸림
작성자: Techy J
Table of Content (목차)

이 글은 Cloudflare Tunnel과 GCP VM 환경에서 웹 UI 보안을 구축하기 위한 아키텍처와 작동 원리를 정리한 문서이다. 특히 Docker 컨테이너 환경에서 Cloudflare Tunnel이 내부 서비스와 어떻게 통신하는지, 그리고 왜 VM의 모든 외부 인바운드 포트를 차단한 상태에서도 서비스 제공이 가능한지를 설명한다.

Cloudflare Tunnel을 사용하는 목적

  • 외부 인바운드 포트 완전 차단 : VM의 모든 외부 인바운드 포트를 차단해도 서비스 접근 가능 (GCP 방화벽에서 80, 443 포트까지 차단 가능)
  • 자동 암호화 : 별도의 SSL 인증서 설정 없이 Cloudflare와 VM 간 암호화된 Tunnel 자동 생성
  • Zero Trust 보안 모델 구현: VM은 Cloudflare로만 아웃바운드 연결을 생성하며, 외부에서 직접 접근 가능한 경로가 존재하지 않음
  • IP 노출 방지: DNS는 Cloudflare IP만 가리키고 실제 VM IP는 외부에 노출되지 않음
  • 운영 단순화: cloudflared 에이전트만 실행하면 복잡한 네트워크 설정 없이 서비스 공개 가능

전체 아키텍처 개요 (Cloudflare + GCP + Docker)

전체 트래픽 흐름은 다음과 같다.

Cloudflare Tunnel을 사용할 경우, Cloudflare Edge와 VM 내부의 cloudflared 컨테이너 간 연결은 공용 인터넷을 경유하지만 암호화된 Tunnel로 보호된다.
이 구조에서는 외부에서 VM으로 직접 접근 가능한 네트워크 경로가 존재하지 않으며, 보안 관점에서 논리적으로 private 네트워크와 유사한 효과를 제공한다. Cloudflare에 등록된 도메인에 접속하면 사용자는 Cloudflare IP만 보게 되며, 실제 VM IP는 은닉된다. VM은 외부 요청을 직접 수신하지 않는다.

GCP 방화벽에서 모든 인바운드 포트를 차단하고, Cloudflare Tunnel만 허용함으로써 외부의 직접 접근을 원천적으로 제거할 수 있다.

Cloudflare SSL 모드와 Tunnel의 관계

Cloudflare에 DNS를 등록하면 SSL 모드를 선택하게 되며, 이는 사용자 ↔ Cloudflare 구간과 Cloudflare ↔ VM 구간의 TLS 동작 방식을 정의한다.

  • Flexible: 사용자 ↔ Cloudflare: HTTPS , Cloudflare ↔ VM: HTTP
  • Full / Full (Strict): 전체 구간 HTTPS (VM에 SSL 인증서 필요) Cloudflare Tunnel은 SSL 모드와 별도의 개념으로, 연결 방식(네트워크 아키텍처) 자체를 변경한다.
    Tunnel을 사용할 경우 Cloudflare와 VM은 암호화된 터널로 연결되며, VM의 외부 인바운드 포트는 필요하지 않다.
구간FlexibleFull / Tunnel 사용 시보안 상태
사용자 ↔ CloudflareHTTPSHTTPSSSL, DDoS, WAF 보호
Cloudflare ↔ VMHTTPHTTPS (Tunnel)Tunnel 사용 시 가장 안전

Cloudflare Tunnel의 작동 원리

  • Outbound Tunnel: VM 내부의 cloudflared 서비스가 Cloudflare로 지속적으로 연결을 유지, 외부에서 VM으로 직접 들어오는 연결은 존재하지 않음
  • DNS 기반 라우팅: 도메인은 VM IP가 아닌 Cloudflare IP를 가리킴
  • Reverse Proxy 구조: 모든 요청은 Cloudflare를 거쳐 Tunnel을 통해 내부 서비스로 전달됨
  • Authentication (Cloudflare Access 사용 시): Cloudflare Access를 적용하면 인증 정책을 통과한 요청만 Tunnel로 전달됨 이 구조를 통해 실제 서버 IP 은닉, DDoS 트래픽 사전 차단, 공격 표면 최소화가 가능하다.
    외부 사용자에게는 HTTPS를 제공하면서 VM 내부 서비스는 HTTP로 운영할 수 있다.

Cloudflare Tunnel 사용설정

Cloudflare API Token 생성

Cloudflare 대시보드의 API Tokens 메뉴에서 Custom Token을 생성한다.

권한 설정:

  • Account / Cloudflare Tunnel / Edit
  • Zone / DNS / Edit

Zone Resource에는 다음 중 하나를 선택한다.

  • 특정 도메인 선택 또는
  • All zones from an account

토큰 생성 후 다음 값이 필요하다.

  • CLOUDFLARE_API_TOKEN
  • ACCOUNT_ID

토큰 검증:

curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/tokens/verify" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"

Tunnel 생성

curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/cfd_tunnel" \
  --request POST \
  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  --json '{
    "name": "api-tunnel",
    "config_src": "cloudflare"
  }'

결과로 TUNNEL_ID와 TUNNEL_TOKEN이 반환된다.

Tunnel ingress 설정

Tunnel에 대해 호스트네임과 내부 서비스 URL을 매핑한다.

curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/cfd_tunnel/$TUNNEL_ID/configurations" \
  --request PUT \
  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  --json '{
    "config": {
        "ingress": [
            {
                "hostname": "app.example.com",
                "service": "http://telenode:3000"
            },
            {
                "service": "http_status:404"
            }
        ]
    }
  }'

Cloudflare는 호스트네임에 대해 설정된 Tunnel로 요청을 전달하고, cloudflared 컨테이너는 해당 요청을 내부 서비스 URL로 프록시한다.

Docker 환경에서 컨테이너 통신 구조 (docker-compose.yml)

docker-compose.yml에 정의된 서비스들은 동일한 브리지 네트워크에 속하며, 컨테이너 이름은 내부 DNS로 자동 등록된다. 따라서 ports: 설정 없이도 cloudflared 컨테이너는 http://telenode:3000과 같이 접근 가능하다. 이 구조에서는 외부에 서비스 포트를 노출할 필요가 없으며, Cloudflare를 경유하지 않은 직접 접근은 차단된다. Tunnel은 ingress 설정에 정의된 서비스 URL의 포트로 요청을 전달하므로, 서비스는 해당 포트에서 listen 해야 한다. 이 애플리케이션이 WEB_PORT 환경변수를 사용하도록 구현된 경우 다음과 같이 설정한다.

services:
  telenode:
    image: telenode-img
    container_name: telenode-container
    environment:
      - WEB_PORT=3000
    env_file:
      - .env
    restart: unless-stopped
 
  tunnel:
    image: cloudflare/cloudflared:latest
    container_name: cloudflared-tunnel
    command: tunnel run
    environment:
      - TUNNEL_TOKEN=${TUNNEL_TOKEN}
    restart: unless-stopped

운영 환경에서는 ports: 설정을 제거하여 외부 포트 노출을 완전히 차단한다.

로컬 개발 환경 설정 (docker-compose.override.yml)

로컬 테스트 시에만 포트를 개방한다.

services:
  telenode:
    ports:
      - "3000:3000"

docker-compose.override.yml은 자동 병합되므로 운영 환경에는 배포되지 않도록 .gitignore에 포함시킨다.

Cloudflare Tunnel을 이용한 이 구조는 다음을 만족한다.

  • VM 인바운드 포트 0개
  • Cloudflare 단일 진입점
  • Zero Trust 보안 모델 구현
  • Docker 내부 네트워크 기반 서비스 연결
  • HTTPS 제공과 내부 HTTP 운영 분리

즉, 서버를 인터넷에 직접 노출하지 않고도 웹 서비스를 안전하게 제공하는 아키텍처이다.

(끝)

이 글은 ' 출처: 변호사 전정숙 '과 ' 원본링크: https://www.korean-lawer.com/articles/iaas/cloudflare-tunnel-gcp-vm-docker-zero-trust'를 명시하는 조건으로 인용가능 합니다.
무단 복제, AI 학습 목적으로의 사용과 Google, Naver의 Indexing 외 크롤링 금지합니다
About
전정숙 변호사
법무법인 정맥 파트너 변호사부산파산법원 파산관재인전) 부산변호사회 부회장전) 전국여성변호사회 부회장전) 부산 가정법원 조정위원
Contact

(82) 051-916-8582 , 051-916-8583

부산광역시 연제구 법원로 12 (거제동)

로윈타워빌딩 2층 법무법인정맥

변호사 전정숙

© 2005-2026 전정숙 변호사.

All Rights Reserved.