Files
llm-wiki/raw/branch-notes/feature-keycloak-account-linking-sub-vs-email.md

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-account-linking-sub-vs-email (Account Linking 보안 — sub vs email) branch-note raw BR-KEYCLOAK-PATTERNS-OVERVIEW-018 project-work-item keycloak-patterns-overview WI-KEYCLOAK-PATTERNS-OVERVIEW-018
DEC-KEYCLOAK-PATTERNS-OVERVIEW-IDP-BROKERING-001@1
WI-KEYCLOAK-PATTERNS-OVERVIEW-016
1 feature-keycloak-account-linking-sub-vs-email
keycloak-patterns
branch
keycloak-patterns
p1b
account-linking
security
account-takeover
2026-05-25 in-progress 54e36081984bb3b7bb0b46f7bd31beb8a7f6ff170e7c6ca76c76f4d0228bf27d

branch: feature-keycloak-account-linking-sub-vs-email (Account Linking 보안 — sub vs email)

Layer: raw/branch-notes/raw/project-notes/keycloak-patterns-overview Work Item의 직접 자식 branch. 학습 노트: P1B는 documented-only (실 구현 안 함). status_label: in-progress

부모 (필수)

raw/project-notes/keycloak-patterns-overview

브랜치 계약 패킷

  • 생성 시 프로젝트 개정: 1
  • 패킷 스키마: contract_packet: 1
  • 완료 조건: sub와 email linking key의 security comparison과 선택이 기록된다

상속한 프로젝트 결정

Decision Ref Project Summary Branch Application Source
DEC-KEYCLOAK-PATTERNS-OVERVIEW-IDP-BROKERING-001@1 Google federation은 Keycloak IdP brokering과 hardened First Broker Login을 사용한다 federated identity의 persistent key와 account-linking security policy에 적용한다 raw/project-notes/keycloak-patterns-overview

브랜치 지역 결정

Decision ID Decision Relation Supporting Claims Status
D1 federated identity의 persistent key로 Google sub를 사용한다 local raw/project-notes/keycloak-patterns-overview proposed
D2 기존 local 계정 linking 시 재인증 조건을 고정한다 local raw/project-notes/keycloak-patterns-overview proposed
D3 self-service unlink lockout을 server guard와 UX로 처리한다 local raw/project-notes/keycloak-patterns-overview proposed
D4 self-service link의 추가 password 재확인은 근거 확보 전 보류한다 local raw/project-notes/keycloak-patterns-overview proposed
D5 attribute Sync Mode 선택은 별도 owner에 위임한다 local raw/project-notes/keycloak-patterns-overview proposed

선언한 예외

Override ID Overrides Reason Approval Status

없음.

목표

Google federation 운영의 가장 큰 보안 함정은 Account Linking의 primary key 선택이다. email 기반 linking은 직관적이지만, 다음 두 사실 때문에 account takeover 시나리오를 만든다.

  1. email은 변경 가능: Google 계정 소유자가 primary email을 변경할 수 있음.
  2. email은 재사용 가능: Google Workspace에서 퇴사자 email이 신규 직원에게 재배정될 수 있음 (raw/company-tech-blogs/keycloak-google-login-codemancers 명시).
  3. email_verified=false인 Google 사용자 존재: 일부 케이스에서 Google이 미인증 email로 ID token 발급 가능.

반면 sub claim은 영구·불변이며 Google이 사용자별로 발급한 globally unique ID. Account linking의 primary key는 반드시 sub여야 한다.

본 노트는 takeover 시나리오를 정리하고, sub 기반 linking 정책을 명시한다.

범위

포함 범위

  • Account linking primary key 선택 (sub vs email) 및 그 근거 — takeover 위협 모델 A/B/C (본 branch 의 core owned 결정 D1).
  • self-service unlink 의 lockout-safe 정책 — password 미설정 계정 보호 (본 branch owned D3; raw/branch-notes/feature-keycloak-account-linking-spa-ux D4 가 안전정책을 본 branch 에 위임).
  • 기존 local 계정에 IdP link 시 재인증 정책 수준 요구 (D2 — flow 구성 은 sibling 위임).
  • Sync Mode 가 takeover 안전성에 미치는 영향 분석 (D5 — 직교성 확인; 선택 자체는 sibling 위임).

