클라우드플레어 터널(Zero Trust)로 포트 오픈 없이 내부 서버 안전 공개하기

방화벽 인바운드 포트를 열지 않아도 내부 서비스를 외부에 안전하게 노출할 수 있다. 핵심은 클라우드플레어 터널과 Zero Trust 정책이다. 외부 공격면을 줄이면서 운영 복잡도도 낮아진다.

클라우드플레어 터널은 어떻게 포트 없이 서버를 공개할까?

  • 원리: 내부에 설치된 cloudflared가 아웃바운드로 엣지에 TLS 터널을 연다. 외부에서 오는 요청은 엣지 → 터널 → 내부 서비스로 역방향 전달된다.
  • 이점
    • 방화벽 인바운드 0. 포트 스캔 무력화.
    • 고정 IP가 없어도 동작. NAT 환경에서도 문제없다.
    • Zero Trust Access와 결합해 SSO, MFA, 디바이스 posture로 접근 제어 가능.
  • 구성 요소
    • cloudflared: 서버에 설치하는 커넥터.
    • Tunnel ID/자격증명: 엣지와 상호 인증.
    • DNS/Route: 특정 도메인으로 들어온 요청을 터널로 연결.
    • Access 정책: 사용자·그룹별 접근 규칙.

시작 준비물과 설치

서버 시간이 NTP로 동기화되어야 인증 오류를 피할 수 있다.

단계별 설정 절차

1) Zero Trust 대시보드 진입

  • Cloudflare → Zero Trust → Access → Tunnels → Create a tunnel → Cloudflared 선택.

2) 서버에서 터널 생성 및 로그인

  • cloudflared tunnel login
    • 브라우저가 열리고 계정·도메인을 승인한다.
  • cloudflared tunnel create app-tunnel
    • 터널 UUID와 자격증명 JSON이 생성된다.

3) 라우팅(DNS) 연결

  • 예시: app.example.com으로 서비스 공개
  • cloudflared tunnel route dns app-tunnel app.example.com

4) 서비스 매핑 설정(config.yml)

  • 위치: ~/.cloudflared/config.yml (Windows는 %USERPROFILE%.cloudflared)
  • 예제
    • tunnel: <TUNNEL-UUID>
    • credentials-file: /home/ubuntu/.cloudflared/<TUNNEL-UUID>.json
    • ingress:
      • hostname: app.example.com
        service: http://localhost:3000
      • hostname: ssh.example.com
        service: ssh://localhost:22
      • service: http_status:404

설명

  • hostname별로 내부 서비스에 매핑한다.
  • 마지막 404 규칙은 누락된 경로 기본 처리용이다.

5) 서비스로 실행

  • Linux(systemd)
    • sudo cloudflared service install
    • sudo systemctl enable –now cloudflared
  • 수동 실행
    • cloudflared –config ~/.cloudflared/config.yml –no-autoupdate run
  • 상태 확인
    • cloudflared tunnel list
    • cloudflared tunnel info app-tunnel
    • 로그: journalctl -u cloudflared -f

6) Zero Trust Access로 보호(SSO/MFA)

  • Zero Trust → Access → Applications → Add an application → Self-hosted
  • Domain: app.example.com
  • 정책 예시
    • Include: Email ending in @company.com
    • Require: MFA, Device posture(관리 대상 PC), Country not in [차단국가]
  • SSH 보호
    • Application Type: SSH
    • 클라이언트: cloudflared access ssh –hostname ssh.example.com

7) 동작 확인

예시: 여러 마이크로서비스 노출

서버 보안을 더 단단하게 만드는 설정

  • 인바운드 폐쇄
    • 외부에서 80/443 포트를 닫고, 오직 cloudflared의 아웃바운드만 허용한다.
  • 기계 간 통신 보호
    • 서비스 토큰(Service Auth)로 백엔드·웹훅 같은 머신 트래픽을 인증한다.
  • 원본 TLS
    • 내부가 HTTPS만 허용이라면 service: https://localhost:8443로 지정.
    • 자체 서명 인증서 사용 시 NoTLSVerify 옵션 대신 신뢰 루트 관리로 해결한다.
  • WAF·봇 관리 연계
    • 도메인에 WAF 규칙을 적용해 L7 공격을 엣지에서 걸러낸다.
  • 레이트 리미트
    • Zero Trust Access 정책 또는 WAF Rate Limit으로 로그인 시도 과다를 억제한다.
  • 로깅
    • Ray ID, CF-Connecting-IP를 애플리케이션 로그에 포함하면 추적이 쉬워진다.

장애 해결과 주의사항(FAQ)

  • 접속은 되나 522/525/526 코드 표시
    • 522: cloudflared가 내부 서비스에 닿지 못함. 로컬 포트 확인, SELinux/iptables 확인.
    • 525/526: HTTPS 핸드셰이크 문제. 내부 서비스 인증서 체인 점검. 필요 시 HTTP로 우회해 진단.
  • DNS는 설정했는데 접속 불가
    • app.example.com이 proxy(주황 구름) 상태인지 확인.
    • 로컬 캐시/전파 지연. dig로 A/AAAA/CNAME 확인.
  • 회사망에서만 실패
    • 프록시·SSL 검열 장비가 443을 가로채는 경우가 있다. 예외 정책에 *.cloudflare.com 추가.
  • 자동 재시작 필요
    • systemd Restart=always, WatchdogSec 설정 권장.
  • 리소스 사용량
    • cloudflared는 경량이다. 트래픽이 많다면 커넥터를 2개 이상 분산.
  • 동적 IP 환경
    • 문제없다. 터널은 아웃바운드로 엣지에 재연결한다.
  • SSH 파일 전송
    • scp -o ProxyCommand=”cloudflared access ssh –hostname ssh.example.com” user@ssh.example.com:/path .
  • 쿠버네티스
    • cloudflared를 Deployment로 올리고 ConfigMap에 config.yml을 주입한다.

운영 팁과 성능 개선 아이디어

  • 커넥터 이중화
    • 다른 물리 서버 2대 이상에 같은 터널 연결. 한 대 장애 시 나머지가 처리.
  • 헬스체크
    • 내부 서비스 헬스 엔드포인트 마련. 5xx 증가 시 알림 연동.
  • 캐시/이미지 경로는 엣지로 처리
    • 정적 자원은 CDN 캐시를 활용해 원서버 부하를 줄인다.
  • 세분화된 Access 정책
    • 운영자(admin.example.com)는 회사 SSO+MFA, 고객 포털(app.example.com)은 이메일 도메인 필터 등으로 분리.
  • 로그 상관 분석
    • Ray ID를 애플리케이션 로그에 넣고, 장애 시 대시보드에서 동일 ID로 추적.

핵심 포인트 체크

  • 포트 개방 없이 터널로 안전하게 노출한다.
  • Access 정책으로 사용자·디바이스 조건을 엄격하게 통제한다.
  • 여러 호스트네임을 하나의 터널에 매핑해 운영 단계를 단순화한다.
  • 커넥터를 중복 배치해 장애에 대비한다.
  • 로그와 WAF를 엣지에서 먼저 활용해 서버 부담을 낮춘다.

댓글 남기기