Files
llm-wiki/raw/branch-notes/feature-keycloak-header-spoofing-defense.md

36 KiB

title, source_type, status, id, kind, project, work_item, inherits, refines, overrides, depends_on, contract_packet, branch, parent_branch, related_projects, tags, created, target_merge, status_label, contract_packet_sha256
title source_type status id kind project work_item inherits refines overrides depends_on contract_packet branch parent_branch related_projects tags created target_merge status_label contract_packet_sha256
branch / feature-keycloak-header-spoofing-defense (P1A — 헤더 spoofing 방어, Network 경계 강제) branch-note raw BR-KEYCLOAK-PATTERNS-OVERVIEW-014 project-work-item keycloak-patterns-overview WI-KEYCLOAK-PATTERNS-OVERVIEW-014
DEC-KEYCLOAK-PATTERNS-OVERVIEW-EDGE-FORWARDAUTH-001@1
DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1
WI-KEYCLOAK-PATTERNS-OVERVIEW-012
1 feature-keycloak-header-spoofing-defense
keycloak-patterns
branch
keycloak-patterns
p1a
network-policy
security-group
header-spoofing
zero-trust
2026-05-25 in-progress 2bdbf4639b4e61ad38f9f32504f877dd87ad84f8f07523fd0c874bc316c1ae79

branch: feature-keycloak-header-spoofing-defense (P1A — 헤더 spoofing 방어, Network 경계 강제)

Layer: raw/branch-notes/raw/project-notes/keycloak-patterns-overviewWI-KEYCLOAK-PATTERNS-OVERVIEW-014 직접 branch. P1A 패턴이 깨지는 유일하고도 가장 흔한 경로 — backend가 ingress 우회 경로로 도달 가능할 때 — 의 방어 메커니즘을 정리. K8s NetworkPolicy, EC2 Security Group, mTLS, shared-secret 헤더 검증 4가지를 비교. 본 sub-sub-branch는 문서까지만 (documented-only). status_label: in-progress

부모 (필수)

raw/project-notes/keycloak-patterns-overview

브랜치 계약 패킷

  • 생성 시 프로젝트 개정: 1
  • 패킷 스키마: contract_packet: 1
  • 완료 조건: forwarded-user spoofing 우회를 재현하고 network isolation 후 차단한다

상속한 프로젝트 결정

Decision Ref Project Summary Branch Application Source
DEC-KEYCLOAK-PATTERNS-OVERVIEW-EDGE-FORWARDAUTH-001@1 AP4는 oauth2-proxy ForwardAuth를 사용한다 forwarded identity header의 신뢰 경계와 network isolation에 적용한다 raw/project-notes/keycloak-patterns-overview
DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1 done-bar는 E2E success와 signature security failure 재현·해결 evidence다 spoofing 우회 재현과 차단 evidence를 완료 조건으로 사용한다 raw/project-notes/keycloak-patterns-overview

브랜치 지역 결정

기존 branch-local 결정은 아래 ## Decision Evidence Map의 D-row가 소유하며 이 packet에서 복제하지 않는다.

Decision ID Decision Relation Supporting Claims Status

선언한 예외

Override ID Overrides Reason Approval Status

없음.

목표

P1A의 단점 섹션(부모 sub-branch §장점/단점)에서 가장 먼저 등장하는 문제는 헤더 spoofing이다. backend는 X-Auth-Request-User: alice 헤더를 oauth2-proxy가 붙였다고 믿고만 동작하므로, ingress를 우회해 backend에 직접 접근할 수 있는 경로가 하나라도 있으면 패턴 전체가 무너진다.

본 sub-sub는 이 단일 위협에 대해:

  1. K8s 환경: NetworkPolicy로 ingress namespace의 pod만 backend pod에 in-bound 허용.
  2. EC2/VM 환경: Security Group inbound를 ALB/ingress SG만 허용. backend가 0.0.0.0에 listen하지 않게.
  3. mTLS 옵션: ingress ↔ backend 간 mutual TLS로 헤더 발신자를 cryptographic하게 검증.
  4. 헤더 검증 추가: oauth2-proxy ↔ backend가 공유하는 shared secret을 별도 헤더(X-Internal-Auth-Token)에 실어 backend가 검증.

이 네 가지 trade-off와 각각의 운영 비용을 정리.

핵심 질문:

  1. K8s NetworkPolicy는 default-deny + ingress namespace allow 두 단계로 작성해야 한다. 왜?
  2. EC2 Security Group만으로 충분한가? VPC 내부 다른 인스턴스의 위협은?
  3. mTLS는 왜 ForwardAuth 패턴에서 자주 생략되는가? (운영 복잡도 vs 위협 모델)
  4. shared-secret 헤더는 어디에 저장하고 어떻게 회전하는가?
  • 이슈:
  • PR:

범위

포함 범위

  • 4가지 헤더 spoofing 방어 메커니즘의 비교·근거 문서화 (documented-only): K8s NetworkPolicy 2단계(D3), EC2 Security Group + loopback bind 2계층(D4), mTLS deferral 조건(D2), shared-secret 헤더(D5).
  • 각 메커니즘의 공식 vendor doc 근거 + 명시적 실패 모드 정리 (§Decision Evidence Map, §구현 가이드, §엣지·실패·의존).
  • 면접 답변 후보: "P1A/AP4 패턴에서 가장 중요한 운영 결정 = 백엔드를 ingress 뒤에 네트워크로 격리하는 강제 메커니즘"(D1).