제외 범위

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

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

TODO (과거 계획 스냅샷)

각 항목 옆에 증거 등급. 아래는 2026-05-25 계획 스냅샷이며 active 정책은 §Decision Evidence Map을 따른다. 본 P1B sub-sub-branch는 전체 documented-only / planned.

  • Takeover 시나리오 (A/B/C) 다이어그램화 — 등급: planned
  • Keycloak federated identity 테이블 스키마 확인 — 등급: needs-confirmation
    • 테이블명: FEDERATED_IDENTITY
    • composite key: (IDENTITY_PROVIDER, FEDERATED_USER_ID, USER_ID) 추정 — 확인 필요
  • sub 기반 linking 강제 정책 명시 — 등급: documented-only
    • email 기반 자동 linking 금지 (앞선 -2-2 노트와 연결)
    • federated identity primary key = Google sub claim
  • 기존 Keycloak 계정에 federated identity link 시 password 재확인 정책 — 등급: documented-only
    • "Confirm Link Existing Account" + "Verify Existing Account by Re-authentication" REQUIRED
    • 사용자가 기존 계정 password를 입력해야 link 완료
  • Account Console에서 사용자 link/unlink 정책 결정 — 등급: documented-only
    • Self-service unlink 허용 시: 사용자가 비밀번호 미설정 상태에서 unlink → 잠금 위험 (대안 로그인 수단 미보유) → 사전 password 설정 강제
    • Self-service link 허용 시: 사용자가 Account Console에서 새 Google 계정 link → 같은 takeover 위험 → password 재확인 필수
  • email 변경 시 user attribute 동기화 정책 — 등급: documented-only
    • Sync Mode FORCE면 매 로그인마다 갱신
    • Sync Mode IMPORT면 first login 시점만 → 이후 Google 측 변경 무시 (안정성 ↑, 최신성 ↓)

⚠️ 2026-07-15 조사 정정 (위 항목 전제 수정): password 재인증(D2)·unlink lockout(D3)·self-service link 재확인(D4)·Sync Mode(D5) 관련 전제 일부는 공식 문서·엔진 소스 조사로 수정됐다. 원 TODO 는 verbatim 보존하되, 정정 내용은 §Decision Evidence Map 의 Open Risk 열 + §Audit & Findings 를 따른다.

진행 중 메모

  • raw/company-tech-blogs/keycloak-google-login-codemancers가 명시: "전 직원 email이 신규 직원에게 재배정되는 케이스 → email 기반 linking은 위험". 본 노트의 핵심 출처.
  • Keycloak 공식 문서가 "Confirm Link Existing Account" flow를 보안 기본값으로 권장하는 이유가 바로 본 노트의 시나리오들.
  • 면접에서 받기 좋은 질문: "왜 sub를 primary key로 쓰나? email로 하면 안 되나?" — Scenario A/B로 답변 가능.
  • 본 정책은 P1B 한정이 아닌 모든 Google federation 패턴(P2B, P3B)에 동일 적용.

계정 탈취 시나리오 분석

본 § 는 §결정 사항의 근거가 되는 위협 모델. 각 결정(특히 D1)이 어떤 공격을 막는지의 분석.

Scenario A: email 재배정 (퇴사자 → 신규 직원)

  1. alice@company.com (Google sub = sub_A)이 Keycloak 계정 보유, federated identity = sub_A.
  2. Alice 퇴사 → IT 관리자가 Google Workspace에서 alice@company.com 계정 삭제.
  3. 신규 직원 Bob에게 같은 alice@company.com email 재배정 (Google sub = sub_B).
  4. Bob이 Google 로그인 시도 → Keycloak이 받은 ID token의 sub = sub_B.
  5. email 기반 linking이면: Keycloak이 email match로 Alice의 기존 계정에 Bob을 link → Bob이 Alice의 권한 + 데이터에 접근.
  6. sub 기반 linking이면: sub_B로 federated identity 검색 → 미존재 → 신규 user 생성 (또는 confirm flow). 안전.

