Files
llm-wiki/raw/branch-notes/feature-keycloak-three-leg-trust-chain.md
T

31 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-three-leg-trust-chain (3-leg trust chain — Browser ↔ Keycloak ↔ Google 검증 메커니즘) branch-note raw BR-KEYCLOAK-CHILD-11A28CFF branch-child keycloak-patterns-overview WI-KEYCLOAK-PATTERNS-OVERVIEW-015
DEC-KEYCLOAK-PATTERNS-OVERVIEW-IDP-BROKERING-001@1
WI-KEYCLOAK-PATTERNS-OVERVIEW-003
1 feature-keycloak-three-leg-trust-chain feature-keycloak-idp-brokering-google-client
keycloak-patterns
branch
keycloak-patterns
spa
idp-brokering
google-federation
trust-chain
jwt
p2b
2026-05-25 in-progress 1af4709799789103babb4b3503ffefc67f35e51a4eb8c5175c4928267a419143

branch: feature-keycloak-three-leg-trust-chain (3-leg trust chain 검증)

Layer: raw/branch-notes/raw/branch-notes/feature-keycloak-idp-brokering-google-client의 WI015 child branch. 학습 노트. P2B는 documented-only 단계.

본 노트의 역할 (2026-07-18 /branch-spec 정리): 본 노트는 부모 P2B(raw/branch-notes/feature-keycloak-internal-spa-direct-google-federation) 가 hop 별 검증 매트릭스의 owner 로 위임한 결정(D5)의 정본이다(부모 §신뢰 경계 delegation). 부모는 이 D5 를 consume 만 하며, 본 노트가 각 hop 의 누가·무엇을·어떻게 검증하는가 를 소유한다.

부모 (필수)

raw/branch-notes/feature-keycloak-idp-brokering-google-client

브랜치 계약 패킷

  • 생성 시 프로젝트 개정: 1
  • 패킷 스키마: contract_packet: 1
  • 완료 조건: Google login·Keycloak user mapping 200과 application diff 0줄이 검증된다

상속한 프로젝트 결정

Decision Ref Project Summary Branch Application Source
DEC-KEYCLOAK-PATTERNS-OVERVIEW-IDP-BROKERING-001@1 Google federation은 Keycloak IdP brokering과 hardened First Broker Login을 사용한다 Browser·Keycloak·Google의 hop별 trust verification에 적용한다 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

없음.

목표

P2A는 2-leg trust (Browser ↔ Keycloak)였으나, P2B는 3-leg trust (Browser ↔ Keycloak ↔ Google). 각 hop마다 누가 무엇을 검증하는지 명확히 정리.

면접 질문: "Google 로그인이 추가되면 신뢰 검증이 어떻게 늘어나나요?" → "OIDC 표준상 RP는 Google ID token의 signature·issuer·audience·expiry와 요청에 보낸 nonce 일치를 검증해야 합니다. 이 배치에서는 Keycloak이 RP 역할을 맡지만, target Keycloak 버전이 nonce를 자동 송신·대조하는 제품 동작은 아직 wire trace로 확인하지 않았습니다. 이후 Keycloak이 자체 서명한 access token을 발급하고 backend는 Keycloak issuer/JWKS만 신뢰합니다."

  • 이슈:
  • PR:

범위

포함 범위

  • Hop 1: Google → Keycloak — Google ID token signature 검증
  • Hop 2: Keycloak → SPA — Keycloak access token signature 발급
  • Hop 3: SPA → Backend — backend의 Keycloak JWT 검증
  • Issuer 검증 규칙:
    • Google iss=https://accounts.google.com정확히 이 문자열. (⚠️ 정정 2026-07-18: 원래 여기 "또는 accounts.google.com — spec 상 둘 다 허용" 이라 적었으나 사실과 다르다. 아카이브 근거 raw/official-docs/google-oidc-discovery-spec.md#GOOGLE-OIDC-C1 의 discovery JSON 은 iss 를 정확히 https://accounts.google.com 로만 규정하고, 그 "Does not prove" 열이 bare-hostname alias 를 명시적으로 부인한다. §Claims To Verify CV1 참조.)
    • Keycloak iss=https://kc.example.com/realms/{realm-name}
  • JWKS rotation 정책 비교 (Google vs Keycloak)
  • Keycloak이 Google jwks_uri를 캐시하는 방식

