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 |
|
|
1 | feature-keycloak-header-spoofing-defense |
|
|
2026-05-25 | in-progress | 2bdbf4639b4e61ad38f9f32504f877dd87ad84f8f07523fd0c874bc316c1ae79 |
branch: feature-keycloak-header-spoofing-defense (P1A — 헤더 spoofing 방어, Network 경계 강제)
Layer:
raw/branch-notes/— raw/project-notes/keycloak-patterns-overview의WI-KEYCLOAK-PATTERNS-OVERVIEW-014직접 branch. P1A 패턴이 깨지는 유일하고도 가장 흔한 경로 — backend가 ingress 우회 경로로 도달 가능할 때 — 의 방어 메커니즘을 정리. K8sNetworkPolicy, 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는 이 단일 위협에 대해:
- K8s 환경:
NetworkPolicy로 ingress namespace의 pod만 backend pod에 in-bound 허용. - EC2/VM 환경: Security Group inbound를 ALB/ingress SG만 허용. backend가 0.0.0.0에 listen하지 않게.
- mTLS 옵션: ingress ↔ backend 간 mutual TLS로 헤더 발신자를 cryptographic하게 검증.
- 헤더 검증 추가: oauth2-proxy ↔ backend가 공유하는 shared secret을 별도 헤더(
X-Internal-Auth-Token)에 실어 backend가 검증.
이 네 가지 trade-off와 각각의 운영 비용을 정리.
핵심 질문:
- K8s
NetworkPolicy는 default-deny + ingress namespace allow 두 단계로 작성해야 한다. 왜? - EC2 Security Group만으로 충분한가? VPC 내부 다른 인스턴스의 위협은?
- mTLS는 왜 ForwardAuth 패턴에서 자주 생략되는가? (운영 복잡도 vs 위협 모델)
- 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
authResponseHeadersreplace 동작(TFA-C3) +trustForwardHeaderdeprecated 경고(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
trustForwardHeaderdeprecated 경고, KeycloakKC_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 격리 단일 계층에만 의존하게 됨.
- NetworkPolicy silent no-op (D3): 실사용 CNI 가 NetworkPolicy 를 구현하지 않으면(flannel default) manifest 는 API 에 저장되나 아무것도 차단하지 않음 —
- 다른 계약 의존 (대상 브랜치 + 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-officialraw 가 그 위임을 이행 — 부모 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 결정 범위 밖으로 명시.
- 부모 raw/branch-notes/feature-keycloak-edge-forwardauth-no-google
검증해야 할 주장
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 :8080 에 X-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 |
마주친 문제
- 아직 없음(문서 단계).
묶음
- raw/official-docs/aws-alb-target-security-group-restriction-official
- raw/official-docs/aws-cloudfront-origin-shared-secret-header-official
- raw/official-docs/aws-security-group-referencing-official
- raw/official-docs/docker-port-publishing-loopback-bind-official
- raw/official-docs/istio-mtls-cert-rotation-official
- raw/official-docs/k8s-network-policy-official
- raw/official-docs/keycloak-reverseproxy-official
- raw/official-docs/nginx-auth-request-module-official
- raw/official-docs/traefik-forwardauth-middleware-official
본 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/직접 승급 없음.
- 본 sub-sub-branch 전체가