Scenario B: 자체 email 변경 (Google 계정 소유자)

  1. eve@gmail.com (sub = sub_E)이 Keycloak에 신규 가입 (federated identity = sub_E).
  2. Eve가 자신의 Google 계정 primary email을 victim@gmail.com으로 변경 (Google이 허용하는 시나리오 — alias 변경 등).
  3. Keycloak에 이미 victim@gmail.com으로 가입된 별개 사용자 Victim 존재.
  4. email 기반 매 로그인 재확인이면: Eve가 다음 로그인 시 Keycloak이 새 email로 Victim 계정에 link 시도 → takeover.
  5. sub 기반이면: sub_E로 매핑된 Eve 계정 그대로 사용. email attribute만 갱신 (sync mode FORCE) 또는 그대로 (IMPORT). → Sync Mode 는 takeover 방지에 관여하지 않음; 방지 주체는 sub 기반 linking (§Audit RATIONALE_CORRECTION).

Scenario C: email_verified=false

  1. 공격자가 Google OAuth client를 자체 운영하면서 email_verified=false인 임의 email을 가진 사용자로 가장.
  2. Keycloak trustEmail=true로 설정돼 있으면 email match로 기존 victim 계정에 link.
  3. 해결: trustEmail=false + First Broker Login Flow에 Confirm Link Existing Account (이미 raw/branch-notes/feature-keycloak-first-broker-login-flow에서 다룸).

결정 사항 (과거 기록)

2026-05-25 초기 판단의 보존 영역이다. Active 정본은 아래 Decision Evidence Map이며, D2와 D5의 값·선택 조건은 각 owner를 참조한다.

  • 2026-05-25: federated identity primary key = Google sub claim 만. email은 attribute일 뿐 link key 아님.
  • 2026-05-25: 기존 Keycloak local 계정에 Google federated identity 추가 link 시 → 기존 계정 password 재인증 필수 ("Verify Existing Account by Re-authentication" REQUIRED).
  • 2026-05-25: Account Console self-service unlink는 사용자가 password를 설정한 경우에만 허용 (잠금 방지).
  • 2026-05-25: Self-service link 시점에도 기존 password 재확인 강제.
  • 2026-05-25: Sync Mode = IMPORT (first login만). Google 측 email 변경이 Keycloak으로 자동 전파되지 않음 → Scenario B 회피. Superseded by D5 — takeover와 Sync Mode는 직교하며 값 선택은 owner가 소유한다.

정정 메모 (2026-07-15 조사): 위 원 결정 중 D2/D3/D4/D5 는 공식 문서·엔진 소스 조사로 일부 전제가 수정됐다 — 원문은 위에 verbatim 보존하고, 수정 내용은 §Decision Evidence Map 의 Open Risk 열과 §Audit & Findings 에 기록한다 (CLAUDE.md §11: 사용자 작성 결정은 자동 rewrite 금지, 정합 권고만).

결정-근거 매핑

각 결정이 어떤 raw source claim 으로 뒷받침되는지 명시한다. Decision ID 는 이 branch-note 안에서 안정적으로 유지한다. Supporting Claimsraw/<category>/<slug>.md#<CLAIM-ID> 형식. 선택 조건 (R2): 이 조건일 때 이 결정 / 다른 조건이면 어떤 대안.

