27 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-realm-client-export (Keycloak realm/client 설정 + realm JSON export) | branch-note | raw | BR-KEYCLOAK-PATTERNS-OVERVIEW-002 | project-work-item | keycloak-patterns-overview | WI-KEYCLOAK-PATTERNS-OVERVIEW-002 |
|
|
1 | feature-keycloak-realm-client-export |
|
|
2026-05-25 | in-progress | f751af30be9944511f5759f72096e406a9d6e191e075904df611b11f5797c5df |
branch: feature-keycloak-realm-client-export (Keycloak realm/client 설정 + JSON export)
Layer:
raw/branch-notes/— raw/project-notes/keycloak-patterns-overview Work Item의 직접 자식 branch. P3A는 실 구현 대상. 본 sub-sub는 학습 + 작업 plan 기록 — 실 구현은/home/donghyeon/workspace/keycloak-patterns/.
부모 (필수)
raw/project-notes/keycloak-patterns-overview
브랜치 계약 패킷
- 생성 시 프로젝트 개정:
1 - 패킷 스키마:
contract_packet: 1 - 완료 조건: realm import와 client 4개 등록 후 unauthenticated protected endpoint가 401이고 export가 재현된다
상속한 프로젝트 결정
| Decision Ref | Project Summary | Branch Application | Source |
|---|---|---|---|
DEC-KEYCLOAK-PATTERNS-OVERVIEW-REALM-CLIENT-001@1 |
단일 realm keycloak-patterns에서 인증 패턴별 client를 분리한다 | realm import와 인증 패턴별 client export 구성에 적용한다 | raw/project-notes/keycloak-patterns-overview |
DEC-KEYCLOAK-PATTERNS-OVERVIEW-SECRET-BOUNDARY-001@1 |
confidential client secret은 env var로 주입하고 commit·realm export 평문을 금지한다 | realm export artifact의 secret redaction과 주입 경계에 적용한다 | 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 |
|---|
없음.
목표
keycloak-patterns realm + spa-client (public, PKCE S256 강제) + 테스트 user 2명 + role 2개를 설정하고 realm JSON export를 commit한다. import 배선은 raw/branch-notes/feature-keycloak-docker-compose-stack D4가 소유하며, 본 문서는 그 consumer가 사용할 JSON artifact의 내용·검증 계약만 소유한다.
면접 질문: "Keycloak에서 public client에 PKCE 강제는 어떻게 거나요?"
→ "대상 Keycloak Client의 Capability config에서 PKCE method = S256을 지정합니다. 실제 export의 client attribute와 verifier 없는 요청의 거부 응답은 배포 버전에서 확인합니다. RFC 7636 관점에서 client_secret을 안전하게 보관할 수 없는 public SPA의 code interception 위험을 PKCE로 완화합니다."
- 이슈:
- PR: (별도 keycloak-patterns repo)
범위
포함 범위
- realm
keycloak-patterns생성 - Client
spa-client(public, Standard Flow + PKCE S256 강제) - Valid Redirect URIs (
http://localhost/*,http://127.0.0.1/*) - Web Origins (
+— Valid Redirect URI에서 자동 도출) - User 2명 (
admin-user/regular-user) + 초기 password - Role 2개 (
admin-role/user-role) + user에 매핑 - Refresh Token Rotation 설정 필드와 target-version 실험 후보값 기록(현재 후보: ON /
Max Reuse: 0; 의미는 owner 실험 전 확정하지 않음) - Realm JSON export 파일 commit (
./realm-export.json) - import consumer가 사용할 realm JSON artifact의 파일명·내용·redaction 검증 계약
제외 범위
- Google IdP 추가 (P3B → raw/branch-notes/feature-keycloak-single-ec2-google-federation)
- 세밀한 role hierarchy / composite role
- group / organization
- 본격적인 password policy / OTP
--import-realm, volume mount, container command 등 import 배선 — raw/branch-notes/feature-keycloak-docker-compose-stack D4 소유
근거 (필수, 최소 1개+)
노트 최초 작성(2026-05-25) 당시 근거 raw 가 부재해 D1/D2/D5 가
UNSUPPORTED_DECISION이었으나, 이후 corpus 성장으로 아래 raw 들이 추가되어 official 근거로 승격했다(재조사 없이 기존 raw 재매핑). 상세는 §Audit & FindingsEVIDENCE_UPGRADE.
| Source | 정당화하는 결정 |
|---|---|
| raw/official-docs/oauth2-pkce-rfc-7636 | D1 — public client 의 code interception 취약성 + S256 공식 + token endpoint 의 verifier 불일치 거부 (PKCE-RFC7636-C1/C3/C4) |
| raw/official-docs/keycloak-client-pkce-method-enforcement-official | D1 — Keycloak client 단위 PKCE 강제 옵션의 정식 명칭("PKCE method")과 S256 값 동작 (KC-PKCE-C1/C3) |
| raw/official-docs/oauth2-browser-based-apps-ietf-draft | D1 — 브라우저 앱 = public client(client credentials 없음) 표준 정의 (OAUTH-BBA-C3) |
| raw/official-docs/oauth-v2-1-draft-ietf | D1 — 모든 client PKCE MUST + AS enforce MUST (OA21-C1); D2 — redirect URI exact-match MUST (OA21-C5); D3 — refresh token scope/RS bound + code flow 발급 경로 (OA21-C3/C6) |
| raw/official-docs/keycloak-getting-started-docker | D2 — quickstart 자체가 redirect URI 를 .../* wildcard + Web origins 정확값으로 설정 (KC-GSD-C4); realm=tenant, client 등록 절차 (KC-GSD-C3) |
| raw/official-docs/keycloak-import-export-realms | D5 — --import-realm startup import + 컨테이너 import dir(/opt/keycloak/data/import) + 기존 realm skip(멱등) + offline --override 차이 (KC-IMPORT-C1..C4) |
| raw/official-docs/keycloak-server-containers-docker | D5 — 컨테이너 실행/env context; 정확한 env 이름·기본 포트는 KC-CONTAINER-C5 가 needs-confirmation |
TODO
- Keycloak admin console 접속 (
http://localhost:8080, admin 계정) — 등급:planned - realm
keycloak-patterns생성 — 등급:planned - Client
spa-client생성: Access Typepublic, Standard Flow Enabled, Direct Access Grants Disabled — 등급:planned - Client Capability config:
PKCE method = S256; 생성된 realm export의 내부 key도 함께 확인 — 등급:planned - Client Valid Redirect URIs:
http://localhost/*,http://127.0.0.1/*양쪽 등록 — 등급:planned - Client Web Origins:
+(Redirect URIs에서 자동 도출) — 등급:planned - Role 생성: realm role
admin-role,user-role— 등급:planned - User 생성:
admin-user(password 초기화,admin-role부여) — 등급:planned - User 생성:
regular-user(password 초기화,user-role부여) — 등급:planned - Realm Settings → Tokens: owner 실험 profile에 따라
Revoke Refresh Token과Refresh Token Max Reuse값을 설정하고 export에 기록(0/1의 의미는 사전 단정 금지) — 등급:planned - Realm Settings → Tokens: Access Token Lifespan 5분 (학습용 짧게) — 등급:
planned - Realm export: admin console → Export 또는
kc.sh export --realm keycloak-patterns --file /opt/keycloak/data/import/realm-export.json— 등급:planned - export JSON에서 secret/password 제거(또는 placeholder 치환) 후 git commit — 등급:
planned - raw/branch-notes/feature-keycloak-docker-compose-stack D4가 본 artifact를 소비하는지 acceptance 검증(경로·파일명·realm/client 존재 확인); mount/command 저작은 하지 않음 — 등급:
planned - 환경 reset 후 consumer import acceptance 검증 (
docker compose down -v && up→ admin 로그인 → realm/client 존재 확인) — 등급:planned
진행 중 메모
- PKCE는 Keycloak public client 기본 권장. S256만 허용(
plain거부)이 보안 표준. Valid Redirect URIs에localhost와127.0.0.1둘 다 등록하는 이유: 브라우저가 어느 호스트로 SPA를 로드하느냐에 따라 redirect URI도 달라짐. 두 URI는 Keycloak이 다른 것으로 본다.- Web Origins
+는 Redirect URIs 도메인을 자동으로 CORS allow에 추가. wildcard*는 학습에서도 비권장. - Realm export의 credential 포함 여부·표현 형식은 Keycloak 버전과 export mode에 따라 달라질 수 있으며 현재 근거로 확정할 수 없다. target image의
kc.sh export --help, 실제 JSON, re-import 후 로그인까지 확인하기 전에는 password 포함/미포함을 모두 가정하지 않는다. 기본 절차는 credential을 별도 bootstrap/reset하고 commit 전 민감 필드를 redact하는 것이다. --import-realm은 Keycloak 19+ 부터 지원 (자동 import). 구버전은kc.sh import별도 실행.
결정 사항 (decisions)
- 2026-05-25: public client + PKCE S256 강제. 이유: vanilla JS SPA는 client_secret 보관 불가 (RFC 7636), public client + PKCE가 표준.
- 2026-05-25: Redirect URI에 wildcard
/*사용. 이유: 학습 환경 한정 (localhost callback 경로 자유로움). prod에서는 정확한 경로 하나만. - 2026-05-25 (Historical / superseded rationale): Refresh Token Rotation ON + Max Reuse 0을 곧바로 보안 정책으로 확정했으나,
Max Reuse의미와 reuse 후 family 동작은 target-version 실험 전 단정할 수 없다. 현 결정은 raw/branch-notes/feature-keycloak-refresh-token-rotation D1/D2의 정책·검증 계약을 소비해 확정된 값을 export에 기록하는 것이다. - 2026-05-25: Access Token Lifespan 5분. 이유: rotation/revoke 시연 시 access token이 즉시 invalidate 안 됨을 짧게 검증.
- 2026-05-25: Realm JSON export commit. 이유: 환경 reset 1줄 정책 (
docker compose down -v && up후 실 import).
결정-근거 매핑
각 결정이 어떤 raw source claim 으로 뒷받침되는지 명시.
Decision ID는 본 branch-note 안에서 안정적으로 유지.선택 조건열: "이 조건일 때 이 결정, 다른 조건이면 어떤 대안". 분기 없으면N/A. D3/D4/D5 는 sibling owner 브랜치에 rationale/wiring 을 위임(delegate) 한다 — Single-Owner(consistency-contract) 준수, 재진술(RESTATED_FOREIGN_DECISION) 금지. 상세는 §Audit & Findings.
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|---|
| D1 | public client + PKCE S256 강제 (vanilla JS SPA 는 client_secret 보관 불가) |
SPA 가 client_secret 을 안전 보관 못할 때 이 결정 (OAUTH-BBA-C3, PKCE-RFC7636-C1). backend 를 둘 수 있으면 → 대안 BFF confidential client (OA21-C4) |
raw/official-docs/oauth2-pkce-rfc-7636.md#PKCE-RFC7636-C1, raw/official-docs/oauth2-pkce-rfc-7636.md#PKCE-RFC7636-C3, raw/official-docs/oauth2-pkce-rfc-7636.md#PKCE-RFC7636-C4, raw/official-docs/keycloak-client-pkce-method-enforcement-official.md#KC-PKCE-C1, raw/official-docs/keycloak-client-pkce-method-enforcement-official.md#KC-PKCE-C3, raw/official-docs/oauth-v2-1-draft-ietf.md#OA21-C1 |
official-standard + official-vendor-doc |
code_challenge_method=plain/verifier 없는 요청의 4xx 거부는 KC-PKCE-C3 가 증명 안 함(강제 적용 암시만) → §Claims To Verify 로 실측. Admin UI 라벨은 "PKCE method"(§Audit NAMING_DRIFT) |
| D2 | Redirect URI 에 wildcard /* 사용 (localhost 학습 한정) |
localhost/학습이면 /* (callback 경로 자유·quickstart 도 /* 사용 KC-GSD-C4). prod 진입 시 → 대안 exact-match 단일 경로 (표준 OA21-C5: AS MUST reject non-exact redirect URI) |
raw/official-docs/keycloak-getting-started-docker.md#KC-GSD-C4, raw/official-docs/oauth-v2-1-draft-ietf.md#OA21-C5 |
official-vendor-doc + official-standard |
prod 에서 /* 는 OA21-C5 exact-match MUST 위반 — out of scope(Out of scope 는 아니나 prod 미대상). KC-GSD-C4 는 /* 예시만 보증, wildcard 의 보안 영향은 미증명 |
| D3 | realm export에 rotation 실험 후보값을 기록하되 의미를 재정의하지 않음 | 값·정책의 owner인 raw/branch-notes/feature-keycloak-refresh-token-rotation D1/D2가 확정한 target-version profile을 소비한다. runtime 동작은 raw/branch-notes/feature-keycloak-refresh-rotation-and-logout D1/D5에서 관찰한다. | raw/official-docs/oauth-v2-1-draft-ietf.md#OA21-C3, raw/official-docs/oauth-v2-1-draft-ietf.md#OA21-C6 + delegated |
official-standard (baseline) + delegated |
Max Reuse=0의 의미와 refresh-token family invalidation은 배포 버전 실험 전 확정하지 않는다. 본 branch는 export에 최종 선택값만 반영한다. |
| D4 | Access Token Lifespan 실험값을 realm export에 기록 | TTL 정책은 raw/branch-notes/feature-keycloak-refresh-token-rotation D2를 소비하고, 5분이라는 실행 편의값과 관찰은 raw/branch-notes/feature-keycloak-refresh-rotation-and-logout D2에서 검증한다. prod TTL은 별도 결정이다. | UNSUPPORTED_DECISION + delegated |
UNSUPPORTED_DECISION + delegated |
target-version export의 내부 key와 실제 만료 시간이 일치하는지 runtime acceptance 필요 |
| D5 | realm-export.json 저작 + commit (realm/client/role/user/token 설정을 담고 민감 필드를 검토·redact) | 환경 reset 반복 + realm 즉시 복원이 목표면 export artifact를 commit. 1회성 수동 설정이면 Admin UI 수동 생성. 기존 realm 강제 덮어쓰기는 offline import --override(KC-IMPORT-C4) 검토 |
raw/official-docs/keycloak-import-export-realms.md#KC-IMPORT-C2, raw/official-docs/keycloak-import-export-realms.md#KC-IMPORT-C3, raw/official-docs/keycloak-import-export-realms.md#KC-IMPORT-C4 + import 배선 delegate raw/branch-notes/feature-keycloak-docker-compose-stack D4 |
official-vendor-doc + delegated (wiring) |
secret/password/credential 포함 여부와 형식은 모두 needs-confirmation. import wiring은 compose sibling D4 owner이며 본 문서는 artifact만 소유한다. |
구현 가이드
본 branch 는 실 구현 repo(
/home/donghyeon/workspace/keycloak-patterns/)가 아직 부재(§AuditNO_GROUND_TRUTH) → 모든 항목planned. code grep 으로actually-implemented확정 불가. 3-rule(CLAUDE.md §15.5): R1 Reference 필수 · R2 UNSUPPORTED_IMPL_DECISION 명시 · R3 OUT_OF_BRANCH_SCOPE 정제.
1. realm-export.json 저작 명세 (client
Trace: D1(
PKCE-RFC7636-C1/C3/C4,KC-PKCE-C1/C3,OA21-C1) · D2(KC-GSD-C4,OA21-C5) · D3(raw/branch-notes/feature-keycloak-refresh-token-rotation D1/D2 + runtime raw/branch-notes/feature-keycloak-refresh-rotation-and-logout D1/D5) · D4(raw/branch-notes/feature-keycloak-refresh-token-rotation D2 + runtime raw/branch-notes/feature-keycloak-refresh-rotation-and-logout D2)
- UNSUPPORTED_IMPL_DECISION:
- client 내부 JSON 속성 key
pkce.code.challenge.method—KC-PKCE-C1"Does not prove" 가 이 내부 속성명이 page 에 명시 안 됨을 명시. Admin UI 라벨("PKCE method")만 증명됨. trade-off: export-first 접근(Admin UI 에서 설정 →kc.sh export로 정확한 key 자동 생성) 채택, hand-author JSON key 는 금지.needs-confirmation.- realm token 설정 JSON key(
revokeRefreshToken/refreshTokenMaxReuse/accessTokenLifespan) — cited raw 에 verbatim 부재. trade-off: 마찬가지로 export-first 로 확정.needs-confirmation.- user credential의 export 포함 여부와 JSON 표현(
users[].credentials[]등) — cited raw 미증명. targetkc.sh export --help, 실제 export JSON, re-import login을 확인하기 전에는 포함/미포함을 가정하지 않는다. trade-off: 별도 bootstrap/reset을 default로 두고 hand-authored credential block은 피한다.needs-confirmation.
| JSON path (planned, export-first 로 확정) | 값 | 근거 | 상태 |
|---|---|---|---|
realm |
keycloak-patterns |
D5 / 범위 | planned |
clients[].clientId |
spa-client |
범위 | planned |
clients[].publicClient |
true |
D1 PKCE-RFC7636-C1 (SPA=public), OAUTH-BBA-C3 |
planned |
clients[].standardFlowEnabled |
true |
범위 (Standard Flow = Authorization Code) | planned |
clients[].directAccessGrantsEnabled |
false |
범위 (ROPC 비활성) | planned |
clients[].attributes."pkce.code.challenge.method" |
S256 |
D1 KC-PKCE-C3(UI "PKCE method"=S256). 내부 key = UNSUPPORTED_IMPL |
needs-confirmation |
clients[].redirectUris |
["http://localhost/*","http://127.0.0.1/*"] |
D2 KC-GSD-C4 (redirect URI 형식) |
planned |
clients[].webOrigins |
["+"] |
범위 (Redirect URI 에서 CORS 자동 도출) | planned |
roles.realm[].name |
admin-role, user-role |
범위 | planned |
users[].username (+ realmRoles) |
admin-user(admin-role), regular-user(user-role) |
범위 | planned |
users[].credentials[] (초기 password) |
포함 여부·형식 미확정. 별도 bootstrap/reset을 default로 두고 hand-author 금지 | 범위("초기 password") + §엣지 + Claims To Verify #4 | needs-confirmation |
realm token: revokeRefreshToken |
owner가 확정한 target-version 실험값(현재 candidate true) |
D3 → raw/branch-notes/feature-keycloak-refresh-token-rotation D1/D2. key = UNSUPPORTED_IMPL | needs-confirmation |
realm token: refreshTokenMaxReuse |
owner가 0/1 실험 후 확정한 값(현재 candidate 0) |
D3 → concept owner + runtime observation. key = UNSUPPORTED_IMPL | needs-confirmation |
realm token: accessTokenLifespan |
300 (5분, 실행 편의 candidate) |
D4 → concept owner + runtime raw/branch-notes/feature-keycloak-refresh-rotation-and-logout D2. key = UNSUPPORTED_IMPL | needs-confirmation |
2. export 절차 + secret/password redaction
Trace: D5(
KC-IMPORT-C4offline export 경로,KC-CONTAINERcontext)
- UNSUPPORTED_IMPL_DECISION:
kc.sh export의 정확한 flag(--dirvs--file,--users옵션)와 client secret 이 export 에 평문 포함되는지 = cited raw 미증명 → §Claims To Verify. trade-off: 실 export 1회 수행 후 JSON 을 grep 으로 확인하는 절차로 대체.
- Admin console 에서 realm/client/role/user/token 설정 (§1 표대로).
- export:
kc.sh export --realm keycloak-patterns --file /opt/keycloak/data/import/realm-export.json(또는--dir).--users처리 정책은 §엣지 참조. - commit 전 redact:
grep -n 'secret\|password\|credential' realm-export.json→ 평문 노출 필드는 placeholder 치환 또는.gitignore. ./realm-export.json로 repo 에 commit.
3. import 배선 (OUT_OF_BRANCH_SCOPE — delegate)
Trace / R3: volume mount + Keycloak 부트 command
--import-realm는 sibling raw/branch-notes/feature-keycloak-docker-compose-stack D4가 owner (KC-IMPORT-C1/C2/C3/C4인용). 본 branch는 realm-export.json 저작과 consumer acceptance만 담당하며 배선을 재진술하지 않는다. 배선 계약이 바뀌면 본 export 파일 배치에 영향(§엣지·의존).
엣지·실패·의존
R4 캡처: 정상 경로 외 실패/엣지 + 다른 계약 의존(대상 브랜치 + Decision ID).
- 실패·엣지 경로:
- export JSON 에 client secret 평문 포함 가능 — public client 는 secret 없지만 confidential 전환 시 위험. 기대 동작: commit 전
secretgrep + redact(§구현 가이드 2-3). (§Claims To Verify #3) - credential 포함 여부 미확정 — export mode·version에 따라 password/credential 포함 여부와 형식이 다를 수 있다. 기대 동작: 별도 bootstrap/reset을 기본으로 하고 commit 전
secret|password|credential검색, 실제 re-import login으로 검증. (§Claims To Verify #4) - 기존 realm 존재 시 auto-import skip —
KC-IMPORT-C3(멱등).docker compose down -v로 postgres volume 을 삭제해야 재import 됨(볼륨 잔존 시 옛 realm 유지, 새 export 반영 안 됨). - import dir 파일명/확장자 오류 —
KC-IMPORT-C2:.jsonregular file 만 읽고 sub-dir 무시. 경로/확장자 오타 시 silent skip → 부트는 성공하나 realm 없음.
- export JSON 에 client secret 평문 포함 가능 — public client 는 secret 없지만 confidential 전환 시 위험. 기대 동작: commit 전
- 다른 계약 의존:
- raw/branch-notes/feature-keycloak-docker-compose-stack D4 —
--import-realm+ volume mount 배선 owner. 그 D4의 import dir 경로/flag가 바뀌면 본 export 파일 배치 위치·이름에 영향. - raw/branch-notes/feature-keycloak-refresh-token-rotation D1/D2 — rotation 값·정책 owner. raw/branch-notes/feature-keycloak-refresh-rotation-and-logout D1/D5 — target-version 실행·관찰 owner. 결과가 바뀌면 본 realm-export.json token 섹션 동기화 필요.
- raw/branch-notes/feature-keycloak-single-ec2-no-google D3 —
KC_HOSTNAME=localhost+ issuer-uri + network 계약 owner. 이 hostname 계약이 D2의 redirect URI 값(http://localhost/*,http://127.0.0.1/*)의 전제이며, parent D3가 hostname/port를 바꾸면 함께 동기화한다. 본 client scope는 parent D5의 실 구현에 소비된다.
- raw/branch-notes/feature-keycloak-docker-compose-stack D4 —
검증해야 할 주장
공식 문서나 사례는 근거지만, 내 프로젝트에서의 동작을 자동으로 보장하지 않는다.
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
대상 Keycloak Client Capability config의 PKCE method = S256 설정이 token endpoint에서 code_verifier 없는 요청을 거부하는지 |
KC-PKCE-C1/C3은 UI 라벨과 S256 선택을 다루지만 exact HTTP status와 version별 내부 key는 증명하지 않음 |
target UI 설정 후 realm export의 내부 key를 확인하고 PKCE 없는 token request의 응답을 기록 | needs-confirmation |
--import-realm 옵션의 정확한 명령 형식 (docker run ... start-dev --import-realm 또는 kc.sh start --import-realm) |
KC-CONTAINER-C5 가 명시적으로 needs-confirmation — env/option verbatim 부재 |
Keycloak all-config / import 공식 페이지 발췌 후 raw/official-docs/ 에 추가하여 verbatim 인용 확보 |
needs-confirmation |
| Realm export JSON 에 client secret 이 평문으로 포함될 수 있음 → gitignore / redact 필요 | 본 branch 진행 중 메모 — 1차 raw 미수집 | 실 export 수행 후 JSON 파싱 → secret 필드 검색 + 평문 노출 여부 확인 |
needs-confirmation |
| target Keycloak의 export mode가 user credential을 어떤 조건·형식으로 포함하는지 | usersExport=true와 password 포함을 연결하는 1차 근거가 없고 버전별 CLI 옵션 차이 가능 |
target image에서 kc.sh export --help 확인 → 실제 JSON의 credential 필드 검사 → re-import 후 로그인 검증 |
needs-confirmation |
환경 reset (docker compose down -v && up) 후 realm/client/user 자동 import 동작 |
위 D5 가 needs-confirmation — 실제 동작 검증 미수행 |
docker-compose 구동 → admin 로그인 → realm keycloak-patterns 존재 + spa-client 존재 확인 |
planned |
realm-export.json 의 client PKCE 내부 속성 key 가 pkce.code.challenge.method 인지 |
KC-PKCE-C1 "Does not prove" — page 에 내부 속성명 미명시 |
Admin UI 에서 "PKCE method=S256" 설정 후 kc.sh export → 생성된 JSON 의 clients[].attributes key 확인 |
needs-confirmation |
Audit & Findings
/branch-spec채움 중 발견한 정합/근거 이슈. 사용자 작성 결정 영역은 자동 rewrite 하지 않고 정합 권고만 기록(CLAUDE.md §11, consistency-contract).
EVIDENCE_UPGRADE— 노트 최초 작성(2026-05-25) 당시 D1/D2/D5 는 근거 raw 부재로 전부UNSUPPORTED_DECISION이었다. 이후 corpus 성장으로oauth2-pkce-rfc-7636,keycloak-client-pkce-method-enforcement-official,oauth2-browser-based-apps-ietf-draft,oauth-v2-1-draft-ietf,keycloak-getting-started-docker,keycloak-import-export-realms가 추가되어 official 근거로 승격. 재조사(researcher dispatch) 없이 기존 raw 재매핑으로 해결 — 모든 결정이 근거 보유 또는 정당한 UNSUPPORTED trade-off(D4).NAMING_DRIFT(해소 2026-07-18) — §목표·§TODO·§Claims를 대상 UI의PKCE method(Capability config)로 통일했다. 다른 Keycloak 버전의 라벨·내부 key 차이는 생성된 realm export와 대조하며, exact 거부 응답은needs-confirmation으로 유지한다.OWNERSHIP_NARROWED(D5) — 원 D5는 "export commit +--import-realm자동 import"를 함께 기술했으나,--import-realm+ volume mount 배선은 sibling raw/branch-notes/feature-keycloak-docker-compose-stack D4가 owner다. 본 D5는 realm-export.json 저작·commit과 consumer acceptance로 좁혔다.DELEGATED_RATIONALE(D3/D4) — rotation 값·정책은 raw/branch-notes/feature-keycloak-refresh-token-rotation D1/D2, 실행·관찰은 raw/branch-notes/feature-keycloak-refresh-rotation-and-logout D1/D5가 owner다. 본 branch는 target-version 결과로 확정된 값을 realm-export.json에 기록할 뿐Max Reuse나 family invalidation 의미를 재진술하지 않는다.NO_GROUND_TRUTH(code) — 실 구현 repo/home/donghyeon/workspace/keycloak-patterns/부재 확인. 코드 grep 으로actually-implemented확정 불가 → 모든 항목planned/documented-only유지. (ca-tmpl ground truth 는 본 keycloak-patterns 프로젝트에 비적용 — 별개 트리)
마주친 문제
- (구현 시작 후 추가) realm export JSON 안에 client secret이 평문으로 들어가는 경우 — gitignore 또는 redact 필요.
- (구현 시작 후 추가) user password 재설정 자동화 어려움 — 초기 password 정책 / temporary password flag 활용 검토.
묶음
본 sub-sub-branch 는 leaf — 자식 자료 없음. Phase 3 P3A 실 구현 또는 외부 산출물 단계에서 errors / interview prep / lectures 가 누적되면 본 섹션에서 그룹화.
오류 기록 (이 sub-sub-branch 작업 중 발생)
- (없음 — 현재 documented-only 단계)
면접 준비 (이 작업에서 나올 수 있는 면접 질문)
- (없음 — Phase 3 실 구현 단계에 누적)
관련 일일 노트
완료 후 정리
실 구현 후 realm import 자동화 검증 시
planned→actually-implemented/locally-verified승급.
- PR 링크: (별도 keycloak-patterns repo)
- 리뷰 메모:
- 머지 결과 / 배포 환경: 로컬 docker-compose / 단일 EC2 시뮬레이션
- wiki 추출 대상:
actually-implemented항목: (구현 후 채움)locally-verified항목: (구현 후 채움)prod-verified항목: (없음)
- 추출하지 않을 항목: 현재 전부
planned.