제외 범위

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

Source 정당화하는 결정
raw/official-docs/keycloak-first-broker-login-flow First Broker Login Flow 존재 + account linking 시점 (D4)
raw/official-docs/spring-security-resource-server-jwt 백엔드가 단일 issuer(Keycloak) JWKS 로 self-configure + iss/aud 검증 (D1, D5 Hop3, CV4)
raw/official-docs/google-oidc-discovery-spec Google issuer 문자열 + RS256 + nonce Required + local validation (D5 Hop1, D3, CV1)
raw/official-docs/security-jwt-rfc-7519-validation JWT aud MUST-reject / exp MUST-NOT-accept (D5 Hop1·Hop3 aud·exp)
raw/official-docs/google-oauth2-redirect-uri-validation-official redirect URI 정확 매칭 → redirect_uri_mismatch (CV7)
raw/official-docs/openid-connect-core-id-token-validation OIDC Core 1.0 §2/§3.1.2.1/§3.1.3.7 — ID Token aud=RP client_id + nonce 검증 mandatory (OIDC-CORE-C1~C5; D5 Hop1-aud·nonce, D3)
raw/official-docs/jwks-keycloak-key-rotation-active-passive Keycloak 이 자체 active key pair 로 새 서명 생성 (KC-ROT-C1) — D5 Hop2(Keycloak→SPA 재서명) 근거로만. ⚠️ 아래 disambiguation

인용 범위 한정 (disambiguation): raw/official-docs/jwks-keycloak-key-rotation-active-passive.md (KC-ROT-C*) 는 Keycloak 자신의 realm 서명키 active-passive 회전이다 — D5 Hop2(Keycloak 이 자체 키로 재서명)의 근거로는 유효하나, 외부 Google JWKS 캐시(D2)와는 무관하다. D2 근거로 인용하면 파일명의 "JWKS" 에 낚인 FILENAME_INFERENCE 오용이다.

TODO

  • 3-leg 다이어그램 작성 (각 hop의 검증 항목 표기) — 등급: documented-only (§구현 가이드 §1 매트릭스로 승격)
  • Google ID token 검증 항목 정리: signature(RS256, JWKS), iss, aud, exp, nonce — 등급: documented-only (§구현 가이드 §1, cell 별 근거)
  • Google iss 허용값 — 정정 완료: https://accounts.google.com 단일 (bare-hostname alias 는 spec 부인). 근거 #GOOGLE-OIDC-C1 — 등급: documented-only (CV1 resolved-as-contradiction)
  • Keycloak access token 검증 항목 정리 (backend 측): signature, iss, aud, exp — 등급: documented-only (§구현 가이드 §1 Hop3, SSRS-JWT-C1/C2/C6). ※azp/typ=Bearer 는 본 노트 Sources 에 직접 인용 없음 → 형제 audience-validator 매트릭스 소관
  • Google JWKS rotation 빈도 (수일~수주 주기, 정확한 SLA 없음) — 등급: needs-confirmation (CV2, 아카이브 부재 — live header 관찰 필요)
  • Keycloak이 Google jwks_uri를 캐시하는 정책: 기본 캐시 TTL, expired key fallback — 등급: needs-confirmation (CV3/D2, 아카이브 부재 — Keycloak IdP config doc/소스 필요)
  • 함정: Keycloak이 Google JWKS 캐시 갱신 실패 시 Google 로그인 전체 장애 → fallback 정책 확인 — 등급: needs-confirmation (§엣지·실패·의존)
  • 함정: backend가 Keycloak issuer를 잘못 적으면 모든 Google-originated token 거부 — 등급: documented-only (CV4 resolved, SSRS-JWT-C6 — 단 local 재현은 planned)

