Go로 구현한 PEP / PDP / PIP 구조의 TLS MITM 정책 프록시. WireGuard 터널 끝단에서 클라이언트 트래픽을 투명하게 가로채 SNI·host·path·method·header 단위로 allow / deny / log를 적용한다.
웹(HTTP/1.1, HTTP/2) enforcement gateway에 초점.
Ubuntu EC2 + macOS WireGuard 클라이언트 환경에서 end-to-end 검증됨.
- 투명 프록시 — TUN 디바이스 + gVisor 유저스페이스 TCP/IP 스택. 커널 모듈·애플리케이션 수정 불필요
- TLS MITM — SNI 기반 leaf cert 동적 발급 + 호스트별 캐시, ALPN으로 HTTP/1.1·HTTP/2 자동 분기
- 정책 엔진 — hosts, SNI, path, method, source/dest IP, port, header 조건 · glob·CIDR 매칭 · priority 기반 first-match
- 두 가지 동작 모드 —
local(명시적 HTTP 프록시),tun(투명 프록시) - Linux host 배포 자산 — systemd unit, WireGuard 예시, 설치/점검/원복 스크립트, nftables·sysctl
프록시와 WireGuard 클라이언트가 별도 컨테이너로 분리된 환경. 로컬을 건드리지 않고 정책 동작을 확인한다.
./docker/gen-keys.sh # 최초 1회: WireGuard 키 생성
docker compose up --build # 빌드 + 실행
docker exec -it zt-client /test.sh # 정책 검증검증 환경: Ubuntu EC2 + macOS WireGuard 클라이언트.
- Ubuntu EC2, 퍼블릭 IPv4 활성화
- 보안 그룹 인바운드:
22/tcp(for SSH),51820/udp(for WireGuard) (My IP) - 아웃바운드 기본값 (전부 허용)
이 서버는 WireGuard 종단점 + 프록시 게이트웨이다. 80/443 공개 불필요.
ssh ubuntu@<EC2_IP>
git clone https://github.com/khs-alt/zero-trust-proxy.git
cd zero-trust-proxy
sudo ./deploy/linux/install.sh
sudo ztproxy-check # wg0, ztun0, systemd 상태 확인클라이언트 앱 설치: https://www.wireguard.com/install/
서버에서 — 서버 공개키 확인:
sudo cat /etc/wireguard/server.pub클라이언트에서 — 키 생성:
wg genkey | tee client.key | wg pubkey > client.pub서버 /etc/wireguard/wg0.conf 파일에 peer 추가 후 적용:
[Peer]
PublicKey = <client.pub 내용>
AllowedIPs = 10.20.0.2/32
PersistentKeepalive = 25sudo systemctl restart wg-quick@wg0클라이언트 설정:
[Interface]
Address = 10.20.0.2/24
PrivateKey = <client.key 내용>
DNS = 1.1.1.1
[Peer]
PublicKey = <server.pub 내용>
Endpoint = <EC2_IP>:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25HTTPS MITM을 위해 서버 루트 CA를 클라이언트가 신뢰해야 한다.
scp ubuntu@<EC2_IP>:/var/lib/ztproxy/ca.crt .
# macOS: Keychain Access → 시스템 키체인에 추가 → Always Trust → 브라우저 모두 종료 후 재시작
/var/lib/ztproxy/ca.key는 절대 외부 반출 금지. Chrome 계열은 테스트 중 QUIC/HTTP/3 비활성화 권장.
# 클라이언트
curl ifconfig.me # EC2 공인 IP가 나와야 함
curl https://example.com # 허용
curl https://naver.com # 차단 (기본 정책)
# 서버
sudo wg show # latest handshake / transfer 확인현재 기본 도메인은 naver.com과 facebook.com가 있기에 wireguard 활성화 후 두 도메인만 접속 불가능하면 설정 완료
설정 파일은 config/policies.yaml 참고
sudo ztproxy-uninstallmacOS에서 명시적 HTTP 프록시로만 돌리고 싶을 때:
go run ./cmd/ztproxy/ -config ./configs/config.yaml
sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain ./certs/ca.crt
networksetup -setwebproxy Wi-Fi 127.0.0.1 8080
networksetup -setsecurewebproxy Wi-Fi 127.0.0.1 8080종료 시 반드시 프록시 해제 (networksetup -setwebproxystate Wi-Fi off, -setsecurewebproxystate Wi-Fi off).
전체 키는 configs/config.yaml 참고. 핵심:
| 키 | 기본값 | 설명 |
|---|---|---|
proxy.mode |
local |
local 또는 tun |
proxy.listen_addr |
:8080 |
local 모드 리슨 주소 |
proxy.cert_cache_ttl |
1h |
MITM leaf cert 캐시 TTL |
tun.name |
"" |
TUN 이름 (Linux host는 ztun0 고정 권장) |
policy.default_action |
allow |
매칭 규칙 없을 때 동작 |
ca.auto_generate |
true |
CA 없으면 자동 생성 |
# configs/policies.yaml
rules:
- name: "block-naver"
action: "deny"
priority: 10
conditions:
snis: ["naver.com", "*.naver.com"]priority가 낮을수록 먼저 평가되며, 첫 매칭 규칙의 action이 최종 결정.
| 조건 | 매칭 | 예시 |
|---|---|---|
hosts, snis, paths, headers |
glob | *.example.com |
source_ips, dest_ips |
CIDR | 10.0.0.0/8 |
methods |
정확 일치 | GET |
dest_ports |
정확 일치 | [80, 443] |
액션: allow · deny · log.
cmd/ztproxy/ 진입점
internal/
cert/ CA + 호스트별 cert 캐시
config/ YAML 로드
netstack/ gVisor TCP/IP 스택
policy/ PEP, PDP, PIP, Rule
proxy/ dispatcher, TLS MITM, HTTP/1.1, HTTP/2, passthrough, UDP
tundev/ TUN 디바이스 + netstack 브릿지
configs/ config*.yaml, policies.yaml
deploy/linux/ systemd, 설치/점검/원복 스크립트
docker/ WireGuard + E2E 테스트 환경
Go 1.25.5+.
go build -o ztproxy ./cmd/ztproxy/이 프로젝트는 웹 중심 zero-trust data plane prototype이다.
- HTTP/1.1, HTTP/2 기반 웹 트래픽만 검증됨
- 현재 QUIC / HTTP/3 미지원 -> 추후 지원 예정
- APNS,
mtalk.google.com등 비웹 TLS 프로토콜은 handshake 실패 가능 - 상용 VPN 대체 목적이 아님 — 범용 터널링이 아닌 웹 트래픽 enforcement gateway