homelab89 Docs Logs Legacy Files ☰ TOC 🌓
notenetworking 2026-07-22squidforward-proxyproxyhttp-connectacltunnelingaccess-log

Squid 학습 노트 — 프록시는 두 모드로 산다 (L0·L1)

원본은 실측 기반 학습 노트 HTML

이 글의 본체는 학습 노트 전문이다. 배치도·모드 비교 시퀀스·first-match 계단 다이어그램 3종, 실측 출력 9건, 운영 함정 5건, 확인 질문 6문(정답 접기)을 포함한다. 모든 출력은 Ubuntu 24.04 + Squid 6.14 컨테이너 실측값.

→ 전문 보기 (squid-study-l0-l1.html)

이 페이지는 핵심 요약본.

한 문단 요약

프록시는 두 모드로 산다. 대상이 http://면 Squid는 absolute-form 요청 라인을 끝까지 파싱하는 완전한 중간자다 — URL 수준 ACL·캐시가 가능하고, origin-form으로 재작성하며 Via/X-Forwarded-For를 붙여 오리진이 받는 바이트 자체가 달라진다. 대상이 https://면 클라이언트가 TLS 시작 전에 CONNECT host:443을 보내고, Squid는 ACL 판정·DNS resolve까지만 개입한 뒤 양방향 바이트 복사기가 된다(TLS는 클라이언트↔오리진 end-to-end — 증거는 curl에 오리진 인증서 CN=origin.lab이 그대로 보인다는 것). “아무것도 못 본다"가 아니라 개입이 시간 축으로 나뉜다는 것이 정확한 표현이다. 정책 쪽(L1)의 전부는 acl(어휘)과 http_access(문장)의 분리, 그리고 값 OR → 줄 AND → 줄간 first-match라는 3층 평가에 숨은 4번째 규칙 — 무매치 시 마지막 줄의 반대가 암묵 기본값 — 이다. deny all을 항상 명시하는 이유가 여기 있다.

구성

레벨 주제 핵심
L0 forward proxy와 CONNECT의 실체 request-target 3형태, TCP 두 개 독립·DNS는 Squid의 몫, 두 동작 모드, 실측 4실험
L1 squid.conf 해부 — ACL과 first-match 정의/사용 분리, 3층+암묵 기본값, dstdomain 선행 점·rDNS, 실습 5건
QR 치트시트 운영 반사신경 7건

L0 핵심 압축

  • 왜 존재하는가 — 보안망은 직접 외부 연결을 금지하고 단일 관문만 연다. 관문이 하나로 모이면 정책(허용 도메인)·감사(접속 로그)·캐시가 따라온다. forward proxy = 클라이언트의 대리인, reverse proxy = 서버의 대리인 — nginx/Envoy로 익숙한 쪽은 후자, Squid의 본업은 전자.
  • 프록시 요청은 별도 프로토콜이 아니다 — 그냥 HTTP이고, 다른 것은 request-target 형태 하나(RFC 9112):
형태 예시 언제
origin-form GET / HTTP/1.1 서버에 직접 (평소)
absolute-form GET http://origin.lab/ HTTP/1.1 프록시에 http:// 요청
authority-form CONNECT origin.lab:443 HTTP/1.1 프록시에 터널 요청
  • HTTP_PROXY는 OS 기능이 아니라 라이브러리 관례 — curl·requests·Go는 읽고 Java는 기본 무시(-Dhttp.proxyHost). https_proxy는 “https:// URL에 쓸 프록시"라는 선택 기준이고, 프록시 자체와의 연결은 두 경우 다 보통 평문 http.
  • 배치: TCP 두 개, DNS는 Squid의 몫 — 클라이언트는 프록시 주소만 resolve한다. 목적지 이름은 요청 라인에 문자열로 실려 가고, resolve는 Squid가 한다. TCP #1(클라→프록시)과 #2(프록시→오리진)는 완전히 독립 — keep-alive 재사용도 타임아웃도 각자 간다.

실측 4실험이 증명한 것

실험 관찰 증명
A curl -v에 GET http://origin.lab:8080/ HTTP/1.1 목적지가 요청 라인 안에 (absolute-form)
B 200 Connection established 후 TLS 시작, 인증서 CN=origin.lab TLS는 터널 “안에서”, end-to-end
C tcpdump 오리진 도착분에 Via·X-Forwarded-For 모드 1은 재작성 — 클라가 보낸 적 없는 헤더 추가 (내부 IP 노출)
D 터널 12초 유지 중 로그 0줄 → 종료 후 1줄, elapsed=11970ms CONNECT 로그는 종료 시점의 부검 기록. 바이트 필드 = Squid가 클라 방향으로 보낸 총량