진행 중 메모

  • 핵심 통찰: backend는 Google을 모른다. backend의 JWT validation 코드는 Keycloak issuer / Keycloak JWKS만 본다. Google 추가/제거는 backend 코드에 영향 없음.
  • 누가 무엇을 검증하나 정리 (§구현 가이드 §1 로 명세 승격 — 아래는 원본 통찰 보존):
Hop 검증자 검증 대상 검증 항목
Google → Keycloak Keycloak Google ID token signature(RS256, Google JWKS), iss, aud=Keycloak이 보유한 Google client_id, exp, nonce
(Keycloak 내부) Keycloak First Broker Login Flow 정책 email_verified, hd, Account Linking 결정
Keycloak → SPA (Keycloak이 발급) Keycloak access token (Keycloak이 RS256 서명)
SPA → Backend Backend Keycloak access token signature(Keycloak JWKS), iss=https://kc/realms/{r}, aud=<backend-client-id>, exp
  • Google JWKS 키 갱신 빈도가 빠른 편. spec에는 정해진 SLA 없음. Keycloak이 캐시한 키가 만료되었을 때 자동 refetch 필요.
  • redirect URI 변조 방지: Google Cloud Console에 등록된 redirect URI 외 거부. Keycloak broker endpoint URL 변경 시 Google에도 반영 필요.
  • nonce 검증 계약: OIDC RP는 요청의 nonce와 ID token nonce를 대조해야 한다. Keycloak이 이를 자동 송신·대조하는 target-version 제품 동작은 needs-confirmation이며 HAR/source 확인 전 사실형으로 표현하지 않는다.
  • 2026-07-18 (/branch-spec 채움 pass) — pre-template(2026-05-25) 노트를 템플릿 정합으로 보강: 선택 조건(R2) 열 추가 · ## 구현 가이드(§1 Hop별 검증 계약 · §2 issuer/audience 문자열 정합) · ## 엣지·실패·의존 추가 · Sources 1→6 확장 · 섹션 순서 템플릿 정렬(Cluster 하단·Sources 상단). NO_GROUND_TRUTH — keycloak-patterns 는 실 구현 repo(/home/donghyeon/workspace/keycloak-patterns/, 부재 확인)가 없어 전 항목 documented-only/needs-confirmation(코드 grep 불가). ca-tmpl 은 별개 프로젝트지만 APP_SECURITY_JWT_ISSUER env-key + AUTH_ISSUER_MISMATCH 에러코드가 D1/CV4 의 "단일 issuer" 원리를 실물로 예시(cross-project 참고, 본 노트 등급엔 미반영).
  • 자동조사wiki-research-lane 로 기존 아카이브 8+5 문서를 재앵커링: D1 + D5 의 12 cell 중 8개가 official 근거 획득(이전엔 D4 외 전부 UNSUPPORTED_DECISION). 신규 조사 1건(OIDC Core spec 아카이브)으로 Hop1-aud/nonce cell 을 승격. deferred 3건(Keycloak 외부 JWKS 캐시·Google rotation cadence·Keycloak 기본 서명 알고리즘 — 아카이브 문서로 안 닫히는 runtime/config-empirical 항목, §Claims To Verify 로 위임).

결정 사항 (decisions)

  • 2026-05-25: backend는 Keycloak JWKS만 신뢰 — Google JWKS는 backend 측에서 절대 검증하지 않음. 이유: 신뢰 경계 단순화. backend 입장에서 IdP는 Keycloak 하나.
  • 2026-05-25: Google JWKS rotation은 Keycloak 책임 — Keycloak realm export / restore 시 캐시 초기화될 수 있음. 운영 시 모니터링 항목.
  • 2026-05-25 (정합 2026-07-18): nonce 검증은 OIDC RP 의무다. Keycloak 자동 처리 및 비활성화 옵션 존재 여부는 target version에서 미검증이다.

결정-근거 매핑

