30 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-edge-forwardauth-no-google (P1A Edge Forward Auth, no Google) | branch-note | raw | BR-KEYCLOAK-CHILD-12F5B5DA | branch-child | keycloak-patterns-overview | WI-KEYCLOAK-PATTERNS-OVERVIEW-020 |
|
1 | feature-keycloak-edge-forwardauth-no-google | feature-keycloak-patterns |
|
|
2026-05-25 | in-progress | e8d7d4e1b0766c23adb5879a98225689106a683f5882dd49a3b4b24b5fc18f08 |
branch: feature-keycloak-edge-forwardauth-no-google (P1A Edge Forward Auth, no Google)
Layer:
raw/branch-notes/— Keycloak 패턴 P1A 한정 sub-branch. Ingress(nginxauth_request또는 TraefikforwardAuth)가 외부 auth service(oauth2-proxy baseline)에 인증을 위임하고 백엔드는 인증 코드를 갖지 않는 패턴. Google federation 없음(=P1B는 별도 sub-branch). 본 sub-branch는 문서까지만(=documented-only). 실제 ingress/Traefik 환경 구축은 root branch의 P3A 한정.status_label:in-progress
부모 (필수)
- Parent branch (root): raw/branch-notes/feature-keycloak-patterns
- Parent project: raw/project-notes/keycloak-patterns-overview
- Sibling sub-branches:
- raw/branch-notes/feature-keycloak-edge-forwardauth-google-federation — P1B (Edge + Google)
- raw/branch-notes/feature-keycloak-internal-spa-direct-no-google — P2A (Cluster-internal, no Google)
- raw/branch-notes/feature-keycloak-internal-spa-direct-google-federation — P2B (Cluster-internal + Google)
- raw/branch-notes/feature-keycloak-single-ec2-no-google — P3A (Single EC2, no Google)
- raw/branch-notes/feature-keycloak-single-ec2-google-federation — P3B (Single EC2 + Google)
브랜치 계약 패킷
- 생성 시 프로젝트 개정:
1 - 패킷 스키마:
contract_packet: 1 - 완료 조건: project governance hub가 AP1~AP4 taxonomy와 child progress index를 유지한다
상속한 프로젝트 결정
| Decision Ref | Project Summary | Branch Application | Source |
|---|---|---|---|
DEC-KEYCLOAK-PATTERNS-OVERVIEW-AUTH-TAXONOMY-001@1 |
canonical 분류축은 AP1~AP4 인증 통합 아키텍처와 cross-cutting 변형이다 | no-Google Edge ForwardAuth를 AP4 비교 자료로 분류한다 | raw/project-notes/keycloak-patterns-overview |
브랜치 지역 결정
| Decision ID | Decision | Relation | Supporting Claims | Status |
|---|---|---|---|---|
| D1 | ingress 축과 auth-service 축을 분리한다 | local |
raw/project-notes/keycloak-patterns-overview | proposed |
| D2 | upstream identity header naming을 고정한다 | local |
raw/project-notes/keycloak-patterns-overview | proposed |
| D3 | backend authentication을 edge ForwardAuth에 위임한다 | local |
raw/project-notes/keycloak-patterns-overview | proposed |
| D4 | ingress-only traffic으로 header spoofing을 방어한다 | local |
raw/project-notes/keycloak-patterns-overview | proposed |
선언한 예외
| Override ID | Overrides | Reason | Approval | Status |
|---|
없음.
목표
Edge forward-auth 패턴이 무엇이고, 왜 이 배치를 택하는지를 컴포넌트 다이어그램 + 토큰 교환 sequence + 신뢰 경계 수준으로 정리. 백엔드 코드에서 인증 로직을 제거하고 edge proxy 단일 지점에서 zero-trust ingress 를 강제하는 흐름을 면접에서 설명할 수 있어야 함.
핵심 질문 두 개에 답할 수 있어야 한다:
- 왜 백엔드에 JWT validator를 두지 않고 edge proxy에 인증을 위임하는가? → 다중 서비스에 일관 인증 + 인증 코드 0줄.
- edge proxy를 신뢰하는 대신 잃는 것은? → 백엔드는 헤더만 보고 사용자를 식별하므로, ingress 우회 경로가 있으면 헤더 spoofing 위험.
- 이슈:
- PR:
범위
포함 범위
- P1A 컴포넌트 다이어그램 (텍스트 + Mermaid)
- 토큰 교환 sequence 7단계
- Ingress 선택(nginx vs Traefik)과 auth service 선택(oauth2-proxy vs 호환 OIDC agent)의 2축 비교
- nginx
auth_request방식과 TraefikforwardAuth방식의 차이 - 신뢰 경계 정의 (ingress → proxy까지)
- 장단점 / 운영 비용 / 보안 surface
- 외부 공식 문서 raw 보존 (oauth2-proxy, Traefik, nginx)
제외 범위
- Google IdP brokering (=P1B sub-branch에서 다룸)
- 실제 K8s / docker-compose 환경 구축 (root branch P3A 한정)
- BFF 패턴 (별도 결합 패턴, sub-branch에서 언급만)
- mTLS / FAPI / DPoP 등 고급 보안 옵션
- oauth2-proxy 비-Keycloak provider (GitHub, Google direct 등)
근거 (필수, 최소 1개+)
본 sub-branch의 P1A Edge ForwardAuth 패턴 채택 근거. 상세 대안 비교는 §외부 근거 / 대안 조사 참조.
| Source | 정당화하는 결정 |
|---|---|
| raw/official-docs/oauth2-proxy-overview-config-official | oauth2-proxy 공식 — 채택 컴포넌트 근거 (load-bearing: OAUTH2PROXY-C2/C3; C1 은 needs-confirmation, 결정 미인용) |
| raw/official-docs/oauth2-proxy-keycloak-oidc-provider-official | oauth2-proxy ↔ Keycloak OIDC 연동 — provider=keycloak-oidc 채택 근거 |
| raw/official-docs/oauth2-proxy-nginx-integration-official | nginx auth_request 통합 — Ingress-Nginx 결합 근거 |
| raw/official-docs/nginx-auth-request-module-official | nginx ngx_http_auth_request_module — subrequest 동작 근거 |
| raw/official-docs/traefik-forwardauth-middleware-official | Traefik ForwardAuth middleware — K8s 환경 대안 비교 근거 |
컴포넌트 다이어그램
텍스트
Browser → Ingress (Nginx / Traefik)
│
├── (1) ForwardAuth subrequest → oauth2-proxy / compatible auth service
│ │
│ └── (2) OIDC handshake → Keycloak
│ │
│ ← (3) 세션 쿠키 + X-Auth-Request-* 헤더 ←┘
│
↓ (4) 인증 통과 시 backend로 forward (헤더만 신뢰)
Backend (인증 코드 0줄, 헤더 trust만)
Mermaid
flowchart LR
B[Browser] -->|HTTPS| I[Ingress: Nginx or Traefik]
I -. auth_request or forwardAuth .-> P[oauth2-proxy / auth service]
P -. OIDC .-> K[Keycloak]
P -- 202 + X-Auth-Request-* --> I
I -->|trusted headers| BE[Backend API]
토큰 교환 sequence
"Browser, Ingress, oauth2-proxy, Keycloak, Backend" 5개 액터 기준.
- Browser → Ingress: unauthenticated request
GET /api/orders(쿠키 없음). - Ingress → oauth2-proxy
/oauth2/auth: nginx의auth_request디렉티브 또는 Traefik의forwardAuth미들웨어가 subrequest 전송. 이 endpoint는 요청을 프록시하지 않고 202(Accepted) 또는 401(Unauthorized)만 반환. - oauth2-proxy → Keycloak
/protocol/openid-connect/auth: 쿠키 없으므로 401 → Ingress가 error_page로 받아 named location@oauth2_signin으로 302 redirect 발급. 사용자 브라우저가 Keycloak 로그인 페이지로 이동. - Browser → Keycloak 로그인 UI → 사용자 인증 → callback: Authorization Code Flow + PKCE. Keycloak이 oauth2-proxy의 callback URL (
/oauth2/callback)로code파라미터와 함께 redirect. - oauth2-proxy → Keycloak
/protocol/openid-connect/token:code+client_secret→access_token+id_token+ (옵션)refresh_token교환. oauth2-proxy는 confidential client. - oauth2-proxy → 세션 쿠키 발급: JavaScript가 raw token을 읽지 못하는 HttpOnly 세션 쿠키(
_oauth2_proxy)를 발급한다. cookie-backed store면 encrypted cookie가 token material을 보유할 수 있고, Redis/server-side store면 cookie는 opaque session identifier만 보유한다. 이후auth_requestsubrequest 통과 시X-Auth-Request-User,X-Auth-Request-Email,X-Auth-Request-Groups헤더를 Ingress에 응답한다(P1A baseline은 access-token upstream 전달 미사용). - Ingress → Backend: Ingress가 응답 헤더에서
auth_request_set으로 변수 추출 →proxy_set_header X-User $user; X-Email $email;형식으로 backend에 헤더 주입. 백엔드는 JWT 검증을 하지 않고 헤더만 신뢰.
장점 / 단점
장점
- 백엔드 인증 코드 0줄: Resource Server 보일러플레이트(spring-security-oauth2-resource-server, JWT decoder, JWKS cache 등) 불필요.
- 다중 서비스 일관 인증: 같은 ingress 뒤의 모든 backend에 동일한 인증 정책 적용. 마이크로서비스 환경에서 인증 코드 분산을 방지.
- raw token의 JavaScript 노출 없음: HttpOnly cookie라 SPA script가 access/refresh token bytes를 직접 읽지 못한다. 다만 cookie-backed session이면 브라우저가 encrypted token-bearing cookie를 보유하므로 server-side custody와 동일하다고 표현하지 않는다.
- 운영 일원화: 인증 정책 변경(allowed-role, allowed-group 등) 시 oauth2-proxy config만 수정.
단점
- 헤더 spoofing risk: 백엔드가 ingress-only traffic을 강제하지 못하면(예: backend가 직접 NodePort 노출), 공격자가
X-Auth-Request-User: admin헤더를 위조해 우회 가능. - proxy SPOF: oauth2-proxy 다운 시 모든 backend 접근 불가. HA 구성 필수.
- 세션 저장 방식별 위험: cookie-backed store가 access token까지 encrypted cookie에 담으면 nginx의 기본 4kb 헤더 한도를 넘어 split-cookie 처리가 필요하다. Redis/server-side store면 cookie는 opaque ID지만 외부 state store 운영 책임이 생긴다.
- 백엔드가 토큰 claim 직접 접근 불가: scope / custom claim 기반 fine-grained 권한 체크가 필요하면 추가로
X-Auth-Request-Access-Token헤더로 토큰 자체를 전달하거나, 결국 backend에서도 JWT 파싱해야 함.
신뢰 경계
[ Public Internet ] ←→ [ Ingress + Forward-Auth Proxy ] ←→ [ Backend ]
untrusted ← 인증 경계 (boundary) trusted-by-header
- 인증 boundary: ingress → proxy 까지. 이 구간에서 사용자 식별 확정.
- 백엔드 전제: ingress 외 경로로는 도달 불가. 구체적 강제 수단:
- K8s:
NetworkPolicy로 ingress namespace에서만 backend pod 접근 허용. - VM: backend listen address를 loopback / private subnet으로 한정. Security Group으로 ingress IP만 허용.
- K8s:
- 이 전제가 깨지면 패턴 전체가 깨짐 → 외부 공격자가 backend에 직접
X-Auth-Request-User: anyuser헤더로 요청 가능.
제외 범위 (재확인)
- Google federation은 P1B 별도 sub-branch (raw/branch-notes/feature-keycloak-edge-forwardauth-google-federation). 본 sub-branch는 Keycloak 자체 user store만 사용.
TODO
각 항목 옆에 증거 등급 표기: actually-implemented | locally-verified | prod-verified | documented-only | planned | needs-confirmation
- P1A 컴포넌트 다이어그램 (텍스트 + Mermaid) — 등급:
documented-only - 토큰 교환 sequence 7단계 — 등급:
documented-only - Ingress(nginx/Traefik)와 auth service(oauth2-proxy/호환 agent) 선택축 분리 (D1) — 등급:
documented-only - 신뢰 경계 정의 + header spoofing 방어(D4)를 자식 branch 로 위임 — 등급:
documented-only - 실 구현(oauth2-proxy config + nginx
auth_requestblock) — root branch P3A 한정 — 등급:planned - §Claims To Verify 5개 주장 실측 (nginx build flag / 4kb cookie / 헤더 전파 / ingress-only / Traefik 비-2XX) — 등급:
planned(일부needs-confirmation)
진행 중 메모
- P1A 의 본질 한 줄: edge proxy 가 인증을 종결하고 backend 는 헤더만 신뢰 → "backend 인증 코드 0줄" 이 최대 이점이자 동시에 최대 약점(header spoofing). 이 한 문장이 §장점·§단점·D3·D4 를 관통한다.
- subrequest mode endpoint 구분: oauth2-proxy 의
/oauth2/auth는 요청을 프록시하지 않고 2xx/401 만 반환하는 subrequest 전용 endpoint(O2PN-C2)로, 정상 reverse-proxy mode(/oauth2/start,/oauth2/callback)와 경로가 다르다. nginxauth_request는 이 endpoint 만 부른다 — 두 mode 를 혼동하면 302 루프가 난다. - 4kb cookie 함정: cookie-backed store가 access token을 encrypted cookie에 실으면 nginx 기본 헤더 한도(4kb)를 넘어 split cookie가 되고, nginx가 첫
Set-Cookie만 복사하는 문제(O2PN-C6)가 있다. Redis/server-side store에서는 이 크기 위험 대신 state-store 운영 위험을 검증한다. - 본 sub-branch 는
documented-only.wiki/projects/승급은 root 의 6-패턴 비교 매트릭스 시점에 일괄 처리(개별 승급 없음).
결정 사항 (decisions)
- D1 2026-05-25: 선택을 두 축으로 분리한다.
- Ingress 축: Ingress-Nginx면
auth_request, Traefik이면forwardAuthmiddleware를 사용한다. - Auth service 축: oauth2-proxy를 baseline OIDC agent로 두며, 다른 호환 auth service를 쓰려면 동일한 allow/deny·header contract를 검증한다.
- Traefik
forwardAuth는 OIDC session provider 자체가 아니라 외부 auth service를 호출하는 middleware다. 따라서Traefik + oauth2-proxy는 정상 조합이며 상호 배타적 대안이 아니다.
- Ingress 축: Ingress-Nginx면
- D2 2026-05-25: 헤더 이름은 nginx 측
X-Auth-Request-User가 사실상 표준 (oauth2-proxy 응답 헤더). Traefik의X-Forwarded-User는 oauth2-proxy 측 옵션--pass-user-headers가 추가 발급하는 헤더로, 본 문서에서는 nginx 계열 명명 우선. - D3 2026-05-25: 백엔드 인증 코드를 제거하고 edge proxy 의 ForwardAuth subrequest 로 인증 위임 (Edge ForwardAuth 패턴 채택).
- D4 2026-05-25: header spoofing 방어를 위해 ingress-only traffic 강제 (K8s NetworkPolicy 또는 VPC SG) — backend 가 ingress 외 경로로 도달 불가해야 함.
결정-근거 매핑
본 sub-branch 의 P1A Edge ForwardAuth 패턴 채택 결정과 raw source claim 매핑. claim 형식
raw/<category>/<slug>.md#<CLAIM-ID>.
| Decision ID | Decision | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|
| D1 | Ingress 축(nginx auth_request / Traefik forwardAuth)과 auth service 축(oauth2-proxy / compatible OIDC agent)을 분리. baseline은 두 ingress 모두 oauth2-proxy 호출 |
raw/official-docs/oauth2-proxy-overview-config-official.md#OAUTH2PROXY-C2, raw/official-docs/oauth2-proxy-overview-config-official.md#OAUTH2PROXY-C3, raw/official-docs/oauth2-proxy-keycloak-oidc-provider-official.md#O2PK-C1, raw/official-docs/oauth2-proxy-keycloak-oidc-provider-official.md#O2PK-C2, raw/official-docs/oauth2-proxy-nginx-integration-official.md#O2PN-C1, raw/official-docs/traefik-forwardauth-middleware-official.md#TFA-C1, raw/official-docs/traefik-forwardauth-middleware-official.md#TFA-C3, raw/official-docs/traefik-forwardauth-middleware-official.md#TFA-C4 |
official-vendor-doc (3 vendors: oauth2-proxy + Keycloak + Traefik) |
ingress별 비-2XX 처리 차이와 auth service 대체 호환성은 실측 필요 |
| D2 | 헤더 명명은 nginx 계열 X-Auth-Request-User (oauth2-proxy 응답 헤더) 우선 |
raw/official-docs/oauth2-proxy-overview-config-official.md#OAUTH2PROXY-C3, raw/official-docs/oauth2-proxy-overview-config-official.md#OAUTH2PROXY-C4, raw/official-docs/oauth2-proxy-nginx-integration-official.md#O2PN-C3 |
official-vendor-doc |
X-Auth-Request-* (subrequest mode response headers) vs X-Forwarded-* (--pass-user-headers upstream forwarding) 의 정확한 default 활성화 여부는 OAUTH2PROXY-C4 의 "Does not prove" 에 명시 — 별도 config 확인 필요 |
| D3 | 백엔드 인증 코드 제거 + edge proxy 의 ForwardAuth subrequest 로 인증 위임 (Edge ForwardAuth 패턴 채택) | raw/official-docs/nginx-auth-request-module-official.md#NGAR-C1, raw/official-docs/nginx-auth-request-module-official.md#NGAR-C2, raw/official-docs/nginx-auth-request-module-official.md#NGAR-C4, raw/official-docs/nginx-auth-request-module-official.md#NGAR-C5, raw/official-docs/oauth2-proxy-nginx-integration-official.md#O2PN-C2, raw/official-docs/oauth2-proxy-nginx-integration-official.md#O2PN-C5, raw/official-docs/traefik-forwardauth-middleware-official.md#TFA-C1 |
official-standard (nginx) + official-vendor-doc (oauth2-proxy, Traefik) |
"다중 백엔드에 일관 인증" / "백엔드 코드 0줄" 의 운영상 이점은 본 raw claim 들이 직접 enumerate 하지 않음 — 운영 관행 추론 |
| D4 | header spoofing 방어 — ingress-only traffic 강제 (NetworkPolicy / VPC SG) | UNSUPPORTED_DECISION (오current Sources 표 에는 NetworkPolicy / VPC SG enforcement 의 공식 raw 가 없음 — sub-sub-branch feature-keycloak-header-spoofing-defense 에서 별도 raw 보존 필요) |
internal-reasoning (보안 일반 원칙) |
NetworkPolicy default deny / VPC SG 정확한 구성 패턴이 본 sub-branch 의 Sources 표에 부재. 구현 단계 진입 전 K8s NetworkPolicy 공식 doc + AWS SG 공식 doc 을 raw 로 보존 필요 |
구현 가이드
본 sub-branch 는
documented-only— 산출물은 코드가 아니라 패턴 문서다. 아래는 root branch P3A 에서 실제 구현 시 이 branch 의 결정(D1~D4)이 강제하는 config 앵커의 사전 명세. 모든 항목 등급planned(코드 미존재 —src/grep 으로 확정 안 됨).NO_GROUND_TRUTH: 본 branch 는keycloak-patterns학습 프로젝트 소속으로 ca-tmpl skeleton 범위 밖 인프라 설정이다 — error-codes/env-keys/headers registry 등 ca-tmpl 계약 SSOT 대조 대상이 아니며, 근거는 vendor 공식 doc(oauth2-proxy / nginx / Traefik)이다.
1. oauth2-proxy config (K8s + Ingress-Nginx 경로)
Trace: D1(nginx ingress + oauth2-proxy baseline) + D2(헤더 명명 nginx 계열). Supporting:
OAUTH2PROXY-C2,O2PK-C1,O2PK-C2,O2PN-C3.
- UNSUPPORTED_IMPL_DECISION: 없음 — 아래 파라미터·값은 vendor doc 이 verbatim 명시.
| 설정 | 값 | 근거 claim |
|---|---|---|
--provider |
keycloak-oidc |
O2PK-C1 |
--client-id / --client-secret / --oidc-issuer-url |
confidential client 3종 필수 파라미터 | O2PK-C1 |
| issuer URL 패턴 | Keycloak 17+ https://<host>/realms/<realm> (17 미만 legacy /auth/realms/...) |
O2PK-C2 |
--set-xauthrequest |
활성 — X-Auth-Request-User/-Email 응답 헤더 발급 (subrequest mode) |
O2PN-C3 |
2. nginx auth_request location block
Trace: D3(edge ForwardAuth 로 인증 위임). Supporting:
NGAR-C1,NGAR-C2,NGAR-C4,NGAR-C5,O2PN-C2,O2PN-C5.
- UNSUPPORTED_IMPL_DECISION: named location 이름(
@oauth2_signin)은 관례적 명명 — 임의 선택 가능(vendor 예시 관용값). 강제되는 것은 이름이 아니라 "401 → 302 redirect" contract(O2PN-C5)뿐. trade-off: 관용값을 벗어나면 남의 예시 config 를 그대로 못 붙임.
| 디렉티브 | 역할 | 근거 claim |
|---|---|---|
auth_request /oauth2/auth; |
보호 location 에서 subrequest 발사 (URI = oauth2-proxy subrequest endpoint) | NGAR-C4, O2PN-C2 |
| subrequest 응답 contract | 2xx=allow, 401/403=deny | NGAR-C2, O2PN-C2 |
auth_request_set $user $upstream_http_x_auth_request_user; (+ $email) |
subrequest 응답 헤더 → main request 변수 | NGAR-C5, O2PN-C3 |
proxy_set_header X-User $user; (+ X-Email $email;) |
backend 로 사용자 식별 헤더 주입 | O2PN-C3 |
error_page 401 = @oauth2_signin; → return 302 /oauth2/sign_in?rd=... |
미인증 브라우저 302 redirect | O2PN-C5 |
| nginx build | --with-http_auth_request_module 필수 (기본 빌드 미포함) |
NGAR-C1 · 검증 → §Claims 1 (NGAR-C7) |
3. Traefik forwardAuth ingress variant (auth service는 별도)
Trace: D1(Traefik ingress 축).
forwardAuth.address는 oauth2-proxy 또는 호환 auth service를 가리킨다. Supporting:TFA-C1,TFA-C3,TFA-C4.
- UNSUPPORTED_IMPL_DECISION: nginx(401/403 만 deny)와 Traefik(모든 non-2XX 를 302 포함 client 에 그대로 전달)의 비-2XX 처리 contract 차이는 vendor doc 이 명시(
TFA-C1)하나, 두 경로가 동일 로그인 UX 를 내는지는 미실측 → §Claims 5. trade-off: 두 경로를 "동등"으로 문서화하려면 이 실측이 선행.
| 미들웨어 옵션 | 역할 | 근거 claim |
|---|---|---|
forwardAuth.address |
oauth2-proxy /oauth2/auth 로 위임, 2XX=allow + 원본 요청 진행 |
TFA-C1 |
authResponseHeaders |
인증 서버 응답 헤더(X-Auth-Request-*)를 forwarded request 로 복사 (충돌 헤더 대체) |
TFA-C3 |
authRequestHeaders |
인증 서버로 전달할 request 헤더 필터 (비우면 전부 전달 — sensitive 헤더 노출 주의) | TFA-C4 |
4. ingress-only 강제 (header spoofing 방어) — 자식 branch 로 위임
Trace: D4(
UNSUPPORTED_DECISION).
- R3 OUT_OF_BRANCH_SCOPE: NetworkPolicy default-deny / VPC SG 의 구체 구성은 P1A 결정 범위 밖 — 자식 sub-sub-branch raw/branch-notes/feature-keycloak-header-spoofing-defense 가 owner. 본 branch 는 "ingress 외 경로로 backend 도달 불가를 강제해야 한다"는 원칙만 명시하고 enforcement detail 은 재진술하지 않는다(포인터만).
엣지·실패·의존
R4(깊이 게이트) 캡처. 정상 경로(§토큰 교환 sequence) 외 구현 중 부딪힐 실패·엣지 + 다른 계약 의존.
- 실패·엣지 경로:
- proxy SPOF: oauth2-proxy 다운 → 같은 ingress 뒤 모든 backend 접근 불가(§단점). 기대 동작: HA(replica ≥2) + readiness probe. 미구성 시 단일 장애점.
- 4kb cookie 초과 / split cookie: access_token 을 cookie 에 실으면 nginx 헤더 한도 초과 → nginx 가 첫
Set-Cookie만 복사(O2PN-C6). 기대 동작: cookie 분할 처리 또는 access_token 을 cookie 에 싣지 않음. → §Claims 2. - 미인증 XHR/API 요청:
O2PN-C5의 401→302 redirect 는 브라우저 전제. API client 는 302 를 따라가지 못함. 기대 동작:Accept: application/json요청엔 401 유지(별도 처리 —O2PN-C5"Does not prove" 참조). - nginx build 에 auth_request 모듈 부재: 기본 빌드 미포함(
NGAR-C7) →auth_requestdirective 무효화. 기대 동작: 기동 시 config 오류로 조기 실패. → §Claims 1. - nginx vs Traefik 비-2XX contract 차이: oauth2-proxy 가 5xx 반환 시 nginx(401/403 만 deny, 그 외 error)와 Traefik(모든 non-2XX 를 client 에 전달)의 최종 응답이 갈림(
TFA-C1). → §Claims 5.
- 다른 계약 의존 (대상 브랜치 + 그 Decision ID 병기):
- raw/branch-notes/feature-keycloak-header-spoofing-defense
D1(백엔드 ingress-뒤 격리 = 1차 방어) +D3(K8s NetworkPolicy default-deny) /D4(EC2 Security Group + private-subnet listen) 에 의존 — 이 계약이 없으면 본 branchD3(헤더 trust)의 전제가 깨져 외부에서X-Auth-Request-User위조가 가능해지고 P1A 패턴 전체가 무력화된다. 본 branchD4는 원칙만 선언, enforcement detail 은 이 자식 owner. - raw/branch-notes/feature-keycloak-oauth2-proxy-oidc-flow
D2(oauth2-proxyprovider=keycloak-oidc+--client-id/-secret/-oidc-issuer-url+ Keycloak 17+ issuer URL 패턴)가 §sequence step 3~6 handshake 의 owner. 이 계약이 바뀌면 본 branch §구현 가이드 1 의 config 앵커(D1/D2)가 영향받음. - raw/branch-notes/feature-keycloak-nginx-auth-request-integration
D2(subrequest 2xx/401/403 contract) +D3(auth_request_set→proxy_set_header2-step 헤더 전파) +D5(4kb cookie split 대응)가 본 branch §구현 가이드 2(nginxauth_requestblock)의 owner. - P1B 변형 raw/branch-notes/feature-keycloak-edge-forwardauth-google-federation — Google federation을 추가해도 raw/branch-notes/feature-keycloak-edge-forwardauth-no-google D3의 header-only backend trust를 그대로 consume한다.
- raw/branch-notes/feature-keycloak-header-spoofing-defense
검증해야 할 주장
본 sub-branch 는
documented-only단계. 구현 진입 시 검증해야 할 주장 enumerate.
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
nginx 빌드에 --with-http_auth_request_module 가 활성화되어 있음 |
NGAR-C7 명시 — 기본 빌드에 포함되지 않음 |
nginx -V 2>&1 | grep -o with-http_auth_request_module |
planned (구현 진입 시) |
| oauth2-proxy 가 큰 access_token (Keycloak refresh token 포함) 을 cookie 4kb 한도 내에서 처리 또는 split | O2PN-C6 명시 — 분할 cookie 시 nginx 가 첫 Set-Cookie 만 복사 |
docker-compose 환경에서 큰 토큰 발급 후 브라우저 cookie 확인 + nginx access_log 의 Set-Cookie 헤더 검사 | planned |
--set-xauthrequest 활성화 시 nginx auth_request_set 이 backend 까지 X-User / X-Email 헤더 전파 |
O2PN-C3 가 contract 명시했으나 실제 nginx config 의 proxy_set_header 작성 필요 |
backend 에 echo endpoint 추가 후 curl 로 헤더 확인 | planned |
| backend 가 ingress-only traffic 만 받음 (header spoofing 우회 차단) | D4 의 UNSUPPORTED_DECISION 와 동일 — 정책 enforcement 가 실제로 강제되는지 별도 검증 필요 | K8s: NetworkPolicy default-deny 적용 후 다른 namespace 에서 curl 시도 → 차단 확인. VM: backend listen address 가 loopback / private subnet 인지 ss -tln 확인 |
needs-confirmation |
Traefik forwardAuth 의 비-2XX 응답 처리가 nginx auth_request 와 호환 가능 |
TFA-C1 가 "비 2XX 응답은 그대로 client 에 반환" 명시 — nginx 의 "401/403 만 deny, 그 외 error" 와 contract 차이 |
두 환경에서 oauth2-proxy 가 5xx 반환 시 client 가 받는 응답 비교 (curl -v) | planned |
마주친 문제
- 아직 없음(문서 단계).
묶음 (자식 sub-sub-branches)
- raw/official-docs/nginx-auth-request-module-official
- raw/official-docs/oauth2-proxy-endpoints-official
- raw/official-docs/oauth2-proxy-keycloak-oidc-provider-official
- raw/official-docs/oauth2-proxy-nginx-integration-official
- raw/official-docs/oauth2-proxy-overview-config-official
- raw/official-docs/traefik-forwardauth-middleware-official
- raw/branch-notes/feature-keycloak-oauth2-proxy-oidc-flow — oauth2-proxy 구성과 OIDC 흐름
- raw/branch-notes/feature-keycloak-nginx-auth-request-integration — nginx auth_request 통합 (4kb cookie 함정)
- raw/branch-notes/feature-keycloak-header-spoofing-defense — 헤더 spoofing 방어 (NetworkPolicy / SG / mTLS)
- raw/branch-notes/feature-keycloak-traefik-forwardauth-alternative — Traefik ForwardAuth 대안 비교
Sources / 근거 자료는 본 문서 하단 "외부 근거 / 대안 조사" 섹션 참조. Errors / Interview prep / Lectures 는 현재 없음 (Phase 3 P3A 실 구현 또는 외부 산출물 단계에 누적 예정).
관련 일일 노트
관련 sub-branch
- raw/branch-notes/feature-keycloak-patterns (root)
- raw/branch-notes/feature-keycloak-edge-forwardauth-google-federation — P1B Edge + Google federation (본 패턴의 federation 변형)
외부 근거 / 대안 조사 (2026-05-25 — P1A Edge Forward Auth)
본 sub-branch의 Edge ForwardAuth 패턴 채택에 대한 외부 source 조사. 대안은 동일 목적(브라우저 인증 + 백엔드 신뢰)을 다른 방식으로 달성하는 패턴들과 비교.
- 채택 결정 (nginx
auth_request또는 TraefikforwardAuthingress + oauth2-proxy baseline + Keycloak):- raw/official-docs/oauth2-proxy-overview-config-official — oauth2-proxy 공식 (Reverse proxy + auth provider integration)
- raw/official-docs/oauth2-proxy-keycloak-oidc-provider-official — oauth2-proxy ↔ Keycloak OIDC 연동
- raw/official-docs/oauth2-proxy-nginx-integration-official — nginx auth_request 통합
- raw/official-docs/nginx-auth-request-module-official — nginx ngx_http_auth_request_module (2xx=allow / 401|403=deny contract)
- raw/official-docs/traefik-forwardauth-middleware-official — Traefik ForwardAuth middleware (K8s 환경 대안)
- 검토한 대안:
- 대안 1: SPA Direct OIDC + Resource Server (P2A) — 클라이언트가 직접 Keycloak 호출, 백엔드는 JWT validator. 장: 백엔드 stateless / 단: SPA에 token 노출. 비교 sub-branch: raw/branch-notes/feature-keycloak-internal-spa-direct-no-google.
- 대안 2: BFF (Backend-for-Frontend) — 백엔드 session cookie + 백엔드가 token holder. 장: XSS surface 축소 / 단: 백엔드 stateful. (Curity / Philippe De Ryck 권고).
- 대안 3: API Gateway 인증 (Kong, AWS API Gateway + Cognito) — vendor lock-in + cloud 종속.
- 대안 4: Service Mesh (Istio AuthorizationPolicy + JWT filter) — K8s mesh 인프라 전제.
- 대안 5: 백엔드 직접 인증 (Spring Security
oauth2Login) — 백엔드가 redirect/callback 처리. 단일 서비스에는 단순하나 다중 서비스 시 중복.
- 비교 핵심: Edge ForwardAuth는 다중 백엔드 서비스가 동일 인증을 공유할 때 가장 단순. 백엔드 코드 0줄 인증. 단, header spoofing 방어 (ingress-only traffic 강제 — K8s NetworkPolicy 또는 VPC SG) 필수. SPA Direct는 mobile/IoT까지 같은 token으로 쓸 때 유리. BFF는 XSS 민감 환경(예: 금융). Service Mesh는 이미 mesh 도입된 환경.
완료 후 정리
본 sub-branch는 문서까지만. wiki 추출은 root branch의 비교 매트릭스 시점에 일괄 처리.
- PR 링크:
- 리뷰 메모:
- 머지 결과 / 배포 환경: 해당 없음 (문서 단계)
- wiki 추출 대상 (verified만,
wiki/projects/로만 추출):actually-implemented항목: 없음locally-verified항목: 없음prod-verified항목: 없음
- 추출하지 않을 항목 (planned / documented-only / abandoned):
- 본 sub-branch 전체가
documented-only등급. 추후 root branch의 6 패턴 비교 매트릭스에 인용되는 형태로만 활용.wiki/projects/직접 승급 없음.
- 본 sub-branch 전체가