배경
최신 origin/dev @ 90394932 기준 Generic HTTP provider는 URL 형식만 확인한 뒤 Workflow Worker에서 HTTP client를 직접 생성했다. 이 구조에서는 loopback, private network, link-local, cloud metadata, 혼합 DNS 응답과 DNS rebinding 목적지로 연결할 수 있었고, Worker 배포 계층의 보조 egress 방어도 없었다.
목표
Generic HTTP의 네트워크 진입점을 application outbound port로 단일화하고, URL·DNS·실제 dial을 하나의 정책 경계로 묶는다. Worker NetworkPolicy를 두 번째 방어선으로 적용해 애플리케이션 검증만으로 구성된 단일 방어선을 피한다.
확정 계약
- Generic HTTP node/provider는 socket 또는 HTTP client를 직접 생성하지 않고
OutboundHttpPort만 사용한다.
- 공통
OutboundEgressGuard가 모든 DNS 결과를 검사하고, 검증된 IP로 직접 dial한 뒤 실제 peer 일치를 확인한다.
- loopback, private, link-local, multicast, reserved, unspecified, cloud metadata와 IPv6 우회 범위를 fail-closed한다.
follow_redirects=false로 3xx를 기존 응답 그대로 반환하며 redirect 목적지로 추가 연결하지 않는다.
trust_env=false로 환경 proxy 우회를 막고 TLS 인증은 원래 hostname 기준으로 유지한다.
- method, port, timeout, header, request body와 response body 상한을 적용한다.
- 정책 거부는 요청 전 영구 실패, 전송 후 read/response 실패는 결과 불확실로 분류해 외부 효과 재시도 계약을 보존한다.
- Helm과 활성 EKS Worker manifest에 private·metadata 목적지를 제외하는 egress NetworkPolicy를 기본 적용한다.
- 차단 오류와 trace에는 safe reason code만 사용하고 raw URL query, header, body, credential과 resolved IP를 남기지 않는다.
구현 범위
- Workflow Engine application outbound HTTP port와 guarded HTTPX/httpcore adapter
- Generic HTTP provider 및 node composition 변경
- Shared egress address/header 검증 보강
- Helm 및 활성 EKS Worker NetworkPolicy
- ADR-0050과 Workflow 요구사항/API/component/test 계약
- SSRF, DNS TOCTOU, peer mismatch, 크기 제한, 외부 효과 phase와 배포 정책 회귀 테스트
완료 조건
- localhost, RFC1918, link-local, metadata, reserved, IPv6 local, 혼합 DNS와 peer mismatch가 요청 전에 차단된다.
- 검증된 IP로만 dial하고 hostname을 다시 해석하지 않는다.
- private redirect로 두 번째 요청이 발생하지 않는다.
- 정상 public 요청의 canonical request, provider response shape와 idempotency/retry 계약이 유지된다.
- Worker Helm과 활성 EKS manifest가 필요한 내부 service port와 승인된 public port만 허용하고 private·metadata 범위를 제외한다.
- 관련 테스트, Ruff, lock/diff 검사와 Helm default/production lint/render가 통과한다.
비범위 및 운영 한계
- 조직별 목적지 allowlist UI
- 모든 Connector, Knowledge, LLM outbound 경로의 일괄 이전
- 전용 egress proxy 또는 FQDN-aware CNI 도입
- private SaaS endpoint 예외 정책
- Generic HTTP public API·DB schema·정상 응답 shape 변경
표준 Kubernetes NetworkPolicy만으로 public 허용 port의 모든 direct dial을 proxy-only로 강제할 수는 없다. 배포 cluster가 NetworkPolicy를 집행하는 CNI를 사용하는지, 동일 Worker selector에 allow-all 정책이 없는지는 별도 운영 점검이 필요하다.
구현 PR
배경
최신
origin/dev @ 90394932기준 Generic HTTP provider는 URL 형식만 확인한 뒤 Workflow Worker에서 HTTP client를 직접 생성했다. 이 구조에서는 loopback, private network, link-local, cloud metadata, 혼합 DNS 응답과 DNS rebinding 목적지로 연결할 수 있었고, Worker 배포 계층의 보조 egress 방어도 없었다.목표
Generic HTTP의 네트워크 진입점을 application outbound port로 단일화하고, URL·DNS·실제 dial을 하나의 정책 경계로 묶는다. Worker NetworkPolicy를 두 번째 방어선으로 적용해 애플리케이션 검증만으로 구성된 단일 방어선을 피한다.
확정 계약
OutboundHttpPort만 사용한다.OutboundEgressGuard가 모든 DNS 결과를 검사하고, 검증된 IP로 직접 dial한 뒤 실제 peer 일치를 확인한다.follow_redirects=false로 3xx를 기존 응답 그대로 반환하며 redirect 목적지로 추가 연결하지 않는다.trust_env=false로 환경 proxy 우회를 막고 TLS 인증은 원래 hostname 기준으로 유지한다.구현 범위
완료 조건
비범위 및 운영 한계
표준 Kubernetes NetworkPolicy만으로 public 허용 port의 모든 direct dial을 proxy-only로 강제할 수는 없다. 배포 cluster가 NetworkPolicy를 집행하는 CNI를 사용하는지, 동일 Worker selector에 allow-all 정책이 없는지는 별도 운영 점검이 필요하다.
구현 PR