본 branch 의 결정-근거 매핑. 선택 조건 열(R2, 2026-07-18 /branch-spec 추가): "이 조건일 때 이 결정, 다른 조건이면 어떤 대안". 분기 없는 원리 진술은 N/A. 2026-07-18 재앵커링: 이전 판은 D4 외 전부 UNSUPPORTED_DECISION 이었다(당시 Source 가 keycloak-first-broker-login-flow 1개뿐). wiki-research-lane 가 기존 아카이브에서 D1·D5(8/12 cell)·D3(일부)의 직접 근거를 발굴 + OIDC Core 신규 아카이브로 Hop1-aud/nonce 를 닫아 재mapping 했다. D2 와 D5 의 4 cell 은 genuine gap 으로 남아 라벨 유지.

Decision ID Decision 선택 조건 (언제 이 결정 / 언제 대안) Supporting Claims Evidence Strength Open Risk
D1 backend 는 Keycloak JWKS 만 신뢰 (Google JWKS 는 backend 측에서 절대 검증하지 않음) 백엔드가 JWT 를 직접 검증하는 Resource Server(P2B)면 단일 issuer(Keycloak)만 신뢰가 기본 — issuer-uri 한 줄이 정확히 1개 AS 로 self-configure. 대안(백엔드가 Google JWKS 도 검증)은 신뢰 경계를 2개로 늘려 federation 추가/제거마다 백엔드 변경 유발 → 기각. 백엔드가 JWT 자체를 안 보는 구성이 필요하면 배치를 Edge forward-auth(P1B)로 바꿈(별도 패턴) raw/official-docs/spring-security-resource-server-jwt.md#SSRS-JWT-C1 (issuer-uri 로 self-configure + iss 검증), raw/official-docs/spring-security-resource-server-jwt.md#SSRS-JWT-C2 (4단계 deterministic discovery — 단일 AS 의 jwks_url) official-vendor-doc multi-issuer 는 JwtIssuerAuthenticationManagerResolver 별도(범위 밖). "신뢰 경계 단순화" 는 이제 mechanism 근거 보유(이전 UNSUPPORTED 해소). cross-project 실물 예시: ca-tmpl APP_SECURITY_JWT_ISSUER(단일 issuer URI 필수) + AUTH_ISSUER_MISMATCH 에러코드
D2 Google JWKS rotation(=외부 IdP JWKS 신선도)은 Keycloak 책임 (realm export/restore 시 캐시 초기화 가능, 운영 모니터링 항목) Keycloak 이 broker 로서 Google id_token 을 검증하는 모든 P2B 구성 — 대안 없음: 백엔드가 Google 을 안 보므로(D1 의 따름) Google JWKS 신선도는 구조상 Keycloak 만 담당 가능. 단 캐시 TTL/fallback 동작은 미검증 UNSUPPORTED_DECISION (Keycloak 의 외부 IdP JWKS 캐시 정책/TTL/fallback 은 아카이브 부재 — wiki-research-lanekeycloak-identity-brokering-overview-official·keycloak-identity-broker-spi·keycloak-import-export-realms 3개 추가 확인했으나 어느 것도 미기술. jwks-keycloak-key-rotation-active-passive.md 는 Keycloak 자체 realm 키 회전이라 D2 근거 아님 — 위 disambiguation) UNSUPPORTED_DECISION 캐시 refetch 실패 시 Google 로그인 전체 5xx(§엣지·실패·의존). monitoring alarm 설계 전 Keycloak IdP config 페이지 또는 소스(OIDCIdentityProvider) 확인 의무 — §Claims To Verify CV3
D3 OIDC RP는 nonce를 송신하고 ID Token의 nonce 일치를 검증해야 한다. target Keycloak의 자동 처리 여부는 별도 제품 검증 Google brokering의 replay 방지 계약. 표준 의무와 특정 제품 동작을 분리한다 raw/official-docs/google-oidc-discovery-spec.md#GOOGLE-OIDC-C5, raw/official-docs/openid-connect-core-id-token-validation.md#OIDC-CORE-C2, #OIDC-CORE-C5 official-standard (의무) / needs-confirmation (Keycloak 제품 동작) Keycloak 자동 송신·대조와 설정 토글은 HAR/source 확인 전 외부 주장 금지
D4 Keycloak 의 First Broker Login Flow 가 외부 IdP (Google) 로 첫 로그인 시 account linking 정책을 실행한다는 일반 진술 N/A (원리 진술 — account linking 의 정확한 정책은 owner 형제 raw/branch-notes/feature-keycloak-first-broker-login-flow 소관) raw/official-docs/keycloak-first-broker-login-flow.md#KC-FBL-C1 (First login flow 존재 + sub-section 구조) official-vendor-doc KC-FBL-C2~C4 는 needs-confirmation — verbatim 재검증 보류. account linking 의 정확한 동작(자동 link vs prompt)은 owner 형제 소관
D5 Hop 별 검증 매트릭스 (Hop1 Google→Keycloak / Hop2 Keycloak→SPA / Hop3 SPA→Backend) — 부모 P2B 가 위임한 owner 결정 N/A (검증 계약 명세, 분기 아님). 단 각 hop 검증 주체는 배치 의존: P2B(SPA direct)면 Hop3 검증자=백엔드 Resource Server, P1B(edge proxy)면 oauth2-proxy 대행(형제 패턴) cell 별(§구현 가이드 §1 표): Hop1-sig #GOOGLE-OIDC-C3·#GOOGLE-OIDC-C8; Hop1-iss #GOOGLE-OIDC-C1; Hop1-aud security-jwt-rfc-7519-validation.md#JWT-RFC7519-C1(generic) + openid-connect-core-id-token-validation.md#OIDC-CORE-C1/#OIDC-CORE-C4; Hop1-exp #JWT-RFC7519-C2; Hop1-nonce #GOOGLE-OIDC-C5+OIDC-CORE-C2/#OIDC-CORE-C5; Hop2 jwks-keycloak-key-rotation-active-passive.md#KC-ROT-C1(자체 active key 서명); Hop3-sig spring-security-resource-server-jwt.md#SSRS-JWT-C1·#SSRS-JWT-C2; Hop3-iss #SSRS-JWT-C1·#SSRS-JWT-C6; Hop3-aud #SSRS-JWT-C6; Hop3-exp #JWT-RFC7519-C2 official-standard + official-vendor-doc (8/12 cell) 4 cell 미해소(§구현 가이드 §1 UNSUPPORTED_IMPL_DECISION): ① Hop1-aud 의 Google-specific "aud=Keycloak client_id"(generic RFC + OIDC Core 로 원리는 닫히나 Google 명시 quote 부재), ② Hop2 default 알고리즘 RS256(KC-ROT-C1 은 "자체 active key 서명"만 증명, RS256 명시 없음), ③ Keycloak-side nonce 자동 동작(D3 와 동일 gap). §Claims To Verify