제외 범위

의도적으로 제외. 면접에서 "이건 범위에 없었습니다"라고 답할 근거.

  • 실 구현 / E2E 시연 — 본 note 는 documented-only. 실 방어 구성·시연은 P3A 실 구현 단계(프로젝트 SSOT §5).
  • mTLS 실 구성 (D2) — 프로젝트 SSOT §5 에서 project-level out-of-scope. 본 note 는 "왜 defer 하는가"의 조건만 문서화.
  • K8s 클러스터 실 구축 — 프로젝트는 single-EC2 실 구현(SSOT §F5), cluster-internal 은 §2.2 cross-cutting 문서만. NetworkPolicy 는 원칙 문서화만.
  • Detection 계층 (VPC Flow Logs / GuardDuty 등 사후 탐지) — prevention 이 아니므로 본 결정 축 밖.
  • IAM 최소권한 (SG 수정 권한 scoping) — SG 방어를 우회할 수 있는 control-plane 위협이나 네트워크 결정과 독립된 별도 관심사.

근거 (필수, 최소 1개+)

부모 sub-branch에서 인용한 자료 + 본 sub-sub에서 추가 검토 후보.

  • raw/official-docs/oauth2-proxy-nginx-integration-official — ingress 우회 위험을 명시한 oauth2-proxy 공식 가이드 (D1 근거, 부모 인용 재참조)
  • raw/official-docs/keycloak-reverseproxy-official — Keycloak reverse proxy 환경의 header spoofing 공식 경고(KC-RP-C3) + KC_PROXY_TRUSTED_ADDRESSES 예시(KC-RP-C5) (D1·D6 근거)
  • raw/official-docs/traefik-forwardauth-middleware-official — Traefik ForwardAuth authResponseHeaders replace 동작(TFA-C3) + trustForwardHeader deprecated 경고(TFA-C6) (D1·D7 근거)
  • raw/official-docs/aws-security-group-referencing-official — AWS 공식: SG-source rule 은 그 SG 소속 인스턴스만 대상·private IP 통신(AWS-SG-REF-C1), same-VPC/peering/TGW 범위 조건(AWS-SG-REF-C2), multi-SG aggregation=union(AWS-SG-REF-C3) (D4 SG-reference 동작·범위 근거)
  • raw/official-docs/aws-alb-target-security-group-restriction-official — AWS 공식: target(EC2 instance) 의 security group 을 load balancer 의 security group 만 허용하도록 제한하라는 권고 (D4 SG 제한 부분의 근거)
  • raw/official-docs/docker-port-publishing-loopback-bind-official — Docker Engine 공식: host IP 미지정 시 기본적으로 모든 host 주소(0.0.0.0/[::])에 publish 하는 것이 "insecure by default", publish flag 에 127.0.0.1/::1 을 포함하면 Docker host 로만 접근 범위가 좁혀짐 (D4 listen-address 제한 부분의 근거)
  • raw/official-docs/k8s-network-policy-official — Kubernetes NetworkPolicy 공식: pod 기본 non-isolated → NetworkPolicy 가 selecting 시 isolated (KNP-C1), policy additive/union 의미론 (KNP-C2), CNI 미구현 시 no effect — silent no-op 위험 (KNP-C3). D3(K8s NetworkPolicy default-deny + ingress namespace allow 2단계 작성) 근거로 2026-07-16 raw 보존 완료
  • raw/official-docs/aws-cloudfront-origin-shared-secret-header-official — AWS CloudFront→ALB shared-secret custom header 공식 mitigation: 헤더를 secure credential 로 취급 (CF-ALB-SECRET-C2), secret 유출 시 전면 우회되는 명시적 실패 모드 (CF-ALB-SECRET-C3), network-layer(AWS-managed prefix list) 병행 권고 (CF-ALB-SECRET-C4), make-before-break 회전 절차 (CF-ALB-SECRET-C5). D5(shared-secret 헤더 = defense-in-depth 2차, network 격리가 1차) 근거로 2026-07-16 raw 보존 완료
  • raw/official-docs/istio-mtls-cert-rotation-official — Istio 공식: mTLS 채택 시 key management 시스템이 cert 생성·배포·rotation 을 자동화해야 함(ISTIO-MTLS-C1/C2/C3), mTLS handshake 의 secure naming check 가 발신자를 암호학적으로 인증(ISTIO-MTLS-C4/C5). D2(학습 프로젝트 한정 mTLS out-of-scope)의 "운영 비용 = cert lifecycle" 기술적 전제 근거로 2026-07-16 raw 보존 완료
  • (검토 후보) Calico NetworkPolicy 공식 — 본 sub-sub 진행 시 raw 추가 여부 결정

TODO

