33 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-google-federation (P1B Edge Forward Auth + Google federation) | branch-note | raw | BR-KEYCLOAK-CHILD-8F3B8B4E | branch-child | keycloak-patterns-overview | WI-KEYCLOAK-PATTERNS-OVERVIEW-020 |
|
1 | feature-keycloak-edge-forwardauth-google-federation | feature-keycloak-patterns |
|
|
2026-05-25 | in-progress | 0d0cfce93fa2e7290518d60b46e5559d479877936fb26cc8dacbf2232cb0d8d3 |
branch: feature-keycloak-edge-forwardauth-google-federation (P1B Edge Forward Auth + Google federation)
Layer:
raw/branch-notes/— root raw/branch-notes/feature-keycloak-patterns의 sub-branch. 패턴 ID: P1B — Edge ForwardAuth (oauth2-proxy / Traefik) + Keycloak에 Google을 외부 IdP로 brokering. 비교 대상: raw/branch-notes/feature-keycloak-edge-forwardauth-no-google (P1A: 같은 배치, Google 없음).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-no-google — P1A (Edge, no Google)
- raw/branch-notes/feature-keycloak-internal-spa-direct-no-google — P2A
- raw/branch-notes/feature-keycloak-internal-spa-direct-google-federation — P2B
- raw/branch-notes/feature-keycloak-single-ec2-no-google — P3A
- raw/branch-notes/feature-keycloak-single-ec2-google-federation — P3B
브랜치 계약 패킷
- 생성 시 프로젝트 개정:
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 변형이다 | Edge ForwardAuth에 Google federation을 결합한 cross-cutting 변형으로 분류한다 | raw/project-notes/keycloak-patterns-overview |
브랜치 지역 결정
| Decision ID | Decision | Relation | Supporting Claims | Status |
|---|---|---|---|---|
| D1 | First Login Review Profile을 기본 off로 둔다 | local |
raw/project-notes/keycloak-patterns-overview | proposed |
| D2 | automatic email linking 대신 manual confirm을 사용한다 | local |
raw/project-notes/keycloak-patterns-overview | proposed |
| D3 | environment별 Google OAuth client를 분리한다 | local |
raw/project-notes/keycloak-patterns-overview | proposed |
| D4 | Google scope를 openid profile email로 제한한다 | local |
raw/project-notes/keycloak-patterns-overview | proposed |
| D5 | persistent federation key policy는 child owner를 소비한다 | local |
raw/project-notes/keycloak-patterns-overview | proposed |
선언한 예외
| Override ID | Overrides | Reason | Approval | Status |
|---|
없음.
묶음 (자식 sub-sub-branches)
- raw/company-tech-blogs/keycloak-google-login-codemancers
- raw/official-docs/google-openid-connect-oidc
- raw/official-docs/keycloak-first-login-flow
- raw/official-docs/keycloak-google-idp-setup
- raw/branch-notes/feature-keycloak-idp-brokering-google-client
- raw/branch-notes/feature-keycloak-first-broker-login-flow
- raw/branch-notes/feature-keycloak-google-claim-attribute-mapping
- raw/branch-notes/feature-keycloak-account-linking-sub-vs-email
Sources는 하단 "외부 근거" 섹션. Errors/Interview/Lectures/Blog 는 현재 없음.
목표
P1A에 외부 IdP(Google)가 붙으면 토큰 흐름이 어떻게 확장되는지를 명확히 한다.
핵심 통찰: edge proxy 입장에서는 변화가 없다. oauth2-proxy는 여전히 Keycloak 한 곳에만 redirect 하고, Keycloak이 발급한 Keycloak access token만 받는다. Google federation은 Keycloak 내부에서 일어나는 외부 IdP brokering 흐름이며, edge / backend 입장에서는 투명(transparent)하다.
면접 / 설계 시 자주 헷갈리는 지점:
- "Google 로그인을 붙이면 backend가 Google ID token을 검증해야 하나?" → 아니다. P1B backend trust는 raw/branch-notes/feature-keycloak-edge-forwardauth-no-google D3 — P1A와 같은 header-only 계약이며 Google token과 Keycloak token을 backend로 전달하지 않는다.
- "edge proxy가 Google client secret을 알아야 하나?" → 아니다. Google credential은 Keycloak이 보관·사용.
- "추가되는 trust hop은 어디인가?" → Google → Keycloak. P1A 대비 추가된 신뢰 경계는 이 한 hop.
범위
포함 범위
- P1B 컴포넌트 다이어그램 (P1A 대비 추가 컴포넌트 표시)
- P1A 대비 추가되는 토큰 교환 단계 (4–8) 명시
- Google federation 시 추가되는 신뢰 경계와 보안 surface
- First Login Flow 정책 결정 지점 (Review Profile / Account Linking)
- P1A 대비 장단점 / 운영 비용 비교
제외 범위
- 실제 구현 (P1B는 문서까지만 — root의 implementation 대상은 P3A)
- Google 외 IdP (GitHub / Facebook / Apple). Google만.
- Keycloak Authentication Flow custom code (Java SPI). 설정 옵션 수준까지.
- prod 환경 Google API rate limit / quota 분석.
근거 (필수, 최소 1개+)
본 sub-branch의 P1B (Edge + Google federation) 채택 근거. 상세 대안 비교는 §외부 근거 / 대안 조사 참조.
| Source | 정당화하는 결정 |
|---|---|
| raw/official-docs/keycloak-identity-brokering-overview-official | Keycloak Identity Broker 공식 — Google IdP brokering 패턴 채택 근거 |
| raw/official-docs/keycloak-google-idp-setup | Keycloak Google IdP setup 절차 — 구성 단계 근거 |
| raw/official-docs/google-openid-connect-oidc | Google OIDC 표준 (issuer, scopes, claims) — Google IdP 표준 동작 근거 |
| raw/official-docs/keycloak-first-login-flow | First Broker Login Flow — Account Linking 정책 근거 |
| raw/company-tech-blogs/keycloak-google-login-codemancers | Keycloak + Google 통합 실무 사례 (참고) |
컴포넌트 다이어그램
Browser
│
▼
Ingress (nginx / Traefik)
│
▼
ForwardAuth (oauth2-proxy) ────► Keycloak (realm: app)
│ (사용자가 "Sign in with Google" 클릭)
▼
Google OIDC
(authorize / token / userinfo)
│ (Google ID token + access token)
▼
Keycloak
(First Login Flow:
Google sub/email → Keycloak user
매핑 또는 신규 생성)
│ (Keycloak access token 발급)
▼
oauth2-proxy
│ (proxy 세션 cookie 셋팅 + 헤더 주입)
▼
Ingress
│
▼
Backend
- edge가 주입한 trusted header만 신뢰
- JWT/Google token은 보지 않음
핵심 표시:
- edge proxy ↔ Keycloak 구간 = P1A와 동일.
- Keycloak ↔ Google 구간 = P1B에서 새로 추가된 leg.
- backend trust = raw/branch-notes/feature-keycloak-edge-forwardauth-no-google D3 — edge-injected header only. Google federation은 이 경계를 바꾸지 않는다.
토큰 교환 sequence (P1A 대비 추가 단계 포함)
P1A 단계와 일치하는 부분은 그대로, Google federation 분기만 새 번호로 표기.
- (P1A 1과 동일) 사용자 브라우저가 보호 리소스 GET → Ingress → oauth2-proxy.
- (P1A 2와 동일) oauth2-proxy: 세션 없음 → Keycloak
authorizeredirect. - (P1A 3과 동일) Keycloak 로그인 페이지 표시.
- (추가) Keycloak 로그인 UI에 "Sign in with Google" 버튼 노출 (Identity Provider로 Google 등록 시 자동).
- (추가) 사용자 버튼 클릭 → Keycloak → Google
authorizeendpoint redirect (https://accounts.google.com/o/oauth2/v2/auth, scope=openid profile email). - (추가) 사용자 Google 로그인 → Google → Keycloak broker callback (
/realms/<realm>/broker/google/endpoint,code전달). - (추가) Keycloak → Google
/token(https://oauth2.googleapis.com/token), Google ID token + access token 수신. - (추가) Keycloak: Google ID token의
sub(영구 식별자) /emailclaim → First Login Flow 진입.- 기존 federated user 있음 → 그대로 매핑된 Keycloak user 사용.
- 없고 email match로 기존 local user 있음 → Handle Existing Account 서브플로우 (자동 링크 / 수동 confirm).
- 둘 다 없음 → 신규 Keycloak user 생성 (Review Profile 옵션에 따라 확인 페이지).
- (P1A 5와 동일) Keycloak → oauth2-proxy callback (
/oauth2/callback,code전달). oauth2-proxy → Keycloak/token. Keycloak access token + refresh token + ID token 발급. - (P1A 6–7과 동일) oauth2-proxy: 세션 cookie 셋팅 + 헤더(
X-Auth-Request-Email등) 주입 후 backend로 forward. P1B 기본 계약은 bearer token을 전달하지 않고 backend가 edge header만 신뢰한다.
신뢰 경계 (P1A 대비 변화)
| 경계 | P1A | P1B |
|---|---|---|
| Browser ↔ oauth2-proxy | TLS, 세션 cookie | 동일 |
| oauth2-proxy ↔ Keycloak | TLS, client secret | 동일 |
| Keycloak ↔ Google | — | 신규. TLS, Google OAuth client secret (Keycloak이 보관) |
| oauth2-proxy ↔ Backend | trusted identity header (bearer token 미전달) | 동일 |
| Backend의 token 검증 | 없음 — edge에서 인증 종결, header-only | 동일 — Google federation만 추가 |
신규 trust hop = Google → Keycloak 한 개. Google ID token signature는 Keycloak이 검증하고 oauth2-proxy는 Keycloak 세션을 만든다. 그 이후 backend trust는 P1A와 같은 header-only 경계다.
장점 / 단점 vs P1A
장점
- 사용자가 Google 계정으로 로그인 가능 → 별도 비밀번호 관리 불필요. UX 개선.
- 조직이 Google Workspace 사용 중이면 사실상의 SSO 통합 (사내 Google 계정 그대로 사용).
- Keycloak이 brokering 하므로 edge/backend 코드 변화 0 — P1A에서 Identity Provider만 추가 설정.
- 다른 외부 IdP(Microsoft / GitHub) 추가 시에도 동일 패턴으로 확장 가능 (broker만 추가 등록).
단점
- 외부 의존: Google OIDC downtime / rate limit 시 신규 로그인 불가 (이미 발급된 Keycloak 세션은 영향 없음).
- 사용자 매핑 정책 운영 부담: First Login Flow / Account Linking 정책 결정 필요. 잘못 설정 시 보안 이슈 (자동 email match linking → account takeover 위험).
- 보안 surface 확장:
- Google OAuth client secret이 Keycloak DB(또는 vault)에 저장됨.
- Google Cloud Console의 redirect URI 등록 관리 (환경별 OAuth client 분리 필요).
- Google 측 권한 변경(예: scope 변경, OAuth verification 요구) 시 영향 받음.
- 개인정보 / 동의 흐름 추가: Google scope 동의 화면, GDPR 등 데이터 처리 정책 영향.
- 디버깅 복잡도: 로그인 실패 시 oauth2-proxy / Keycloak / Google 3-leg 중 어디서 실패했는지 추적 필요 (로그 corr id 설계 중요).
결정 사항 (decisions)
본 sub-branch는 문서까지만 (documented-only)이므로 실제 환경 결정은 없음. 만약 구현한다면 권장 기본값:
- D1 — First Login Flow / Review Profile: OFF (Google이 email/profile 제공하므로 불필요). 단, 신규 사용자 동의 페이지가 필요한 비즈니스 요건이면 ON.
- D2 — Account Linking: 수동 confirm. 공식 문서가 "automatic linking by email = potential security hole" 명시. email match 시 사용자가 명시적으로 link 확인하도록.
- D3 — Google OAuth client 분리: dev / staging / prod 환경별 별도 OAuth client. redirect URI 충돌 방지.
- D4 — scope:
openid profile email만. (추정 — 추가 scope 요청 시 Google OAuth verification 이 트리거될 수 있으나 인용 raw 가 enumerate 안 함, 별도 raw 확보 전까지 근거 미보증.) - D5 — persistent federation key requirement: raw/branch-notes/feature-keycloak-account-linking-sub-vs-email D1 — concrete key policy owner. 본 parent는 안정적인 외부 subject를 사용한다는 P1B invariant만 consume한다.
needs-confirmation:
- Keycloak 세션 만료 시 Google refresh token으로 자동 갱신 가능 여부 (Keycloak이 Google refresh token을 보관하나? 정책상 사용자 재로그인이 일반적).
- Google account 삭제 / suspend 시 Keycloak local user 자동 비활성화 여부.
결정-근거 매핑
P1B 권장 기본값 결정과 raw source claim 매핑. company-tech-blog (
codemancers) claim 은 보조 근거 — 공식 best practice 로 격상 금지 (CLAUDE.md §5).
선택 조건열(R2): 각 결정이 "어떤 조건일 때 이 값, 다른 조건이면 어떤 대안" 인지. 상세 근거는 §결정 사항 prose.
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|---|
| D1 | First Login Flow / Review Profile = OFF (Google이 email/profile 제공하므로 불필요) | Google 이 email+profile 을 제공 → Off. 신규 사용자 동의/추가 attribute 수집이 비즈니스 요건이면 On, mandatory attr 부재 대비 fallback 만이면 missing (KC-FLF-C4 의 3-mode) |
raw/official-docs/keycloak-first-login-flow.md#KC-FLF-C4, raw/official-docs/keycloak-google-idp-setup.md#KC-GIDP-C5, raw/official-docs/google-openid-connect-oidc.md#GOIDC-C4 |
official-vendor-doc (Keycloak) + official-standard (Google OIDC) |
KC-FLF-C4 의 "mandatory information" 정확한 목록 (locale 포함 여부 등) 미확정 — Off mode 에서도 누락 시 자동 fallback 동작 확인 필요 |
| D2 | Account Linking = 수동 confirm (자동 email link 금지) | 외부 IdP email 을 항상 신뢰할 수 없음이 기본(KC-FLF-C2 공식 경고) → 항상 Confirm Link. 자동 email link 는 통제된 신뢰 환경에서도 공식 경고 대상이라 채택 안 함 (대안 없음) | raw/official-docs/keycloak-first-login-flow.md#KC-FLF-C2, raw/official-docs/keycloak-first-login-flow.md#KC-FLF-C3 |
official-vendor-doc (Keycloak 공식 security warning 명시) |
"Confirm Link Existing Account" 가 Keycloak version 별 default flow 에 포함되는지 vs 별도 추가인지 — KC-FLF-C3 의 "Does not prove" 에 명시 — version 별 확인 필요 |
| D3 | dev / staging / prod 환경별 별도 Google OAuth client | 환경별 redirect URI/도메인이 다름 → 환경당 별도 OAuth client. 단일 도메인·단일 환경이면 client 1개 + 다중 redirect URI 로도 가능 | raw/official-docs/keycloak-google-idp-setup.md#KC-GIDP-C3, raw/official-docs/keycloak-google-idp-setup.md#KC-GIDP-C4, raw/company-tech-blogs/keycloak-google-login-codemancers.md#CM-KC-GG-C4 (보조 — company case study, 공식 best practice 아님) |
official-vendor-doc (Keycloak) + company-case-study (codemancers, 보조) |
"환경별 분리가 redirect URI 충돌 방지에 필수" 는 일반 운영 원칙으로 raw claim 들이 직접 명시하지 않음 — KC-GIDP-C4 의 wildcard / 부분 매칭 허용 여부가 raw 범위 밖 |
| D4 | scope = openid profile email 만 |
email/profile 매핑만 필요 → Keycloak default 3 scope 유지. hd(도메인 제한)·groups 등 추가 사용자 데이터가 필요할 때만 scope 추가 |
raw/official-docs/keycloak-google-idp-setup.md#KC-GIDP-C5, raw/official-docs/google-openid-connect-oidc.md#GOIDC-C4 |
official-vendor-doc (Keycloak default) + official-standard (Google OIDC scope contract) |
"추가 scope 요청 시 Google OAuth verification 트리거" 는 본 raw 들이 직접 enumerate 하지 않음 — Google OAuth verification 정책 별도 raw 보존 필요 |
| D5 | P1B는 stable external subject를 요구하며 concrete persistent federation key policy를 직접 소유하지 않음 | key 선택·변경은 child owner에서만 수행. parent는 그 결과를 P1B topology invariant로 consume | raw/branch-notes/feature-keycloak-account-linking-sub-vs-email D1 — persistent Google federation key owner | delegated |
Keycloak 저장 메커니즘과 initial collision locator의 차이는 child에서 추적; parent에 복제하지 않음 |
구현 가이드
본 브랜치는
documented-only설계 hub — P1B topology와 pattern-level 요구만 소유하고 Google brokering의 mutable 설정은 자식 브랜치(§Cluster 4개)에 위임한다. 아래 parent D-row는 자식 owner의 값을 복제하지 않고 pointer로 consume한다. 모든 항목 등급planned— 구현 repo(keycloak-patterns/)가 아직 없어 코드로 확정된 것은 0개(NO_GROUND_TRUTH, ground truth = 공식 raw 문서). 코드 확인 후 등급 승격.3-rule 준수: 각 sub-section 은 Decision ID + Supporting Claim ID 를 Trace. 근거 raw 가 원칙 만 주고 detail 은 안 주는 cell 은
UNSUPPORTED_IMPL_DECISION+ trade-off 한 줄. 본 브랜치 결정 범위 밖 detail(Java SPI custom code 등)은 §범위 out-of-scope 로 이미 배제.
1. Google IdP 등록 (realm config) — D3 · D4 + delegated D5
Trace: D3(환경별 client)·D4(scope). raw/branch-notes/feature-keycloak-account-linking-sub-vs-email D1 — persistent federation key owner. IdP client 설정 owner는 raw/branch-notes/feature-keycloak-idp-brokering-google-client.
- UNSUPPORTED_IMPL_DECISION: (a) redirect URI 정확한 path 형식 — raw 가 명시 안 함(KC-GIDP-C3 "does not prove"), Admin Console 자동표시값을 복사(Claim To Verify #6 가 추적). trade-off: path 를 하드코딩하면
KC_HTTP_RELATIVE_PATH/host 조합 변화에 취약 → UI 표시값 복사가 안전. (b) discovery endpoint cache/retry 동작 — GOIDC-C5 는 URL 만 줌(Claim To Verify #1). (c) 환경별 client 분리 — official 미보증 운영 추론(KC-GIDP-C3/C4 는 양방향 등록까지만). trade-off: 단일 client 다중 redirect URI 도 가능하나 환경 간 실수 유출 위험 → 환경별 분리가 안전측.
| 설정 항목 | 값 / 경로 | Trace | 등급 |
|---|---|---|---|
| IdP 등록 진입 | Admin Console → Identity Providers → Add provider → Google |
KC-GIDP-C1 | planned |
| Client 자격 | Google 발급 Client ID + Client Secret 을 Keycloak Google IdP 에 입력 (Keycloak DB/vault 보관) |
KC-GIDP-C2, D3 | planned |
| 환경 분리 | dev/staging/prod 각 환경별 Google OAuth client 별도 발급 (redirect URI 충돌 방지). UNSUPPORTED_IMPL_DECISION — official 미보증 운영 추론 | D3(운영 추론, KC-GIDP-C3/C4 는 양방향 등록까지만 L1 증명) · CM-KC-GG-C4(보조) | planned |
| Redirect URI | Keycloak Add Identity Provider 페이지 표시값 → Google Cloud Console Authorized redirect URIs 에 복사. 예상 형식 https://<keycloak-host>/realms/<realm>/broker/google/endpoint (UNSUPPORTED_IMPL_DECISION — 형식은 raw 인용 밖, UI 표시값 신뢰) |
KC-GIDP-C3, KC-GIDP-C4 | planned |
| Scope | Default Scopes = openid profile email 유지, 추가 scope 금지(D4 조건) |
KC-GIDP-C5, D4 | planned |
| Discovery | "Import from URL" = https://accounts.google.com/.well-known/openid-configuration |
GOIDC-C5 | planned (Claim To Verify #1) |
2. First Broker Login Flow hardening — D1 · D2
Trace: D1(Review Profile)·D2(Confirm Link) / Claims
KC-FLF-C2,KC-FLF-C3,KC-FLF-C4. Owner 자식: raw/branch-notes/feature-keycloak-first-broker-login-flow.
- OUT_OF_BRANCH_SCOPE: flow 구성의 정본은 raw/branch-notes/feature-keycloak-first-broker-login-flow D1 — silent auto-link 방지, raw/branch-notes/feature-keycloak-first-broker-login-flow D2 — verification profile, raw/branch-notes/feature-keycloak-first-broker-login-flow D4 — custom hard-reject SPI 없이 성립하는 core policy. SPI artifact가 없는 현재 scope에서
email_verified=false전체 hard-reject를 parent acceptance로 주장하지 않는다.
| Flow 설정 | 값 | Trace | 등급 |
|---|---|---|---|
| Flow 편집 전 복제 | built-in "first broker login" flow 를 복제 후 수정 (원본 훼손 시 외부 IdP 전체 차단 위험) | KC-FLF 운영맥락(L90) | planned |
| Review Profile authenticator | Off (Google 이 email+profile 제공). 동의 페이지 필요 시만 On, mandatory 부재 대비만이면 missing |
KC-FLF-C4, D1 | planned |
| Confirm Link Existing Account | required — 자동 email link 금지, 사용자 명시 confirm 강제 (info page: 다른 email 사용 vs link 확인) | KC-FLF-C2, KC-FLF-C3, D2 | planned |
| linking trust policy | raw/branch-notes/feature-keycloak-first-broker-login-flow D4 — silent auto-link 방지 core를 consume. email_verified=false 전체 hard-reject는 custom SPI가 별도 채택될 때만 추가 |
delegated | documented-only; SPI variant는 out-of-scope |
3. Account matching identifier (IdP mapper) — D5
Trace: D5. raw/branch-notes/feature-keycloak-account-linking-sub-vs-email D1 — persistent federation key owner. raw/branch-notes/feature-keycloak-google-claim-attribute-mapping D4 — claim→attribute mapper owner.
- UNSUPPORTED_IMPL_DECISION:
sub를 federated identity primary key 로 매핑하는 정확한 Keycloak IdP mapper 타입/옵션 — 참조 raw 미포함(D5 Open Risk 가keycloak-identity-provider-mappers.md필요 명시). trade-off: mapper 타입 임의 선택 시 재로그인 매칭 실패 가능 → mapper raw 확보 후 자식 브랜치에서 확정.
- Persistent federation key와 mapper 타입/옵션은 위 두 owner D-row를 참조한다. 본 parent는 stable external subject requirement만 유지한다.
엣지·실패·의존
R4 캡처용. 본 브랜치는
documented-only지만, Google leg 추가로 P1A 대비 새 실패 경로가 생기고, 자식·형제 브랜치와 계약 의존이 있다.
- 실패·엣지 경로:
- Google OIDC downtime / rate limit: 신규 로그인 불가. 이미 발급된 Keycloak 세션은 영향 없음 (Google leg 는 최초 인증 시에만) — §장점/단점 근거.
- email 기반 auto-linking 계정 탈취: opt-in AutoLink가 email 값을 무확인 연결하면 기존 계정 탈취 가능. 방어 정본은 raw/branch-notes/feature-keycloak-first-broker-login-flow D1과 raw/branch-notes/feature-keycloak-first-broker-login-flow D4이며, 이 parent는
email_verified=truehard-reject를 별도 acceptance로 두지 않는다. - redirect URI mismatch: Google Cloud Console
Authorized redirect URIs↔ Keycloak/broker/google/endpoint불일치 시 Google 측 오류. 환경별 client 분리(D3)로 완화 (Claim To Verify #6). - bearer token 경계 누출: P1B baseline backend에는 access token 자체가 전달되지 않는다.
Authorizationheader가 관측되거나 Google token이 backend까지 새면 raw/branch-notes/feature-keycloak-edge-forwardauth-no-google D3의 header-only trust 경계가 붕괴한 것이다(Claim To Verify #5). - 3-leg 디버깅 복잡도: 로그인 실패 시 oauth2-proxy / Keycloak / Google 중 실패 지점 추적 필요 → corr-id 설계 (§장점/단점).
- 세션·계정 수명 불일치 (
needs-confirmation): Keycloak 세션 만료 시 Google refresh 자동 갱신 여부(Claim To Verify #2), Google 계정 삭제/suspend 시 Keycloak local user 미비활성(Claim To Verify #3).
- 다른 계약 의존:
- Root: raw/branch-notes/feature-keycloak-patterns 의 고정 결정 F3(단일 공유 realm + 패턴당 client)·F4(confidential secret = env var, 미커밋)에 의존 — Google client secret 저장 정책은 F4 를 따름.
- 자식(위임 — detail owner): raw/branch-notes/feature-keycloak-idp-brokering-google-client D3 — client 등록. raw/branch-notes/feature-keycloak-first-broker-login-flow D1 — silent auto-link 방지, raw/branch-notes/feature-keycloak-first-broker-login-flow D2 — verification profile, raw/branch-notes/feature-keycloak-first-broker-login-flow D4 — core linking policy. raw/branch-notes/feature-keycloak-google-claim-attribute-mapping D4 — claim mapping. raw/branch-notes/feature-keycloak-account-linking-sub-vs-email D1 — persistent federation key. Parent는 topology와 요구만 소유한다.
- 형제(브로커 로직 재사용): [raw/branch-notes/feature-keycloak-internal-spa-direct-google-federation], [raw/branch-notes/feature-keycloak-single-ec2-google-federation] — 동일 Google brokering 흐름. P3B 실 구현 시
KC_HOSTNAME공개 host 강제(Google redirect_uri 검증)라는 배포측 추가 의존.
검증해야 할 주장
본 sub-branch 는
documented-only. 만약 구현한다면 검증해야 할 주장 enumerate.
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
Keycloak 의 Google IdP "Use discovery endpoint" 옵션이 https://accounts.google.com/.well-known/openid-configuration 으로 정상 OIDC discovery 수행 |
GOIDC-C5 가 URL 명시했으나, Keycloak 의 discovery 호출 실제 동작 (cache TTL, retry 정책 등) 별도 검증 |
Keycloak Admin Console > Identity Provider > Google > "Import from URL" 클릭 후 endpoint 자동 채워지는지 확인 + keycloak debug log 에서 GET 요청 확인 | planned |
| Keycloak 세션 만료 시 Google refresh token 으로 자동 갱신 가능 여부 | 본 sub-branch §결정 사항 needs-confirmation 명시 — Keycloak 이 Google refresh token 을 보관하는지 정책 불명 |
Keycloak Admin Console > Identity Provider > Google > "Store Tokens" 옵션 활성화 후 세션 만료 후 동작 관찰 + Keycloak DB federated_identity 테이블 검사 |
needs-confirmation |
| Google account 삭제 / suspend 시 Keycloak local user 자동 비활성화 여부 | 본 sub-branch §결정 사항 needs-confirmation 명시 — Keycloak 에 webhook / polling 메커니즘 없음 (일반적) |
Google Cloud Console 에서 test account suspend 후 Keycloak login 시도 → 거부 여부 관찰 (예상: Keycloak 은 모름, login 시점에 Google 측 401 로만 차단) | needs-confirmation |
| First Broker Login Flow 의 "Confirm Link Existing Account" authenticator 가 Keycloak 26.x default flow 에 포함됨 | KC-FLF-C3 가 authenticator 존재 명시했으나 version 별 default flow 포함 여부 별도 확인 필요 |
Keycloak Admin Console > Authentication > Flows > "first broker login" flow 확인 + "Confirm Link Existing Account" step 존재 여부 | planned |
| P1B가 P1A의 header-only backend trust를 유지하고 Google/Keycloak bearer token을 backend로 전달하지 않음 | raw/branch-notes/feature-keycloak-edge-forwardauth-no-google D3을 consume하지만 실제 proxy config는 아직 없음 | Google 로그인 후 oauth2-proxy/ingress config와 backend request capture에서 trusted headers 존재, Authorization 부재, direct spoof 요청 차단을 확인 |
planned |
Google OAuth client 의 redirect URI 가 /realms/<realm>/broker/google/endpoint 형식과 정확히 일치 |
KC-IDP-BROKER-C2 가 verbatim 부재 명시 — Admin UI 표시값을 신뢰 |
Keycloak Admin Console > Identity Provider > Google 페이지의 "Redirect URI" 필드 값을 복사 → Google Cloud Console 의 Authorized redirect URIs 와 byte-level 일치 확인 | planned |
(Deferred SPI variant) email_verified=false를 flow 진입 즉시 hard-reject하는 custom authenticator를 별도 구현할 필요가 있는가 |
현재 corpus에 provider JAR/SPI artifact가 없고 core silent-link 방지는 raw/branch-notes/feature-keycloak-first-broker-login-flow D4로 성립 | 별도 제품 요구가 생길 때 SPI branch를 만들고 provider JAR, flow export, false-email negative E2E를 함께 검증 | planned (현재 acceptance 아님) |
외부 근거 / 대안 조사 (2026-05-25 — P1B Edge + Google IdP Brokering)
본 sub-branch의 Edge ForwardAuth + Google IdP Brokering 채택에 대한 외부 source. P1A에 외부 IdP federation을 추가하는 방식의 대안 비교.
- 채택 결정 (Keycloak IdP Brokering — Google을 외부 IdP로 등록):
- raw/official-docs/keycloak-identity-brokering-overview-official — Keycloak Identity Broker 공식 (외부 IdP 등록 + first broker login flow)
- raw/official-docs/keycloak-google-idp-setup — Keycloak Google IdP setup 절차
- raw/official-docs/google-openid-connect-oidc — Google OIDC 표준 (issuer, scopes, claims)
- raw/official-docs/keycloak-first-login-flow — First Broker Login Flow (Account Linking 정책)
- raw/company-tech-blogs/keycloak-google-login-codemancers — Keycloak + Google 통합 실무 사례
- 검토한 대안:
- 대안 1: SAML federation (Keycloak ↔ Google Workspace SAML) — 엔터프라이즈 단일 사인온 표준. 그러나 Google OIDC가 더 단순.
- 대안 2: Google OIDC 직접 (Keycloak 우회) — 백엔드가 Google ID token 직접 검증. 장: Keycloak 운영 부담 0 / 단: 다중 IdP 통합 어려움, role mapping 직접 작성.
- 대안 3: Auth0 / Okta (managed multi-IdP SaaS) — 운영 완전 위임. 단: vendor lock-in, 비용.
- 대안 4: oauth2-proxy
--provider=google직접 — Keycloak 없이 oauth2-proxy가 Google과 직접 통신. 장: Keycloak 제거 / 단: realm/role 관리 불가, 멀티 IdP 통합 불가. - 대안 5: AWS Cognito + Google federation — AWS 종속, 동일 패턴.
- 비교 핵심: IdP Brokering의 본질적 가치는 "코드 변경 없이 IdP 추가". SPA/백엔드는 Keycloak만 알면 되고, Google/SAML/LDAP 추가는 Keycloak admin 설정만. AutoLink는 별도 opt-in 위험 기능이며, 본 패턴은 raw/branch-notes/feature-keycloak-first-broker-login-flow D1/D4의 silent-link 방지 core를 따른다.
TODO
각 항목 옆에 증거 등급.
- P1B 다이어그램을 Mermaid sequence로 재작성 — 등급:
planned - P1A vs P1B diff matrix (sequence 단계 / trust boundary / 운영 비용) — 등급:
planned - First Login Flow 정책 분기 트리 도식화 — 등급:
documented-only(구현 안 함) - Keycloak refresh / Google session 만료 상호작용 확인 — 등급:
needs-confirmation
진행 중 메모
- Google ID token은 Keycloak이 검증한 뒤 backend로 전달하지 않는다. oauth2-proxy가 Keycloak token으로 session을 만들고, P1B backend는 raw/branch-notes/feature-keycloak-edge-forwardauth-no-google D3과 같은 edge-injected header-only 계약만 소비한다. 따라서 backend로 Google/Keycloak bearer token이 흐른다고 표현하지 않는다.
- "Google 로그인 = backend가 Google과 통신"으로 오해하기 쉬움. 다이어그램에서 Google ↔ Keycloak leg를 별도 색/박스로 강조해야 함.
- 본 sub-branch는
documented-only한정 — wiki/projects/로 승급 안 함 (root TODO 참조).
마주친 문제
- 없음 (구현 안 함).
관련 sub-branch
- raw/branch-notes/feature-keycloak-patterns (root)
- raw/branch-notes/feature-keycloak-edge-forwardauth-no-google (P1A — Google 없는 동일 배치, 비교 기준)
- raw/branch-notes/feature-keycloak-internal-spa-direct-google-federation (P2B — 내부 배치 + Google, broker 로직은 본 노트와 동일)
- raw/branch-notes/feature-keycloak-single-ec2-google-federation (P3B — 단일 EC2 + Google)
관련 일일 노트
완료 후 정리
- PR 링크: (없음, 문서까지만)
- 머지 결과 / 배포 환경: 없음 (
documented-only) - wiki 추출 대상: 없음. P1B는 root 정책상 wiki/projects/ 승급 안 함.
- 추출하지 않을 항목: 본 sub-branch 전체 (
documented-only/planned).