Decision ID Decision 선택 조건 (언제 이 결정 / 언제 대안) Supporting Claims Evidence Strength Open Risk
D1 federated identity primary key = Google sub claim 만 (email 은 link key 아님) — 본 branch core owned 항상 이 결정 — sub 는 불변·유일, email 은 변경(GOIDC-C3)·재배정(Scenario A) 가능하므로 link key 부적격. 대안(email 기반 link)은 email 의 불변·비재사용이 IdP 계약으로 보장될 때만 — Google 은 명시적 불가 raw/official-docs/google-openid-connect-oidc.md#GOIDC-C3 ("Always use the sub field ... even if the user changes their email address"), raw/company-tech-blogs/keycloak-google-login-codemancers.md (tech-blog 사례 — corroboration 전용, 공식 best practice 단정 금지) official-vendor-doc (Google) + company-case-study Keycloak FEDERATED_IDENTITY 스키마가 sub 를 어떻게 저장하는지 본 Sources 직접 보장 안 함(→ Claims To Verify). OOTB Create User If Unique 는 email/username 으로 충돌 감지(raw/official-docs/keycloak-first-broker-login-verify-authenticators-official.md#KC-FBLVERIFY-C5) → sub-only 매칭엔 커스텀 authenticator 필요(§Audit OUT_OF_BRANCH_SCOPE)
D2 기존 Keycloak local 계정에 Google federated identity link 시 → 기존 계정 password 재인증 — 단 기본 동작 아님: SMTP 설정 realm 은 "Verify Existing Account By Email" 이 기본 ALTERNATIVE 이므로 admin 이 명시 DISABLE 해야 password 재인증 실행 security-first(secret 소유 증명) → email authenticator DISABLE + Re-authentication. SMTP 미설정 → Re-authentication 자동 폴백. 소비자 서비스(마찰·지원부담 우선) → Email 검증 기본값 유지 가능(단 secret 미증명) raw/official-docs/keycloak-first-login-flow.md#KC-FLF-C2 (auto-link=security hole), raw/official-docs/keycloak-first-broker-login-verify-authenticators-official.md#KC-FBLVERIFY-C1 (Email = SMTP 시 기본), #KC-FBLVERIFY-C2 (재인증 관철 = email DISABLE), #KC-FBLVERIFY-C3 (Re-auth 폴백). flow 구성 owner = raw/branch-notes/feature-keycloak-first-broker-login-flow D2 official-vendor-doc Google-first 가입(비밀번호 미설정) 사용자는 Re-authentication 으로 재인증 수단 없어 lockout 가능 — 사용자 population 조사 필요(needs-confirmation)
D3 Account Console self-service unlink lockout 방지는 Keycloak 엔진이 서버에서 이미 강제 (마지막 federated identity 제거는 count>1 || user.isFederated() || isPasswordSet() 아니면 HTTP 400). "사전 password 설정 강제" 는 보안 필수 아니라 UX 개선으로 재분류 — 본 branch owned (spa-ux D4 위임) password 미설정 + 단일 federated identity → 엔진이 unlink 자동 거부. project 는 400 을 UX 로 처리(에러 안내 or 선제 "password 먼저 설정")만. 대안(프로젝트 자체 lockout 가드 구현) = 불필요(중복) raw/official-docs/keycloak-account-console-unlink-lockout-guard-official.md#KC-UNLINKGUARD-C1 (guard 조건 — 마지막 federated identity 제거 HTTP 400), #KC-UNLINKGUARD-C2 (isPasswordSet() 구현), #KC-UNLINKGUARD-C3 ("You can not remove last federated identity as you do not have a password.") official-vendor-doc (엔진 소스코드 직접 근거) keycloak main branch 기준(2026-07-15) — 배포 release tag 별 재확인 필요. narrative Admin Guide 미기재(소스코드가 유일 근거)
D4 Self-service link (Client Initiated Account Linking / idp_link) 시 기존 password 재확인 강제 — 공식 근거 없음 + 반대 근거 존재. self-service link 는 role(account.manage-account-links) + 유효 access token 만 요구, password 재확인 미언급 N/A (근거 부재로 보류). project 가 step-up 을 원하면 idp_link AIA 앞에 커스텀 재인증 삽입 필요 UNSUPPORTED_DECISION — 반대 근거 raw/official-docs/keycloak-client-initiated-account-linking.md#KC-CIAL-C2 (link 전제 = role + scope 만) idp_link kc_action(AIA) 재인증 강제 여부 미조사(needs-confirmation) — 별도 branch
D5 Sync Mode 선택은 takeover 정책과 직교하며 이 branch가 값을 소유하지 않음 D1의 persistent link key는 Sync Mode로 바뀌지 않는다. 값·선택 조건은 owner에서만 변경 raw/branch-notes/feature-keycloak-google-claim-attribute-mapping D3 — attribute synchronization policy owner delegated 원 결정문 "Scenario B 회피"는 인과 오류. 본 branch는 link key 불변식만 소유하고, email 값 충돌의 실제 동작은 needs-confirmation

