--- kind: PROJECT_DECISION slug: no-public-tunnel-because-a-third-hop-pollutes-the-measurement title: 공개 터널을 쓰지 않고 tailnet 직결로 둔다 — 홉이 하나 늘면 재려던 계약이 오염된다 topic: lab-entry-path-and-measurement-integrity topicName: 실험대의 진입 경로 project: virtualization status: 게시 전 decisionStatus: ADOPTED sourceRevision: 9465582b5d1630eb4ae7c4e078021486919bf6b6 source: - final/document.md#305-tunnel-채택하지-않은-이유를-남긴-자산 - final/document.md#302-왜-적용하지-않는-것을-남겨두는가 - final/document.md#300-9층-deploy-무엇이-살아-있고-무엇이-참조인가 - final/document.md#301-전체-지도 --- # 공개 터널을 쓰지 않고 tailnet 직결로 둔다 — 홉이 하나 늘면 재려던 계약이 오염된다 Cloudflare named tunnel 을 앞에 붙이면 브라우저에서 파드까지가 3홉이 되고, 이 실험대가 재려는 것이 정확히 2홉의 forwarded 헤더 계약이라 측정이 오염된다. 그래서 tailnet 직결로 두고 터널 설정 파일은 채택하지 않은 선택지로 남긴다. ## 근거 §305 가 `deploy/` 아래의 `tunnel/cloudflared-config.yml` 을 두고 채택하지 않았다고 적으면서 기각 이유를 전후 홉 그림으로 남겼다. 기각한 파일을 지우지 않는 방침은 §300 부터 §302 에 따로 있다. 저장소에 있으나 적용되지 않는 설정이 여럿인데, 그것들이 죽은 코드가 아니라 의도적으로 남겨 둔 참조 자산이라고 전체 지도와 함께 적는다. - **L7 이 두 겹인 이유와, 진입점 하나를 이중화하려 할 때 끝나지 않는 재귀** 이 결정이 지키려는 2홉이 무엇이고 그 둘의 역할이 왜 다른지를 그 글이 설명한다. - **신뢰 경계에서는 forwarded 헤더를 덧붙이지 않고 덮어쓴다** 앞에 한 겹이 더 붙으면 경계가 Cloudflare 엣지로 옮겨 가 그 기준을 거기서 다시 세워야 한다. - **인증서는 DNS-01 로 받는다 — 실험대 주소가 공개 인터넷에 없어 HTTP-01 이 성립하지 않는다** 이 결정이 청구한 비용 하나를 그 결정이 받는다. - **엣지 nginx 를 호스트에서 게스트 VM 으로 옮긴다 — 성능이 아니라 더러워지는 층의 격리** 같은 2홉을 지킨 채 엣지의 위치만 바꾼 결정이라 홉 수를 건드리지 않는다. - **이 실험대의 certbot 은 HTTP-01 로 받고 있는가 DNS-01 로 받고 있는가** 재구축 때 인증서 디렉터리를 지워도 되는지가 그 물음에 걸려 있다. ## 결정문 공개 터널을 쓰지 않고 tailnet 직결로 둔다. 기각한 설정 파일 `tunnel/cloudflared-config.yml` 은 지우지 않고 채택하지 않은 선택지로 남긴다. 조건이 바뀌어 공개 접근이 필요해지면(예를 들어 다른 회선으로 이전) 그 파일을 그대로 쓴다. ## 판단 이유 Cloudflare named tunnel 은 아웃바운드 연결만 쓰므로 포트포워딩 없이 공개 HTTPS 이름을 얻는다. 공유기를 건드릴 수 없는 환경에서는 매력적인 선택지이고, §305 는 그 설정의 함정 둘까지 적어 두었다. `service:` 에 `127.0.0.1` 을 쓰면 cloudflared 컨테이너 자신을 가리키므로 Compose 서비스 DNS 이름을 써야 하고, 마지막 catch-all 이 없으면 오류가 난다. 기각 근거는 홉 수다. 터널을 쓰면 브라우저가 Cloudflare 엣지와 nginx 와 Traefik 을 지나 파드에 닿아 3홉이 된다. 지금은 브라우저가 nginx 와 Traefik 만 지나 파드에 닿는 2홉이다. Cloudflare 엣지가 TLS 를 끊고 다시 맺으면서 HTTP 를 읽는 홉이 하나 늘고 `CF-Connecting-IP` 같은 자체 헤더가 섞인다. 이 실험대가 측정하려는 것이 정확히 `nginx → Traefik` 2홉의 forwarded 헤더 계약이므로, 앞에 한 겹이 더 붙으면 측정이 오염된다. 터널이 무엇을 해 주는지가 아니라 그것이 이 실험대의 측정 대상에 무엇을 하는지를 보고 정했다. ## 영향 진입 경로가 2홉으로 고정된다. 밖에서 들어오는 요청을 처음 받는 프록시가 하나뿐이라 신뢰 경계가 한 곳이고, forwarded 헤더를 누가 쓰는지가 갈리지 않는다. 감수한 비용은 진입 주소다. `dig` 가 내놓는 `100.83.212.4` 는 `100.64.0.0/10` 안에 있고 그 대역이 CGNAT 용으로 예약돼 있어 공개 인터넷에서 라우팅되지 않는다. 그 대가가 두 곳에서 청구됐다. 인증서 발급 : HTTP-01 로 받을 수 없어 DNS-01 로 갔다 재구축 : 인증서 디렉터리 `/etc/letsencrypt/` 를 지워도 되는지가 미확정이다 기각한 파일을 지우지 않는 방침에도 근거가 셋 있다. ① 저장소의 목적이 비교다 : 선택지를 나란히 두고 트레이드오프를 적는 것 자체가 산출물이라, 하나만 남기면 왜 이것을 골랐는지를 뒷받침할 근거가 없어진다 ② 죽은 코드가 아니라 테스트되는 코드다 : `scripts/verify-public-tunnel-config.sh` 가 붙어 있어 실행되지 않을 뿐 깨지면 드러난다 ③ 실험대 전용 설정은 `lab/` 아래로 분리했다 : 일반 배포 설정과 섞이지 않는다 재지 않은 것도 있다. 터널을 붙인 상태와 지금을 같은 방법으로 잰 비교는 이 저장소에 없다. 기각의 근거는 홉 수와 섞이는 헤더이지 두 구성을 재서 견준 값이 아니다. 인증서를 지금 어느 방식으로 받고 있는지도 이 실험대에서 아직 재지 않았다.