L1 핵심 압축

  • 정의와 사용의 분리acl은 조건에 이름을 붙이는 정의, http_access는 이름을 조합한 판정 규칙. 같은 ACL을 ssl_bump·cache·cache_peer_access 등 다른 판정 지시자도 재사용한다. acl 정의 줄끼리는 순서 무의미, http_access 줄들은 순서가 전부.
  • 평가 4규칙 — ① ACL 내부 값들은 OR ② 한 줄 위 ACL들은 AND(!=부정) ③ 줄들 사이는 first-match 즉시 종결 ④ 무매치면 마지막 줄의 반대가 암묵 기본값. 운영 설정이 전부 http_access deny all로 끝나는 이유 = ④에 보안을 맡기지 않기 위해서.
  • dstdomain 세부.origin.lab(선행 점)은 자신+모든 서브도메인, origin.lab은 정확히 그 호스트만. URL에 IP가 오면 rDNS로 도메인화해 비교를 시도하는데, 실제 인터넷 PTR은 대개 클라우드/ISP 이름이라 매칭 실패 → 403. rDNS는 slow ACL이라 지연도 얹힌다.

실습 5건이 증명한 것

  • dead rule 실측 — 광범위 allow 아래의 deny는 죽어 있다(차단 대상이 200). deny를 위로 올리면 403. TCP_DENIED + HIER_NONE(오리진에 아예 안 나감) = 403의 발원지는 Squid 정책이라는 판독 공식.
  • 암묵 기본값 실측 — allow가 하나도 없는 설정에서 200이 나온다. 마지막 줄이 deny라 기본값이 allow가 된 것 — deny 규칙으로만 채운 방화벽은 문이 열려 있는 상태.
  • 문법 검증기 — 정의 안 된 ACL 참조는 FATAL: Bungled. 이 설정으로 restart하면 Squid가 아예 안 뜬다(reload는 기존 설정으로 버팀). 절차는 항상 squid -k parse → reload.
  • rDNS 도박 실측 — 같은 랩에서 127.0.0.2는 403인데 127.0.0.1은 200 — /etc/hosts 덕에 rDNS가 origin.lab을 돌려줬기 때문. dstdomain의 IP 매칭은 내가 통제하지 않는 PTR 레코드에 의존하는 도박.

운영 함정 5건

ID 함정 증상 / 통제
0.A NO_PROXY 해석은 구현마다 다르다 같은 NO_PROXY인데 특정 언어 앱만 내부 트래픽이 Squid로 흘러 403/지연
0.B Via·X-Forwarded-For 정보 유출 내부 IP·프록시 호스트명이 외부 오리진에 전달. via off·forwarded_for delete
0.C 장수 터널은 로그에 안 보인다 살아있는 CONNECT는 로그 0줄 — “로그에 없다 = 트래픽 없다"는 오판. 장애 시 로그 폭주도 같은 원리
1.A 죽은 규칙(dead rule) “차단했는데 여전히 접속” = 위쪽 광범위 allow가 선점. 추가할 위치가 내용보다 어렵다
1.B 앱이 IP로 호출 rDNS가 기대 도메인을 안 주는 한 403. access.log URL 필드에 IP가 찍혀 있으면 이 케이스

치트시트

반사신경 내용
평가 3층 값 OR → 줄 AND(!=부정) → 줄간 first-match. 무매치면 마지막 줄의 반대
403 + HIER_NONE 거부의 발원지는 오리진이 아니라 Squid 정책(ACL)
CONNECT 로그 터널 종료 시 기록. elapsed=터널 수명, 바이트=클라 방향 전달 총량
dstdomain .d.com=자신+서브도메인, d.com=정확히 그 호스트. IP 요청은 rDNS 의존
설정 변경 절차 squid -k parse(문법) → squid -k reconfigure(reload). FATAL 설정으로 restart 금지
프록시 경유 테스트 curl -v -x http://proxy:3128 URL — 요청 라인 형태(absolute/CONNECT)부터 본다
env 변수 라이브러리 관례일 뿐(Java는 무시). https_proxy=https:// URL용 프록시. no_proxy 파싱은 구현차

확인 질문 (인출 연습)

원문에 L0 3문 + L1 3문이 정답 접기와 함께 있다 — 특히 L1의 3-ACL conf 판정 문제(줄 번호까지 답하기)는 first-match 체화용. 원문에서 풀기

관련 문서

Files