구현 가이드

본 branch 는 documented-only 학습 노트 — 실 구현 코드가 아니라 각 hop 의 검증 계약(누가·무엇을·어떻게 검증하는가)의 사전 명세다. 부모 P2B 가 이 §의 매트릭스를 hop 검증 owner 로 위임했다. 아래 sub-section 은 본 branch 결정(D1·D3·D5)에서만 도출한다.

3-rule: R1 각 cell 은 Decision ID + Claim ID reference. R2 근거 없는 detail 은 UNSUPPORTED_IMPL_DECISION 라벨 + trade-off. R3 본 branch 범위 밖(발급측 aud 주입·KC_HOSTNAME 고정)은 owner 형제로 위임(§엣지·실패·의존 다른 계약 의존).

1. Hop별 검증 계약 (verifier → 대상 → 항목 → 근거)

Trace: D5(전 cell) + D1(Hop3 단일 issuer 신뢰). 각 cell 은 아래 표의 Claim ID 로 근거. §진행 중 메모의 "누가 무엇을 검증하나" 통찰을 명세로 승격.

  • UNSUPPORTED_IMPL_DECISION:
    • Hop1-aud (Google-specific): "Google id_token 의 aud = Keycloak 이 등록한 Google client_id" 의 Google 명시 verbatim 은 아카이브에 없음. generic 근거(JWT-RFC7519-C1 aud MUST-reject) + OIDC Core(ID Token aud=RP client_id)로 원리는 닫히나, "Google 이 그렇게 발급한다" 는 INFERENCE. trade-off: OIDC RP-client 표준 의미상 거의 확실하나 FACT 승격은 Google Identity 페이지 또는 실 토큰 decode 필요(§Claims To Verify).
    • Hop2 서명 알고리즘 (RS256): KC-ROT-C1 은 "Keycloak 이 자체 active key pair 로 새 서명 생성"만 증명 — default 알고리즘이 RS256 이라는 근거는 아카이브 부재. trade-off: Keycloak 관례상 RS256 이 default 로 알려져 있으나 미검증 → 이 cell needs-confirmation.
    • Hop1-nonce (Keycloak-side): nonce 의 필요/검증 원리는 spec(§2 근거), 그러나 Keycloak 이 자동으로 송신/대조하는지는 미아카이브(D3 Open Risk 와 동일).