각 항목 옆에 증거 등급 표기.

  • K8s NetworkPolicy 예제 작성 (default-deny ingress + ingress namespace allow + DNS egress 허용) — 등급: planned — 근거: [[raw/official-docs/k8s-network-policy-official]]#KNP-C1(selecting 시 isolated), #KNP-C2(additive/union — 두 리소스로 나눠 써도 안전)
  • NetworkPolicy의 CNI 의존성 정리 (Calico / Cilium 등이 지원해야 동작. flannel default는 enforce 안 함) — 등급: planned — 근거: [[raw/official-docs/k8s-network-policy-official]]#KNP-C3(CNI 미구현 시 no effect, 어떤 CNI 가 구현하는지는 does-not-prove)
  • EC2 Security Group inbound 예제: backend SG는 ALB SG만 허용. SSH/관리 포트는 별도 bastion SG — 등급: planned
  • backend listen address를 0.0.0.0:8080이 아닌 127.0.0.1:8080 + sidecar proxy 또는 private subnet 한정 — 등급: planned
  • mTLS 옵션 비교: ingress ↔ backend 간 TLS client cert 검증. cert 발급/회전 비용 정리 — 등급: planned
  • mTLS 미사용 사유 정리 (학습 프로젝트 한정, 운영 복잡도 > 위협 모델) — 등급: planned
  • shared-secret 헤더 검증 패턴: X-Internal-Auth-Token: <hmac> + backend middleware 검증. 회전 정책 — 등급: planned
  • 4가지 방어책 비교표 (운영 비용 / 보안 강도 / 도입 시점) — §구현 가이드 §0 에 작성 완료 (2026-07-16) — 등급: documented-only
  • 면접 답변 후보 정리: "P1A 패턴에서 가장 중요한 운영 결정은?" → "백엔드가 ingress 외 경로로 도달되지 않도록 네트워크 격리를 강제하는 것" — 등급: planned
  • K8s NetworkPolicy 공식 raw 보존 검토 (raw/official-docs/k8s-network-policy-official — 2026-07-16 완료, KNP-C1/C2/C3 추출) — 등급: actually-implemented (raw 보존 자체)

진행 중 메모

작업하며 떠오른 메모.

  • ForwardAuth 패턴의 위협 모델 핵심: backend는 헤더만 보는 trust-on-message. 메시지 발신자 검증이 네트워크 레이어에 위임된다.
  • K8s NetworkPolicy는 CNI 미지원이면 manifest만 있고 enforce가 안 되는 silent failure 위험 있음. kubectl get networkpolicy만으로는 enforcement 여부 알 수 없음.
  • shared-secret 헤더는 spoofing 방어로는 약함 (헤더 자체가 leak되면 끝). 네트워크 격리가 1차, shared-secret은 defense-in-depth 2차 정도로 정리.

결정 사항 (decisions)

  • 2026-05-25 (decision candidate): P1A 패턴의 가장 중요한 운영 결정 = 백엔드를 ingress 뒤에 격리하는 강제 메커니즘. 본 sub-sub의 결론은 면접/포트폴리오 답변에서 P1A를 설명할 때의 핵심 메시지로 채택.
  • 2026-05-25: 학습 프로젝트 한정으로 mTLS는 out of scope. 운영 환경 가정 시 검토 항목으로만 표기.

결정-근거 매핑

각 결정이 어떤 raw source claim 으로 뒷받침되는지 명시. 본 sub-sub 의 4가지 방어책 중 Traefik trustForwardHeader deprecated 경고, Keycloak KC_PROXY_TRUSTED_ADDRESSES, EC2 Security Group(D4), K8s NetworkPolicy(D3, 2026-07-16 raw/official-docs/k8s-network-policy-official 보존 후), shared-secret 헤더(D5, 2026-07-16 raw/official-docs/aws-cloudfront-origin-shared-secret-header-official 보존 후 — CloudFront→ALB 구조적 동형 패턴 인용) 는 vendor doc 으로 직접 뒷받침. mTLS(D2) 만 여전히 UNSUPPORTED_DECISION.