구현 가이드

결정(Decisions) 이 "무엇" 이라면 본 §는 "어디에 어떻게" 의 사전 명세. 본 브랜치는 documented-only 학습 노트이므로 구현 detail 은 공식 문서가 규정하는 프로토콜·값 / 엔진 소스를 anchor 로 하고 코드 미확인 항목은 planned/UNSUPPORTED_IMPL_DECISION 로 명시한다. 본 branch 의 in-scope owned 구현 대상은 D1(sub key 정책)D3(unlink lockout — 엔진 확인) 뿐. raw/branch-notes/feature-keycloak-first-broker-login-flow D2 — flow 구성 owner. raw/branch-notes/feature-keycloak-google-claim-attribute-mapping D3 — Sync Mode owner. 본 branch는 두 결정을 재진술하지 않는다.

Trace: D1 + GOIDC-C3 + KC-FLF-C2.

  • UNSUPPORTED_IMPL_DECISION: (a) FEDERATED_IDENTITY 테이블의 composite key/컬럼명(FEDERATED_USER_ID 에 sub 저장)은 본 Sources 미문서화 → Claims To Verify, planned. trade-off: 학습 단계엔 planned, 실 구현 시 DB/admin guide 확인. (b) OOTB Create User If Uniqueemail/username 으로 충돌 감지(KC-FBLVERIFY-C5) → sub-only 매칭엔 커스텀 authenticator 필요. 이 gap 은 본 branch 범위 밖(별도 branch, §Audit).
항목 값 / 명세 근거
link key Google sub → federated identity FEDERATED_USER_ID (Keycloak built-in) D1, GOIDC-C3
email 역할 user attribute 만 (link key 아님). Attribute Importer 매핑 owner = raw/branch-notes/feature-keycloak-google-claim-attribute-mapping D4 D1
auto-link 금지 lever First Broker Login "Automatically Link Existing Account"/AutoLink DISABLED (owner = raw/branch-notes/feature-keycloak-first-broker-login-flow D1) delegate, KC-FLF-C2, KC-FBLVERIFY-C4
충돌 감지 방식 gap OOTB 는 email/username 매칭 → sub-only 원하면 커스텀 authenticator (별도 branch) KC-FBLVERIFY-C5, §Audit

Trace: D2 + KC-FBLVERIFY-C1/C2/C3.

항목 정책 / 명세 근거
기본 동작(주의) SMTP 설정 realm → "Verify Existing Account By Email" 이 기본(ALTERNATIVE) 실행(secret 미증명) KC-FBLVERIFY-C1
password 재인증 관철 admin 이 "Verify Existing Account By Email" DISABLE → "Verify Existing Account By Re-authentication" 실행 KC-FBLVERIFY-C2 / KC-FBLVERIFY-C3
lockout 주의 비밀번호 미설정(Google-first) 사용자는 Re-authentication 불가 → 다른 연결 IdP 재인증 경로 or fallback 설계 필요 KC-FBLVERIFY-C3

Trace: D3 + KC-UNLINKGUARD-C1/C2/C3.

  • UNSUPPORTED_IMPL_DECISION: 클라이언트 UX 처리 방식(에러 표시 vs 선제 안내)은 본 Sources 미규정 — project 선택. trade-off: 학습 단계엔 기본 Account Console 400 메시지 노출(planned).