Hop 검증자 대상 검증 항목 근거 (Claim ID) cell 등급
Hop1 Google→Keycloak Keycloak Google id_token signature RS256 (Google JWKS, local 검증) #GOOGLE-OIDC-C3(RS256-only), #GOOGLE-OIDC-C8(retrieve keys + validate locally) documented-only
Hop1 Keycloak Google id_token iss = https://accounts.google.com (정확 문자열) #GOOGLE-OIDC-C1 documented-only
Hop1 Keycloak Google id_token aud = Keycloak 의 Google client_id #JWT-RFC7519-C1(generic aud MUST-reject) + OIDC-CORE-C1/#OIDC-CORE-C4(ID Token aud=RP client_id) ⚠️ UNSUPPORTED_IMPL_DECISION (Google-specific quote 부재)
Hop1 Keycloak Google id_token exp (만료 검증, clock-skew leeway) #JWT-RFC7519-C2 documented-only
Hop1 Keycloak Google id_token nonce 일치 (replay 방지) #GOOGLE-OIDC-C5(nonce Required) + OIDC-CORE-C2/#OIDC-CORE-C5 ⚠️ UNSUPPORTED_IMPL_DECISION (Keycloak 자동 동작 미검증)
Hop2 Keycloak→SPA (Keycloak 발급) Keycloak access_token 자체 active key 로 재서명 #KC-ROT-C1 (single active key pair → new signatures) ⚠️ needs-confirmation (알고리즘 RS256 명시 부재)
Hop3 SPA→Backend Backend RS Keycloak access_token signature (Keycloak JWKS, discovery) #SSRS-JWT-C1, #SSRS-JWT-C2 documented-only
Hop3 Backend RS Keycloak access_token iss = https://kc/realms/{r} (byte-match) #SSRS-JWT-C1, #SSRS-JWT-C6("iss 가 아니면 validation fail") documented-only
Hop3 Backend RS Keycloak access_token aud = backend-client-id #SSRS-JWT-C6 (audiences property → aud 검증) documented-only (발급측 aud 주입은 형제 audience-validator D4 의존)
Hop3 Backend RS Keycloak access_token exp #JWT-RFC7519-C2 documented-only

2. audience 문자열 정합 규칙 (byte-match + 발급측 선행)