Decision ID Decision Supporting Claims Evidence Strength Open Risk
D1 P1A 패턴의 가장 중요한 운영 결정 = 백엔드를 ingress 뒤에 격리하는 강제 메커니즘 (네트워크 경계가 1차 방어, 헤더 검증은 trust-on-message) raw/official-docs/traefik-forwardauth-middleware-official.md#TFA-C3 (authResponseHeaders 의 replace 동작이 client spoof 를 강제로 deny 하지 않음 — does-not-prove), raw/official-docs/oauth2-proxy-nginx-integration-official.md#O2PN-C3 (X-User 헤더 신뢰가 안전하다는 뜻 아님 — does-not-prove), raw/official-docs/keycloak-reverseproxy-official.md#KC-RP-C3 (proxy header spoofing 공식 경고) official-vendor-doc (3개 공식 문서가 모두 "헤더 검증만으로는 부족" 을 명시) 면접 답변으로 채택했으나, 학습 프로젝트 자체는 단일 EC2 단독 운영이라 실제 네트워크 격리 시연 부재
D2 학습 프로젝트 한정으로 mTLS 는 out of scope (운영 환경 가정 시 검토 항목) raw/official-docs/istio-mtls-cert-rotation-official.md#ISTIO-MTLS-C1 (mTLS 채택 시 cert 생성·배포·rotation 을 자동화하는 key management 시스템이 필요 — 운영 비용의 실체가 "cert lifecycle 관리"), #ISTIO-MTLS-C2(rotation 이 자동·주기적으로 발생해야 함 — 수동 관리가 아니라 자동화 인프라 자체가 전제), #ISTIO-MTLS-C4(mTLS 는 secure naming check 로 발신자를 암호학적으로 인증 — mTLS 의 강점 자체는 공식 근거 확보) + UNSUPPORTED_DECISION 잔존: "이미 mesh 가 없으면 그 비용이 정당화되지 않는다"는 결론 자체는 Istio 문서가 직접 말하지 않음 — 이 프로젝트가 단일 EC2 라는 전제와 결합한 사용자 trade-off 판단 official-vendor-doc(mTLS 운영 비용의 기술적 전제) + UNSUPPORTED_DECISION(mesh 부재 시 defer 하는 결론 자체) 학습 단계 deferral 이 운영 단계에서 누락될 위험. mesh 신규 도입 비용과 mTLS 를 mesh 없이 수동 구성하는 비용의 정량 비교는 여전히 미실측
D3 K8s 환경: NetworkPolicy default-deny + ingress namespace allow 2단계 작성 raw/official-docs/k8s-network-policy-official.md#KNP-C1 (pod 는 기본 non-isolated, selecting 하는 NetworkPolicy 가 있어야 isolated 시작 — default-deny 가 먼저 필요한 이유), #KNP-C2 (policy 는 additive/union 의미론 — default-deny 와 ingress-namespace-allow 를 별도 두 리소스로 나눠 작성해도 안전하게 합쳐짐), #KNP-C3 (CNI 가 NetworkPolicy 를 구현하지 않으면 리소스 생성이 no effect — silent no-op 위험, does-not-prove: 어떤 CNI 가 구현하는지 목록) official-standard (Kubernetes 공식 concepts 문서, 3개 claim 모두 원문 verbatim) NetworkPolicy 가 CNI 미지원 환경 (flannel default) 에서 silent failure → spoofing 방어 실패 (KNP-C3 로 공식 근거 확보됐으나, 실제 클러스터의 CNI 가 NetworkPolicy 를 구현하는지는 실측 필요 — Claims To Verify 참조)
D4 EC2/VM 환경: Security Group inbound 를 ALB/ingress SG 만 허용 + backend 가 0.0.0.0 가 아닌 127.0.0.1:8080 listen 또는 private subnet 한정 raw/official-docs/aws-security-group-referencing-official.md#AWS-SG-REF-C1 (SG-source rule 은 그 SG 에 연결된 인스턴스만 대상, private IP 로 통신), #AWS-SG-REF-C2 (SG-reference 는 same-VPC/peering/(inbound 한정)transit-gateway 범위에서만 동작 — CIDR-source 와 달리 범위 제약), #AWS-SG-REF-C3 (multi-SG aggregation=union — does-not-prove: leftover broad CIDR allow rule 이 함께 aggregate 되면 SG-narrow rule 이 무력화될 수 있다는 문장은 원문에 없고 논리적 추론), raw/official-docs/docker-port-publishing-loopback-bind-official.md#DOCKER-PORT-PUB-C1 (host IP 미지정 시 Docker daemon 이 기본적으로 0.0.0.0/[::] 전체에 publish), #DOCKER-PORT-PUB-C3 (이 기본 동작이 "insecure by default" — 공식 경고), #DOCKER-PORT-PUB-C4 (publish flag 에 127.0.0.1/::1 을 포함하면 오직 Docker host 만 접근 가능해짐 — listen address 를 127.0.0.1 로 제한하는 부분의 공식 근거) official-vendor-doc (SG-reference 의 scope·동작과 backend listen address 를 127.0.0.1 로 제한하는 부분 모두 이제 공식 근거 확보. 단 SG 절반의 "ALB SG 만 허용" 표현은 이 branch 의 실제 토폴로지가 ALB 없는 단일 EC2 라는 점에서 aws-alb-target-security-group-restriction-official.md 자신이 "적용될 실제 ALB 가 없다"고 명시 — 원칙만 차용) VPC 내부 다른 인스턴스의 lateral movement 는 SG-reference 로 이론상 차단되나, 같은 인스턴스에 연결된 다른 SG 에 broad CIDR allow rule 이 남아있으면 aggregation(union) 으로 인해 무력화될 수 있음 — 실 환경에서 leftover rule 부재 여부 실측 필요. loopback bind(127.0.0.1:8080) 절반도 실제 docker-compose.yml 적용 후 host 외부에서 curl 실패·host 내부에서 curl 성공 실측 필요 (Claims To Verify 항목 참조)
D5 shared-secret 헤더 (X-Internal-Auth-Token: <hmac>) 는 defense-in-depth 2차 — 1차 방어는 네트워크 격리 raw/official-docs/aws-cloudfront-origin-shared-secret-header-official.md#CF-ALB-SECRET-C2 (헤더 이름/값을 secure credential 로 취급), #CF-ALB-SECRET-C3 (헤더 secret 유출 = 전면 우회되는 명시적 실패 모드), #CF-ALB-SECRET-C4 (network-layer prefix list 병행 권고 — header 검증 단독 불충분을 AWS 스스로 인정), #CF-ALB-SECRET-C5 (make-before-break 회전 절차) official-vendor-doc (CloudFront→ALB 맥락의 구조적 동형 패턴 — 직접 Keycloak/oauth2-proxy 문서는 아니므로 구조 유사성 인용) 헤더 자체가 leak 되면 우회 가능 (C3 이 명시). 회전 절차의 정확한 "주기"(수치)는 인용 범위 밖 — 본 프로젝트의 실제 회전 주기는 별도 결정 필요
D6 Keycloak reverse proxy 환경에서 KC_PROXY_TRUSTED_ADDRESSES 화이트리스트로 proxy header 송신 IP 제한 (단일 EC2 = 127.0.0.1) raw/official-docs/keycloak-reverseproxy-official.md#KC-RP-C5 (--proxy-trusted-addresses=192.168.0.32,127.0.0.0/8 예시), raw/official-docs/keycloak-reverseproxy-official.md#KC-RP-C3 (header spoofing 공식 경고) official-vendor-doc 화이트리스트 외 IP 가 proxy 헤더 emit 시의 정확한 동작 (drop/ignore/log) 은 인용 범위 밖 (KC-RP-C5 does-not-prove)
D7 Traefik 사용 시 trustForwardHeader=true 회피 (deprecated marker — X-Forwarded-* 무조건 신뢰 위험) raw/official-docs/traefik-forwardauth-middleware-official.md#TFA-C6 official-vendor-doc 대체 옵션의 정확한 신규 이름은 본 인용에 없음 — 별도 deprecated 경고 페이지 raw 보존 필요