항목 동작 근거
엔진 가드 마지막 federated identity 제거 시 count>1 || user.isFederated() || isPasswordSet() 아니면 HTTP 400 KC-UNLINKGUARD-C1, KC-UNLINKGUARD-C2
사용자 메시지 "You can not remove last federated identity as you do not have a password." KC-UNLINKGUARD-C3
project 작업 400 을 UX 로 처리(에러 안내 or 선제 "password 먼저 설정") — 보안 아닌 UX D3
unlink 후 재로그인 Federated Identity record 삭제 → 재로그인 시 First Broker Login 재실행 → §2 재인증 경로 delegate raw/branch-notes/feature-keycloak-first-broker-login-flow D2

엣지·실패·의존

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

검증해야 할 주장

공식 문서 근거가 있어도 내 프로젝트에서의 동작을 자동으로 보장하지 않는다.

Claim Why uncertain How to verify Status
Keycloak FEDERATED_IDENTITY 테이블의 composite key 는 (IDENTITY_PROVIDER, FEDERATED_USER_ID, USER_ID) 이며 FEDERATED_USER_ID 에 Google sub 가 저장됨 본 branch 의 Sources 는 Keycloak 내부 스키마를 다루지 않음. 본문 메모 자체가 "추정" 표기 Keycloak DB 직접 조회 또는 official server-installation guide 의 schema 섹션 확인 needs-confirmation
OOTB Create User If Unique 가 email/username 이 아니라 sub 로 충돌 감지하게 하려면 커스텀 authenticator 가 필요하다 (D1 과 OOTB flow 의 구조적 긴장) 조사에서 OOTB 는 "same email or username" 매칭 확인(KC-FBLVERIFY-C5) — sub-only 커스텀 구현 필요 여부는 미검증 Keycloak IdpCreateUserIfUniqueAuthenticator 소스/SPI 문서 확인 + dev 환경에서 sub 충돌 재현 needs-confirmation
Google 이 실제로 primary email 변경을 허용하며 그 결과 ID token 의 email claim 이 변경된다 (Scenario B 의 전제) GOIDC-C3 는 "email 변경 가능성" 을 함의하지만 Google primary email 변경의 정확한 정책 (alias vs primary) 은 본 인용 범위 밖 Google Account 공식 help 페이지 추가 수집 또는 실제 dev Google 계정으로 변경 시도 needs-confirmation
email_verified=false 인 Google ID token 이 실제로 발급될 수 있는 시나리오가 존재 본 branch 의 Sources 는 email_verified semantics 의 정확한 조건을 직접 인용하지 않음 Google OIDC email_verified claim 공식 spec 인용 추가 수집 needs-confirmation
Google Workspace 에서 퇴사자 email 이 신규 직원에게 재배정 가능 (Scenario A 의 전제) codemancers tech-blog 만 언급 — company-case-study 등급 → 공식 best practice 로 단정 금지 Google Workspace Admin 공식 문서 (user delete + recreate 정책) 인용 추가 수집 needs-confirmation
owner가 선택한 Sync Mode가 공식 semantics와 같은 attribute synchronization 결과를 내며 D1의 link key를 바꾸지 않는다 값 선택은 raw/branch-notes/feature-keycloak-google-claim-attribute-mapping D3 소관이고, 본 branch는 takeover 직교성만 검증 dev realm에서 owner profile 적용 후 attribute 변경·재로그인 결과와 federated identity key 불변을 함께 확인 needs-confirmation (source-grounded)
realm "Duplicate emails" 설정과 Sync Mode FORCE 의 상호작용 — FORCE 로 email 이 충돌 값으로 갱신될 때 실제 동작(성공/실패/무음 충돌) 조사 범위 밖 — 공식 문서 미확인 영역 (Plan Gap) Keycloak Admin Console > Realm Settings > "Duplicate emails" 값 확인 + dev realm 에서 email 충돌 재현 needs-confirmation
인용한 엔진 가드/authenticator 동작이 실제 배포 Keycloak release tag 에서도 동일하다 인용 소스(LinkedAccountsResource.java, first-login-flow.adoc)는 keycloak main branch(2026-07-15) 기준 배포 예정 버전 tag 로 소스/문서 재확인 needs-confirmation
idp_link kc_action(Application Initiated Action) 이 재인증을 강제하는가 (D4 최종 답) 조사에서 client-initiated linking 은 role+token 만 요구 확인(KC-CIAL-C2), idp_link AIA 는 미조사 IdpLinkAction 소스 + Application Initiated Actions 공식 문서 조사 (별도 branch) needs-confirmation