Trace: D1 + D5 Hop3-iss(#SSRS-JWT-C1·#SSRS-JWT-C6) + Hop1-iss(#GOOGLE-OIDC-C1).

  • UNSUPPORTED_IMPL_DECISION: 없음 — 아래는 인용 claim 의 직접 도출.
항목 규칙 근거 의존(owner 형제)
Google iss 정확히 https://accounts.google.com — bare-hostname alias 금지(비교 실패) #GOOGLE-OIDC-C1 (+ Does-not-prove: alias 부인) — (CV1 correction)
Keycloak iss (Hop3) 백엔드 issuer-uri == token iss byte-level 일치. discovery 로 self-configure, 불일치 시 validation fail #SSRS-JWT-C1, #SSRS-JWT-C6 raw/branch-notes/feature-keycloak-iss-claim-hostname-mismatch D1 (KC_HOSTNAME 고정으로 iss 안정화)
Keycloak aud (Hop3) aud 에 backend-client-id 포함해야 통과. 발급측이 안 넣으면 aud=account 만 → 정상 토큰도 거부 #SSRS-JWT-C6 raw/branch-notes/feature-keycloak-spring-rs-audience-validator D4 (SPA client Audience mapper 선행)
Google redirect URI Keycloak broker endpoint 를 Google Console 에 정확 등록 — 불일치 시 redirect_uri_mismatch raw/official-docs/google-oauth2-redirect-uri-validation-official.md#GOOGLE-REDIR-C3 raw/branch-notes/feature-keycloak-google-redirect-uri-policy D1~D4 (exact-match 규칙 deep owner) + raw/branch-notes/feature-keycloak-idp-brokering-google-client D3 (등록 step)

엣지·실패·의존

R4 캡처용. 본 branch 는 documented-only 이나, 3-leg trust 를 실제로 세울 때 부딪힐 실패/엣지와 다른 계약 의존을 미리 열거.

  • 실패·엣지 경로:

    • Keycloak → Google JWKS refetch 실패 → Google 로그인 전체 5xx (가장 위험, 운영): Keycloak 이 Google jwks_uri 를 못 가져오면(네트워크 단절 / Google 측 변경) Hop1 signature 검증 불가 → 모든 Google 로그인 실패. 캐시 TTL·expired-key fallback 동작 미검증(D2/CV3 UNSUPPORTED). 기대 동작: 만료 시 자동 refetch(가정), monitoring alarm 필수.
    • 백엔드 issuer 오설정 → 모든 Google-originated token 거부: 백엔드 issuer-uri 가 Keycloak realm URL 과 byte-level 불일치면 Hop3 에서 iss 검증 실패 → Google 로 로그인한 사용자 포함 전 토큰 401. 근거 #SSRS-JWT-C6("iss 가 아니면 validation will fail"). 기대 동작: 의도적 오설정 시 401 (CV4, local 재현 planned).
    • Google iss alias 혼동 → Hop1 검증 실패: accounts.google.com(bare)로 비교하면 https://accounts.google.com 발급 토큰이 불일치. 근거 #GOOGLE-OIDC-C1(정확 문자열). CV1 정정 사항 — 과거 "둘 다 허용" 은 folklore.
    • nonce 미검증/재사용 → replay 취약: Hop1 에서 nonce 대조를 안 하면 탈취된 id_token 재생 가능(D3). 단 Keycloak 자동 검증 여부 미검증.
    • redirect URI 변조 → Google 거부: Keycloak broker endpoint 외 URI 는 redirect_uri_mismatch(#GOOGLE-REDIR-C3). Keycloak broker URL 변경 시 Google Console 반영 필요.
    • Keycloak 서명 알고리즘 가정 오류: 백엔드가 RS256 을 가정하는데 Keycloak realm 이 다른 알고리즘이면 Hop3 signature 검증 실패. Hop2 알고리즘 default 는 needs-confirmation(§구현 가이드 §1).
  • 다른 계약 의존:

검증해야 할 주장

Claim Why uncertain How to verify Status
[CV1 — resolved-as-contradiction] Google isshttps://accounts.google.comaccounts.google.com 둘 다 spec 상 정당한가 원래 "둘 다 허용" 으로 적었으나 아카이브가 반증 해소: raw/official-docs/google-oidc-discovery-spec.md#GOOGLE-OIDC-C1 — discovery JSON 은 iss 를 정확히 https://accounts.google.com 로만 규정, Does-not-prove 열이 alias 를 명시 부인. 본문 §마주친 문제의 "과거 사례" 는 미검증 folklore resolved (documented-only)
[CV4 — resolved] backend 가 Keycloak issuer 를 잘못 적으면 모든 Google-originated token 거부 메커니즘은 문서화, local 재현은 미실행 메커니즘 raw/official-docs/spring-security-resource-server-jwt.md#SSRS-JWT-C6("iss 가 아니면 validation will fail"). local 재현(issuer-uri 의도적 오설정 → 401)은 별도 planned documented-only (재현 planned)
[CV7 — resolved] Google Cloud Console redirect URI 정확 매칭(변조 방지) Source 미등록이었음 raw/official-docs/google-oauth2-redirect-uri-validation-official.md#GOOGLE-REDIR-C3(정확 매칭, else redirect_uri_mismatch). Sources 에 등록 완료 documented-only
[CV2 — gap] Google JWKS rotation 빈도 + Cache-Control / SLA 아카이브 부재 — google-openid-connect-oidc·google-oidc-discovery-spec 어디에도 cadence/헤더 없음 https://www.googleapis.com/oauth2/v3/certs 응답 헤더(Cache-Control: max-age=...) 직접 관찰 또는 Google 지원 페이지 아카이브 needs-confirmation (research opt-in)
[CV3/D2 — gap] Keycloak 의 외부 IdP(Google) JWKS 캐시 정책 (기본 TTL, expired-key fallback) 아카이브 부재 — Keycloak IdP 문서 3개 확인했으나 미기술. KC-ROT 는 자체 키라 무관 Keycloak Identity Provider admin config 페이지 또는 소스(OIDCIdentityProvider/AbstractOAuth2IdentityProvider) 정독 후 raw/official-docs/ 등록 needs-confirmation (research opt-in)
[CV5 — delegated] Keycloak 발급 access_token 에 aud=<backend-client-id> 포함(federation 환경에서도) 본 노트 Sources 범위 밖 — 발급측 결정 raw/branch-notes/feature-keycloak-spring-rs-audience-validator D4 + 실 토큰 decode. 본 노트는 Hop3-aud cell 로 consume needs-confirmation (형제 위임)
[CV6/D3 — gap] Keycloak 이 Google 요청 시 random nonce 동봉 + 응답 id_token nonce 자동 대조 spec 은 "RP 가 해야 한다"만 증명, Keycloak 자동 동작은 미아카이브 Keycloak OIDC Identity Provider config doc(nonce/PKCE 토글) 또는 소스 OIDCIdentityProvider.createAuthenticationRequest(), 또는 wire trace(HAR) needs-confirmation (research opt-in)
[Hop2 — gap] Keycloak 기본 서명 알고리즘이 RS256 인가 KC-ROT-C1 은 "자체 active key 서명"만 증명, 알고리즘 명시 없음 Keycloak realm "Keys" 탭 문서 또는 realm default-signature-algorithm provider config 확인 needs-confirmation

마주친 문제

  • (학습 단계, 미실행)
  • 잠재적 함정 기록:
    • Google이 issuer 표기를 https://accounts.google.com로도 accounts.google.com로도 발급한 사례가 있음 (과거). ⚠️ 정정(2026-07-18): 이 진술은 미검증 folklore 다. 아카이브 근거(#GOOGLE-OIDC-C1)는 iss 를 정확히 https://accounts.google.com 단일 문자열로 규정하고 alias 를 부인한다. 둘 다 유효했다는 2차 아카이브(예: 과거 Google OIDC discovery 스냅샷)가 나오기 전엔 "둘 다 허용" 으로 취급 금지. (CV1)
    • Keycloak이 Google JWKS를 가져오지 못하면 (네트워크 단절, Google 측 변경) Google 로그인 전체가 5xx. 모니터링 alarm 필요. (§엣지·실패·의존, D2/CV3)

묶음

본 sub-sub-branch 는 leaf — 자식 자료 없음. Phase 3 P3A 실 구현 또는 외부 산출물 단계에서 errors / interview prep / lectures 가 누적되면 본 섹션에서 그룹화.

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

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

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

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

관련 일일 노트

완료 후 정리

학습 노트. P2B는 documented-only 유지.

  • PR 링크:
  • 리뷰 메모:
  • 머지 결과 / 배포 환경: 학습 노트 (documented-only)
  • wiki 추출 대상:
    • actually-implemented 항목: (없음)
    • locally-verified 항목: (없음)
    • prod-verified 항목: (없음)
  • 추출하지 않을 항목: 전 항목 (documented-only / needs-confirmation). 단 D2·CV2·CV3·CV6·Hop2 gap 종결 후 wiki/concepts/keycloak-google-federation-trust-boundary (hop 검증 매트릭스) 합성 후보(현 status documented-only 로 파생 게이트 미달).