구현 가이드

본 sub-sub 는 documented-only — 여기서 "구현"은 각 방어 메커니즘의 구성 레시피(다음 구현자가 되묻지 않고 config 를 작성할 수준)를 뜻한다. 4가지 메커니즘 각각을 결정(D2~D5) + 근거 Claim ID 로 trace. 근거가 원칙만 주고 detail(정확한 라벨/알고리즘/저장소)을 주지 않는 cell 은 UNSUPPORTED_IMPL_DECISION + trade-off 한 줄(CLAUDE.md §15.5 R2).

OUT_OF_BRANCH_SCOPE 정제(R3): mTLS 실 cert 파이프라인(D2)은 프로젝트 SSOT §5 에서 project-level out-of-scope 이므로 "왜 defer 인가"의 조건만 남기고 실제 명세는 남기지 않는다. IAM 최소권한·detection(Flow Logs/GuardDuty)도 별도 관심사로 §엣지·실패·의존 으로 이관.

0. 4가지 방어책 종합 비교 (선택 요약)

In-scope #1(비교·근거 문서화)의 종결 표. 개별 선택 조건이 §1~§4 에 산재하므로 여기서 한눈에 통합.

방어책 계층 운영 비용 보안 강도 도입 시점/조건 근거
D3 K8s NetworkPolicy L3/L4 네트워크 (1차) 낮음 (선언 YAML, CNI 의존) 높음 — 우회 경로 원천 차단, 단 CNI 미구현 시 silent no-op K8s 환경일 때 KNP-C1/C2/C3
D4 EC2 SG + loopback ENI 경계 + host 경계 (1차) 낮음 (SG rule + compose 1줄) 높음 — 단 leftover CIDR rule union 위험 EC2/VM 환경일 때 (단일 EC2 = loopback 우선) AWS-SG-REF-C1/C2, DOCKER-PORT-PUB-C4
D5 shared-secret 헤더 app 계층 (2차) 중간 (secret 저장+회전) 약함 — leak 시 전면 우회 상시 2차 defense-in-depth (단독 1차 금지) CF-ALB-SECRET-C3/C4/C5
D2 mTLS 전송 계층 (암호학적) 높음 (cert lifecycle 자동화 인프라) 가장 넓음 — 경계 내부 위협도 방어 mesh 운영 중 / 멀티테넌트 / 규제 시만 (그 외 defer) ISTIO-MTLS-C1/C2/C4

핵심 선택 규칙: ① 환경으로 1차 방어 결정 (K8s→D3, EC2→D4) → ② D5 를 상시 2차로 병행 → ③ D2 는 조건(mesh/멀티테넌트/규제) 충족 시에만 (그 전엔 network 격리로 충분).

1. K8s NetworkPolicy 2단계 구성 (D3)

Trace: D3 / k8s-network-policy-official#KNP-C1(pod 기본 non-isolated → selecting NetworkPolicy 가 있어야 isolated), #KNP-C2(additive/union — default-deny 와 allow 를 별도 리소스로 나눠도 안전하게 합쳐짐), #KNP-C3(CNI 미구현 시 no effect).

  • UNSUPPORTED_IMPL_DECISION: (a) DNS egress 허용 레시피(port 53 → kube-dns)는 kubernetes.io 공식 문서에 verbatim 부재(community recipe 만 존재, 조사에서 확인) — trade-off: DNS egress 를 빼면 pod 이름 해석이 깨져 정상 트래픽도 실패하므로 실용상 필요하나 공식 근거 미확보, 실 구성 시 사용 CNI vendor 문서로 확인. (b) namespaceSelector 라벨 값은 실 클러스터의 namespace 라벨링 규약에 의존 — 임의 결정.