감사와 발견 사항

2026-07-15 /branch-spec 자동조사(공식 문서 + 엔진 소스) 결과. 사용자 작성 결정은 verbatim 보존, 아래는 정합 권고·정정만 (CLAUDE.md §11).

  • RESOLVED — RESTATED_FOREIGN_DECISION: 본 branch 의 core owned 결정은 D1(sub key) + D3(unlink lockout safety — spa-ux D4 위임) 뿐이다. D2raw/branch-notes/feature-keycloak-first-broker-login-flow D2, D5raw/branch-notes/feature-keycloak-google-claim-attribute-mapping D3 를 Reference-Only로 consume하도록 정리했다.
  • RESOLVED — RATIONALE_CORRECTION (D5): 원 결정문 "Sync Mode = IMPORT → Scenario B 회피" 는 Historical/superseded로 격리했다. Active D5는 D1이 takeover를 차단하고 Sync Mode는 직교한다는 lens와 owner pointer만 유지한다.
  • CORRECTION (D2): 원 TODO/결정의 "Verify Existing Account by Re-authentication REQUIRED(기본)" 은 부정확 — SMTP 설정 realm 은 "Verify Existing Account By Email" 이 기본 ALTERNATIVE(KC-FBLVERIFY-C1). password 재인증을 관철하려면 admin 이 email authenticator 를 명시적으로 DISABLE 해야 한다(KC-FBLVERIFY-C2).
  • UPGRADE (D3, UNSUPPORTED → CONFIRMED): D3 는 기존 UNSUPPORTED_DECISION 이었으나 엔진 소스(LinkedAccountsResource#removeLinkedAccountcount>1 || user.isFederated() || isPasswordSet() 가드 + federatedIdentityRemovingLastProviderMessage)로 CONFIRMED(KC-UNLINKGUARD-C1~C3). lockout 은 Keycloak 서버 가드가 이미 방지 → project 작업은 UX 처리로 축소. narrative Admin Guide 미기재 — 소스코드가 유일 근거.
  • CORRECTION (D4, UNSUPPORTED 유지 — 사유 격상): "self-service link 시 password 재확인" 은 근거 부재가 아니라 확인된 반대 근거(link 전제 = role + token 만, KC-CIAL-C2). project 가 이 정책을 원하면 커스텀 구현 필요.
  • OUT_OF_BRANCH_SCOPE (이관 권고): OOTB Create User If Unique 는 email/username 으로 충돌 감지(KC-FBLVERIFY-C5, sub 아님). D1(sub-only linking)과 OOTB flow 의 구조적 긴장 — sub-only 매칭엔 커스텀 authenticator 필요. 본 branch 범위 밖 → 별도 branch 로 이관 권고(예: feature-keycloak-sub-based-collision-authenticator). 본 §에 이관 history 보존, §구현 가이드 §1 에는 gap 표시만.
  • STALE_REVERSE_REF (Should-fix, /sync 대상): D3 가 UNSUPPORTED_DECISIONofficial-vendor-doc 로 승격됐으므로, 이를 참조하는 raw/branch-notes/feature-keycloak-account-linking-spa-ux 의 D4/§구현 가이드/§엣지 (해당 노트에서 본 branch D3 를 needs-confirmation/UNSUPPORTED 로 요약한 참조들)이 stale. /sync 또는 wiki-doc-author mode=migrate 로 역참조 전파 필요(비차단).

마주친 문제

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

묶음

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

근거 자료

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

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

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

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

관련 일일 노트

완료 후 정리

  • PR 링크: (없음, 문서까지만)
  • 머지 결과 / 배포 환경: 없음 (documented-only)
  • wiki 추출 대상: 없음. P1B sub-sub-branch는 root 정책상 wiki/projects/ 승급 안 함.
  • 추출하지 않을 항목: 본 sub-sub-branch 전체 (documented-only / planned).