단계 manifest 골자 근거
1. default-deny ingress podSelector: {} + policyTypes: [Ingress] (ingress 규칙 없음) → backend namespace 의 모든 pod 를 isolated 로 전환 KNP-C1
2. ingress-namespace allow podSelector: <backend> + ingress: [{from: [{namespaceSelector: <ingress ns 라벨>}]}] → proxy namespace 만 허용 KNP-C2 (1·2 를 별도 리소스로 나눠도 union)
3. enforcement 확인 실사용 CNI 가 NetworkPolicy 를 구현하는지 확인 — kubectl get networkpolicy 로는 불충분(§Claims To Verify 실측) KNP-C3 (does-not-prove: 어떤 CNI 가 구현하는지)

주의(조사 확인): from 배열의 한 원소 안에 namespaceSelector+podSelector 를 같이 넣으면 AND(교집합), 별도 원소면 OR — "ingress namespace 의 아무 pod 든 허용"은 namespaceSelector 단독 원소여야 함.

2. EC2 Security Group + loopback bind — 서로 다른 2계층 (D4)

Trace: D4 / aws-security-group-referencing-official#AWS-SG-REF-C1(SG-source rule = 그 SG 소속 인스턴스만, private IP), #AWS-SG-REF-C2(same-VPC/peering/TGW 범위), aws-alb-target-security-group-restriction-official#ALB-SG-C1(target SG source = LB SG 권고), docker-port-publishing-loopback-bind-official#DOCKER-PORT-PUB-C4(publish flag 에 127.0.0.1 포함 시 Docker host 만 접근).

  • UNSUPPORTED_IMPL_DECISION: 이 프로젝트의 실제 토폴로지는 ALB 없는 단일 EC2(SSOT §F5) — "backend SG 를 ALB SG 만 허용"은 멀티 인스턴스 확장 시의 원칙 차용이고, 현 배포의 실적용 메커니즘은 loopback bind / no-publish 다. SG-ref 와 loopback 은 대체가 아니라 서로 다른 계층(SG=ENI 경계, loopback=host 경계)이라 병행. trade-off: 단일 EC2 에서 SG-ref 는 시연할 별도 proxy 인스턴스가 없어 문서 근거로만 남김.
계층 실적용(단일 EC2) 멀티 인스턴스 확장 시 근거
host 경계 docker-compose 에서 backend 포트를 127.0.0.1:8080:8080 bind 또는 ports: 생략(expose: 만) 동일 유지 DOCKER-PORT-PUB-C4, C3(insecure by default)
ENI 경계 (해당 없음 — proxy·backend 동일 host) backend SG inbound source = proxy/ALB SG-reference AWS-SG-REF-C1, ALB-SG-C1

3. shared-secret 헤더 검증 — defense-in-depth 2차 (D5)

Trace: D5 / aws-cloudfront-origin-shared-secret-header-official#CF-ALB-SECRET-C2(헤더를 secure credential 로 취급), #CF-ALB-SECRET-C3(secret 유출 = 전면 우회), #CF-ALB-SECRET-C4(network-layer 병행 권고), #CF-ALB-SECRET-C5(make-before-break 회전).

  • UNSUPPORTED_IMPL_DECISION: (a) 근거는 AWS CloudFront→ALB 의 구조적 동형 패턴이며 oauth2-proxy/nginx→backend 스택의 vendor 직접 근거가 아님(유추 적용 — 과장 금지). (b) HMAC 알고리즘·secret 저장소(env var vs secret manager)·Spring backend 미들웨어 검증 코드·app-code 무중단 회전 구현은 CloudFront 문서(infra-rule 계층만)의 범위 밖 — 임의 결정. trade-off: 학습 단계는 env var + 단일 시크릿으로 충분하나, 유출 시 무력화되므로 network 격리(D3/D4) 없이 단독 1차 사용 금지.
항목 명세 근거
헤더 proxy 가 X-Internal-Auth-Token 주입, backend 미들웨어가 검증 CF-ALB-SECRET-C2 (구조적 동형)
저장 secure credential 로 취급 — 평문 config 반입 금지 CF-ALB-SECRET-C2
회전 make-before-break: 신규 헤더 추가 → backend 양쪽 허용 → 구 헤더 송신 중단 → 구 헤더 허용 제거 CF-ALB-SECRET-C5
위치 반드시 network 격리(D3/D4) 하위의 2차 — 단독 1차 금지 CF-ALB-SECRET-C3, C4

4. mTLS — deferral 조건만 (D2, 실 cert 파이프라인은 OUT_OF_BRANCH_SCOPE)

Trace: D2 / istio-mtls-cert-rotation-official#ISTIO-MTLS-C1(cert 생성·배포·rotation 자동화 필요 = 운영 비용의 실체), #ISTIO-MTLS-C2(주기적 자동 회전). 프로젝트 SSOT §5(mTLS project-level out-of-scope) + §F5(single-EC2).

  • deferral 조건(언제 재검토): 이미 service mesh 운영 중 / 멀티테넌트 클러스터(backend namespace 를 타 팀 공유) / 규제(FAPI·PCI) 요구 → mTLS 채택. 그 외(단일 테넌트·단일 EC2·학습)는 network 격리로 충분.
  • 실 cert 파이프라인 명세는 본 § 에 남기지 않음(OUT_OF_BRANCH_SCOPE — 운영 전환 시 별도 branch). "mesh 부재 시 defer 결론 자체"는 여전히 UNSUPPORTED_DECISION(Decision Evidence Map D2 참조).

엣지·실패·의존

R4(깊이 게이트) 캡처용. 정상 경로 외에 구현 중 부딪힐 실패/엣지/다른 계약 의존을 미리 열거.

  • 실패·엣지 경로:
    • NetworkPolicy silent no-op (D3): 실사용 CNI 가 NetworkPolicy 를 구현하지 않으면(flannel default) manifest 는 API 에 저장되나 아무것도 차단하지 않음 — kubectl get networkpolicy 로는 탐지 불가(KNP-C3). 기대 동작: 적용 후 직접 backend pod IP 로 curl 해 차단 여부 실측(§Claims To Verify).
    • SG rule aggregation(union) (D4): backend 인스턴스에 연결된 다른 SG 에 broad CIDR allow rule 이 남아있으면 SG-ref 의 narrow rule 과 union 되어 무력화(AWS-SG-REF-C3 does-not-prove — 논리적 추론). 기대 동작: 신규 SG-ref rule 추가 전 기존 rule 전수 감사.
    • loopback bind 회귀 (D4): docker-compose 의 127.0.0.1:8080:8080 을 실수로 8080:8080 으로 되돌리면 즉시 전체 외부 노출(DOCKER-PORT-PUB-C3 "insecure by default"). SG 계층이 최후 방어선.
    • shared-secret leak = 전면 우회 (D5): 헤더/시크릿이 유출되면 방어가 완전 무력화(CF-ALB-SECRET-C3). network 격리(1차) 없이 단독 사용 금지가 그래서 강제.
    • mTLS deferral 누락 (D2): 프로젝트가 멀티테넌트/prod 로 전환될 때 deferral 재검토가 누락되면 network 격리 단일 계층에만 의존하게 됨.
  • 다른 계약 의존 (대상 브랜치 + Decision ID 병기):
    • 부모 raw/branch-notes/feature-keycloak-edge-forwardauth-no-google D2(헤더 명명 = nginx 계열 X-Auth-Request-User 우선) — 본 branch 의 4 방어가 지키는 "신뢰 헤더"의 이름 owner. 부모 D2 가 헤더 이름을 바꾸면 본 branch 방어 대상 입력이 바뀜.
    • 부모 raw/branch-notes/feature-keycloak-edge-forwardauth-no-google D4(header spoofing 방어 = ingress-only 강제, NetworkPolicy/VPC SG) — 역방향 계약: 부모 D4 는 현재 UNSUPPORTED_DECISION 으로 enforcement detail 을 본 sub-sub 에 명시 위임("별도 raw 보존 필요", 부모 :184). 본 branch 의 D3/D4 + 이번 세션 보존한 k8s-network-policy-official·aws-security-group-referencing-official raw 가 그 위임을 이행 — 부모 D4 는 향후 이 근거로 갱신 가능(갱신은 부모 owner 결정, 본 branch 는 근거만 제공).
    • 형제 raw/branch-notes/feature-keycloak-oauth2-proxy-oidc-flow / raw/branch-notes/feature-keycloak-nginx-auth-request-integration — 실제로 헤더를 주입하는 proxy 구성. 이들이 정한 헤더 이름(X-Auth-Request-User/Email/Groups)이 본 branch 방어의 입력.
    • D5 신규 헤더 주입 선행 의존: 본 branch D5 가 도입하는 X-Internal-Auth-Token 은 형제 raw/branch-notes/feature-keycloak-nginx-auth-request-integration 의 현재 전달 헤더 목록(X-Auth-Request-* only, 형제 :70)에 부재. D5 실 구현 시 형제 proxy 구성이 이 헤더를 주입하도록 확장이 선행돼야 함(형제 branch 의 향후 Decision 이 owner — 현재는 미존재 계약).
    • 본 branch 의 D6(KC_PROXY_TRUSTED_ADDRESSES) — Keycloak reverse-proxy 헤더 계약(raw/branch-notes/feature-keycloak-reverse-proxy-headers 계열)에 의존. proxy 신뢰 주소 정책이 바뀌면 D6 도 영향.
    • 범위 밖(별도 관심사, 본 branch 미소유): IAM 최소권한(SG 수정 권한 scoping) = SG 방어(D4)를 우회할 수 있는 control-plane 위협이나 네트워크 결정과 독립 / Detection 계층(VPC Flow Logs·GuardDuty) = prevention 아님. 둘 다 본 branch 결정 범위 밖으로 명시.

검증해야 할 주장

4가지 방어책의 실효성과 운영 비용은 vendor doc 만으로 검증 불가. 다음은 실 환경 시연 시 실측 필요.

Claim Why uncertain How to verify Status
K8s NetworkPolicy 가 CNI 미지원 (flannel default) 환경에서 silent failure 하는지 — kubectl get networkpolicy 만으로 enforcement 여부 확인 불가 D3 는 이제 raw/official-docs/k8s-network-policy-official.md#KNP-C3 로 "CNI 미구현 시 no effect" 원칙 자체는 공식 근거 확보(2026-07-16). 단 이 학습 프로젝트가 실제 사용하는 CNI 가 NetworkPolicy 를 구현하는지, kubectl get networkpolicy 만으로 enforcement 여부를 판별 가능한지는 KNP-C3 의 인용 범위 밖(does-not-prove) — 여전히 실측 필요 flannel(또는 실사용 CNI) 환경에서 NetworkPolicy 적용 후 ingress 우회 시도 (직접 backend pod IP curl) 로 enforce 여부 확인 needs-confirmation
EC2 Security Group inbound 가 ALB/proxy SG-reference 만 허용해도 VPC 내부 다른 인스턴스의 lateral movement 차단 가능한지 D4 는 이제 aws-security-group-referencing-official#AWS-SG-REF-C1/C2 로 "SG-source = SG 소속 인스턴스만·same-VPC 범위" 동작은 공식 근거 확보(2026-07-16). 단 실 배포 backend 인스턴스에 leftover broad CIDR allow rule 이 없는지(union 무력화 여부, AWS-SG-REF-C3 does-not-prove)는 실측 필요 bastion 인스턴스에서 backend :8080 직접 curl 시도 후 차단 여부 확인 + 기존 SG rule 전수 감사 planned
shared-secret 헤더 (X-Internal-Auth-Token: hmac) 가 backend middleware 에서 실제로 우회 차단을 하는지 D5 는 이제 raw/official-docs/aws-cloudfront-origin-shared-secret-header-official.md#CF-ALB-SECRET-C1~C5 로 CloudFront→ALB 맥락의 패턴·실패 모드·회전 절차는 공식 근거 확보(2026-07-16). 단 본 프로젝트의 oauth2-proxy/nginx→backend 조합에서 동일 mitigation 이 실제로 동작하는지, 헤더 leak 시 무력화 위험도가 정량적으로 어느 정도인지는 CloudFront 인용 범위 밖(구조적 유사성만 인용 — does-not-prove) — 여전히 실측 필요 shared-secret 없는 직접 요청과 위조 요청을 backend 에 보내 응답 차이 확인 planned
Keycloak KC_PROXY_TRUSTED_ADDRESSES=127.0.0.1 가 단일 EC2 환경에서 spoofing 차단에 충분한지 KC-RP-C5 does-not-prove "화이트리스트 외 IP 의 정확한 동작" 외부에서 직접 Keycloak :8080X-Forwarded-For: 8.8.8.8 위조 요청 후 로그에 위조 IP 가 기록되는지 확인 needs-confirmation
nginx + oauth2-proxy 의 X-Auth-Request-User 헤더가 backend 도달 전에 ingress 외부에서 주입된 동일 이름 헤더로 위조 가능한지 O2PN-C3 does-not-prove "backend 가 X-User 헤더를 신뢰해도 안전" 외부 client 가 X-Auth-Request-User: admin 헤더를 포함한 요청을 ingress 와 backend 양쪽에 보내 처리 결과 비교 needs-confirmation
Traefik trustForwardHeader=true deprecated 의 대체 옵션 (정확한 신규 이름과 동작) TFA-C6 does-not-prove "대체 옵션명" Traefik 공식 deprecated 경고 페이지 추가 raw 보존 후 신규 옵션 시연 planned
K8s NetworkPolicy 공식 vendor doc raw 보존 (raw/official-docs/k8s-network-policy-official) (해결됨 — 2026-07-16 raw 보존 완료, KNP-C1/C2/C3 추출로 D3 UNSUPPORTED_DECISION 해소) kubernetes.io 공식 NetworkPolicy 페이지를 raw-source-template 으로 보존 후 Claim ID 추출 done
mTLS ingress↔backend 의 cert 발급/회전 운영 비용이 위협 모델 대비 정당한지 D2 UNSUPPORTED — vendor 인용 부재 + 학습 단계 deferral cert-manager 또는 SPIFFE/SPIRE 등 cert 자동화 도구 비교 + 회전 주기별 운영 비용 측정 planned

마주친 문제

  • 아직 없음(문서 단계).

묶음

본 sub-sub-branch 는 leaf — 자식 branch 없음. Phase 3 P3A 실 구현 또는 외부 산출물 단계에서 errors / interview prep / lectures 가 누적되면 본 섹션에서 그룹화. (근거 raw 자료 8건은 §Sources / 근거 에 단일 관리 — 여기 중복 나열하지 않음.)

오류 기록 (이 sub-sub-branch 작업 중 발생)

  • (없음 — 현재 documented-only 단계)

면접 준비 (이 작업에서 나올 수 있는 면접 질문)

  • (없음 — Phase 3 실 구현 단계에 누적)

관련 일일 노트

완료 후 정리

본 sub-sub-branch는 문서까지만. wiki 추출은 root branch의 비교 매트릭스 시점에 일괄 처리.

  • PR 링크:
  • 리뷰 메모:
  • 머지 결과 / 배포 환경: 해당 없음 (문서 단계)
  • wiki 추출 대상 (verified만, wiki/projects/로만 추출):
    • actually-implemented 항목: 없음
    • locally-verified 항목: 없음
    • prod-verified 항목: 없음
  • 추출하지 않을 항목 (planned / documented-only / abandoned):
    • 본 sub-sub-branch 전체가 documented-only 등급. P1A 부모 sub-branch와 함께 추후 비교 매트릭스 / wiki/concepts/keycloak-deployment-patterns.md에 인용되는 형태로만 활용. wiki/projects/ 직접 승급 없음.