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-single-ec2-google-federation (P3B Single EC2 + Google federation) | branch-note | raw | BR-KEYCLOAK-CHILD-D5D01846 | branch-child | keycloak-patterns-overview | WI-KEYCLOAK-PATTERNS-OVERVIEW-020 |
|
1 | feature-keycloak-single-ec2-google-federation | feature-keycloak-patterns |
|
|
2026-05-25 | in-progress | d7981aec13ea69dbc518a68fa2709ba3fa9a7f9ccc7a849a7b039926a9e82f3c |
branch: feature-keycloak-single-ec2-google-federation (P3B Single EC2 + Google federation)
Layer:
raw/branch-notes/— Keycloak 패턴 P3B 한정 sub-branch. 단일 EC2(P3A 토폴로지) + Google IdP brokering. SPA / Spring Boot / Keycloak이 한 호스트에 동거하면서 Keycloak이 Google을 외부 IdP로 위임. SPA flow는 P3A와 동일 (Keycloak만 호출). 본 sub-branch는 문서 + 다이어그램까지만. 실제 EC2 + Google client 등록 + cloudflared / ngrok 시도는 P3A 완료 후의 선택적 확장.status_label:in-progress
부모 (필수)
raw/branch-notes/feature-keycloak-patterns
브랜치 계약 패킷
- 생성 시 프로젝트 개정:
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 변형이다 | single-EC2와 Google federation을 cross-cutting 변형으로 분류한다 | 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 |
|---|
없음.
목표
P3A(단일 EC2, no Google)에 Google federation을 더했을 때 토큰 흐름이 어떻게 바뀌는지, 그리고 단일 EC2 + 외부 IdP 조합이 만들어내는 새로운 제약이 무엇인지 명확히 한다.
핵심 제약 하나: Google이 Keycloak callback URI에 도달해야 함. Google → Keycloak 사이는 redirect 기반이라 사용자 브라우저를 거치지만, 그 redirect URI는 Google Cloud Console에 사전 등록된 HTTPS public URL이어야 한다 (localhost 외에는 HTTP/raw IP 불가). 즉 P3A에서는 localhost:8080만으로도 됐지만 P3B는 public domain + HTTPS가 강제.
면접에서 답해야 할 질문:
- P3A → P3B 추가 비용은? → public domain + TLS + ngrok/Cloudflare Tunnel 학습.
- SPA 코드는 바뀌는가? → 안 바뀜. Keycloak이 Google과 OIDC로 통신, SPA는 늘 Keycloak token만 받음.
- Keycloak이 발급하는 token의 issuer는? → 여전히 Keycloak (Google이 아님). audience도 SPA client.
- 이슈:
- PR:
범위
포함 범위
- P3A → P3B 차이만 (P3A 본문은 raw/branch-notes/feature-keycloak-single-ec2-no-google).
- 단일 EC2 + 외부 IdP의 제약 (public hostname, HTTPS, Google Console redirect URI 등록).
- public issuer·callback·reverse-proxy path가 서로 일치해야 한다는 배포 invariant와 raw/branch-notes/feature-keycloak-reverse-proxy-headers owner pointer.
- Google OAuth client의 Admin UI 표시 callback exact-match invariant와 raw/branch-notes/feature-keycloak-google-redirect-uri-policy owner pointer.
- public URL provider 선택(부모 D3)과 raw/branch-notes/feature-keycloak-public-domain-tunneling 운영 메커니즘 pointer.
- public HTTPS invariant와 raw/branch-notes/feature-keycloak-https-termination-caddy-nginx owner pointer.
- 토큰 교환 sequence (Keycloak ↔ Google brokering이 P3A flow에 삽입되는 위치).
제외 범위
- 실제 EC2 프로비저닝 / Google Cloud Console 등록 / cloudflared 데몬 구동 → 본 sub-branch 범위 밖.
- Google 외 외부 IdP (GitHub / Auth0 / Cognito).
- SAML brokering (OIDC만).
- multi-realm / multi-tenant.
근거 (필수, 최소 1개+)
본 sub-branch의 P3B (Single EC2 + Google federation) 채택 근거. 상세 대안 비교는 §외부 근거 / 대안 조사 참조.
| Source | 정당화하는 결정 |
|---|---|
| raw/official-docs/google-oauth2-redirect-uri-validation-official | Google OAuth redirect URI 검증 규칙 — public domain 확보 필요 근거 |
| raw/official-docs/keycloak-reverseproxy-official | Keycloak behind reverse proxy — proxy 헤더 설정 근거 |
| raw/official-docs/keycloak-hostname-configuration | Keycloak hostname guide — proxy 환경 추가 설정 근거 |
| raw/official-docs/keycloak-identity-brokering-overview-official | Identity Broker (P1B/P2B 공유) — Google IdP brokering 근거 |
| raw/official-docs/ngrok-http-tunnel-official | ngrok HTTP tunnel — 임시 public URL 근거 |
| raw/official-docs/cloudflare-tunnel-routing-official | Cloudflare Tunnel — ngrok 대안 (정적 도메인) 근거 |
컴포넌트 다이어그램
텍스트
EC2 (public IP / 도메인 필요)
├─ nginx or Caddy (port 80/443, TLS termination)
├─ Spring Boot (port 8081, Resource Server)
└─ Keycloak (port 8080, behind reverse proxy)
[1] Browser → EC2:443 → SPA load (HTML/JS, vanilla)
[2] Browser → EC2:443/keycloak/realms/{realm}/protocol/openid-connect/auth
→ Keycloak 로그인 화면 (사용자 "Google 로그인" 선택)
[3] Keycloak → 302 redirect → Google OIDC authorize endpoint (외부)
[4] Browser → Google 인증 UI → 사용자 동의
[5] Google → 302 redirect → EC2:443/keycloak/realms/{realm}/broker/google/endpoint
(=Keycloak broker endpoint, 반드시 public 접근 가능)
[6] Keycloak ← (server-to-server) Google /token endpoint → Google ID token + access token
[7] Keycloak이 Google user → Keycloak user 매핑 (first-login: 신규 생성)
[8] Keycloak → 302 redirect → SPA callback (Keycloak code)
[9] SPA → EC2:443/keycloak/realms/{realm}/protocol/openid-connect/token
→ Keycloak access token + refresh token + ID token
[10] Browser → EC2:443/api/* (Authorization: Bearer <keycloak-access-token>)
→ Spring Boot → Keycloak JWKS (localhost 내부) → 검증 → 응답
Mermaid
sequenceDiagram
autonumber
participant B as Browser (SPA)
participant N as nginx (EC2 :443)
participant K as Keycloak (EC2 :8080)
participant G as Google OIDC
participant API as Spring Boot (EC2 :8081)
B->>N: GET / (SPA load)
N-->>B: index.html
B->>N: GET /keycloak/.../auth
N->>K: proxy
K-->>B: 로그인 화면 (Google 선택지 포함)
B->>K: "Google 로그인" 선택
K-->>B: 302 redirect to Google authorize
B->>G: authorize (Google client_id)
G-->>B: 사용자 인증 + 동의
G-->>B: 302 redirect to https://kc.example.com/keycloak/.../broker/google/endpoint?code=...
B->>N: GET /keycloak/.../broker/google/endpoint?code=...
N->>K: proxy
K->>G: POST /token (code + client_secret) [server-to-server]
G-->>K: Google ID token + access token
K->>K: Google user → Keycloak user 매핑
K-->>B: 302 redirect to SPA callback (Keycloak code)
B->>N: GET /keycloak/.../token (code exchange)
N->>K: proxy
K-->>B: Keycloak access/refresh/ID token
B->>N: GET /api/orders (Bearer KC token)
N->>API: proxy
API->>K: JWKS fetch (localhost, 내부)
K-->>API: JWKS
API-->>B: 200 OK
토큰 교환 sequence (P3A 대비 추가 부분만)
P3A의 단계는 raw/branch-notes/feature-keycloak-single-ec2-no-google. 본 sub-branch는 Keycloak ↔ Google brokering이 어디 끼는지만 명확히.
- P3A 단계 1 (SPA → Keycloak /auth)까지 동일.
- P3A 단계 2 (사용자 로그인)에서 사용자가 "Google" identity provider 선택 → 아래 brokering 분기 삽입:
- B-1: Keycloak이 사용자 브라우저를 Google
/authorize로 302 redirect (Google client_id, Keycloak이 redirect_uri로 자기 broker endpoint 전달). - B-2: 사용자가 Google에서 인증 → Google이 사용자 브라우저를 Keycloak broker endpoint (
/realms/{realm}/broker/google/endpoint?code=...)로 302 redirect. - B-3: Keycloak이 server-to-server로 Google
/token에 code → Google ID token + access token 교환. - B-4: Keycloak이 ID token claim(email 등)으로 Keycloak user를 lookup / first-login 시 신규 생성.
- B-1: Keycloak이 사용자 브라우저를 Google
- 이후 P3A 단계 3-5 (Keycloak이 SPA에 code 발급 → SPA가 token exchange → SPA가 backend 호출)는 동일.
핵심: SPA가 받는 token은 Google token이 아니라 Keycloak token. Google token은 Keycloak이 보관 (broker link 정보).
단일 EC2 + Google federation 추가 제약
P3A 대비 늘어나는 운영 요구사항. 이게 P3B의 학습 포인트.
1) 공개 도메인 필수
- Google Cloud Console "Authorized redirect URIs"에 등록할 URL은 HTTPS + 도메인 형식 (localhost / raw IP 불가, 단 localhost는 dev 한정 일부 허용).
- 단일 EC2 학습 환경이라도 도메인 1개 + DNS A 레코드 → EC2 public IP 매핑 필요.
- 근거: raw/official-docs/google-oauth2-redirect-uri-validation-official.
reverse-proxy 정합
- 배포 invariant: 브라우저가 보는 public issuer·OIDC discovery·broker callback path와 proxy가 origin에 전달하는 host/scheme/path가 일치해야 한다. 환경변수·header·subpath의 정확한 값과 method 선택은 raw/branch-notes/feature-keycloak-reverse-proxy-headers가 소유하며 본 문서는 재진술하지 않는다.
3) 개발 환경 — stable public callback
- 부모 D3의 선택: 반복 가능한 Google callback은 Cloudflare named tunnel + Cloudflare가 관리하는 custom domain을 사용한다.
trycloudflare.comquick tunnel과 ngrok random URL은 dev-only fallback이며 URL이 바뀔 때 Google Console callback도 함께 갱신한다. 명령·DNS·ingress 절차는 raw/branch-notes/feature-keycloak-public-domain-tunneling가 소유한다.
4) TLS termination
- 배포 invariant: Google에 등록하는 public callback은 HTTPS여야 하고 선택한 TLS termination 경로가 public scheme을 끝까지 보존해야 한다. Caddy/nginx/Cloudflare의 선택과 설정 상세는 raw/branch-notes/feature-keycloak-https-termination-caddy-nginx가 소유한다.
5) Google Cloud Console 등록
- 배포 invariant: Keycloak Admin UI가 표시한 broker callback 값을 Google Cloud Console에 그대로 등록하고 실제 요청값과 exact match시킨다. URL 조립·갱신·검증 절차는 raw/branch-notes/feature-keycloak-google-redirect-uri-policy가 소유하며 본 문서는 endpoint 문자열을 재구성하지 않는다.
장점 / 단점 vs P3A
장점
- 사용자 Google 로그인 가능: Keycloak user store 외에 social login 1개 추가.
- P3A 학습 + Google federation 학습 동시: 단일 EC2의 단순함 + OIDC brokering의 핵심을 한 번에.
- SPA 코드 영향 0: SPA는 Keycloak만 호출. Identity provider 추가/제거는 Keycloak 측 설정.
- token issuer가 Keycloak으로 통일: backend는 Google JWT를 직접 검증할 필요 없음 (Keycloak이 broker).
단점
- public 도메인 + HTTPS 요구: 학습 friction +1 (P3A는 localhost로 끝남).
- random URL 갱신 friction: ngrok/quick tunnel URL이 바뀌면 Google Console callback도 갱신해야 함. 반복 학습은 D3의 Cloudflare named tunnel + managed custom domain 사용.
- 운영 surface 증가: Google client_secret 관리, Keycloak hostname 잘못 설정 시 invalid_redirect_uri 디버깅 비용.
- 사용자 매핑 정책 결정: Google email → 기존 Keycloak user 자동 link 여부 (first-login flow 설정).
TODO
각 항목 옆에 증거 등급 표기: actually-implemented | locally-verified | prod-verified | documented-only | planned | needs-confirmation
- P3A→P3B brokering 분기 삽입 위치 sequence 명세 (§토큰 교환 sequence) — 등급:
documented-only - 단일 EC2 + Google federation 추가 제약 5종 정리 (§단일 EC2 추가 제약) — 등급:
documented-only - 컴포넌트/시퀀스 다이어그램 (§컴포넌트 다이어그램) — 등급:
documented-only - 대안 5종 비교 조사 (§외부 근거 / 대안 조사) — 등급:
documented-only - 실 EC2 프로비저닝 + Google client 등록 + cloudflared 구동 — 등급:
planned(본 sub-branch 범위 밖, P3A 완료 후 선택 확장) - §Claims To Verify 6종 실 기동 검증 — 등급:
planned(실 배포 시점에만 가능)
진행 중 메모
- 본 sub-branch 는 documented-only (D1). 실 배포(EC2 / Google client / cloudflared)는 P3A 완료 후 선택 확장 — 여기서는 config recipe + sequence + 제약만 명세한다.
- P3A(raw/branch-notes/feature-keycloak-single-ec2-no-google) 토폴로지에 Google brokering 분기만 삽입 — 새로 생기는 요구는 "public 접근 가능한 callback URL 도달성" 하나뿐(§목표, §토큰 교환 sequence).
- §구현 가이드는 child owner pointer와 deploy invariant만 제공한다. 각 child의 config/명령 및 결합 chain은 실 기동 검증 전까지
actually-implemented로 승격하지 않는다.
결정 사항 (decisions)
- 2026-05-25: 본 패턴은 문서 + 다이어그램까지만. 실 구현(EC2 프로비저닝, Google client 등록, cloudflared 구동)은 진행하지 않음. 이유: root branch가 "P3A 한정 구현"으로 결정 → P3B는 P3A 완료 후 선택적 확장.
- 2026-05-25: P3B의 핵심 학습 포인트를 "Google이 Keycloak callback URI에 도달해야 한다는 제약" 단 한 줄로 압축. 나머지(hostname, proxy headers, ngrok 등)는 그 제약의 파생.
- 2026-07-18 (D3 owner clarification): stable Google callback의 기본 경로는 Cloudflare named tunnel + Cloudflare-managed custom domain이다.
trycloudflare.comquick tunnel과 ngrok random URL은 dev-only fallback이며 URL 회전 시 Google Console callback 갱신이 필요하다. provider 우선순위는 본 부모 D3가 소유하고, 운영 명령·DNS 메커니즘은 child가 소유한다. - 2026-05-25: Keycloak ↔ Google brokering 흐름은 P1B / P2B와 OIDC sequence 동일 — 차이는 "어디에 Keycloak이 떠 있나"뿐. 본 sub-branch는 P3A 토폴로지 + brokering 분기 삽입 위치만 명시.
결정-근거 매핑
각 결정이 어떤 raw source claim 으로 뒷받침되는지. P3B 는 문서/다이어그램 단계라 일부 결정은 우선순위/scope 기반 →
UNSUPPORTED_DECISION.
| Decision ID | Decision | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|
| D1 | 본 패턴은 문서 + 다이어그램까지만 (실 EC2/Google client/cloudflared 구동 안 함) | UNSUPPORTED_DECISION — 학습 scope 결정으로 공식 근거 대상 아님 |
(project scope 결정) | 실 구현 없이 문서만으로 면접 답변 시 "직접 해본 것"으로 오해 금지 — documented-only 등급 명시 필수 |
| D2 | P3B 의 핵심 학습 포인트를 "Google 이 Keycloak callback URI 에 도달해야 한다" 한 줄로 압축 | raw/official-docs/google-oauth2-redirect-uri-validation-official.md#GOOGLE-REDIR-C1, raw/official-docs/google-oauth2-redirect-uri-validation-official.md#GOOGLE-REDIR-C2, raw/official-docs/google-oauth2-redirect-uri-validation-official.md#GOOGLE-REDIR-C3 |
official-vendor-doc |
"한 줄로 압축" 자체는 학습 framing — 실 구현 시 hostname/proxy headers 가 추가 결정점으로 부각될 수 있음 |
| D3 | public URL provider 선택 owner — stable Google callback은 Cloudflare named tunnel + managed custom domain, random quick tunnel/ngrok는 dev-only fallback | raw/official-docs/cloudflare-tunnel-routing-official.md#CLOUDFLARE-TUNNEL-C1, raw/official-docs/cloudflare-tunnel-routing-official.md#CLOUDFLARE-TUNNEL-C2, raw/official-docs/cloudflare-tunnel-routing-official.md#CLOUDFLARE-TUNNEL-C4, raw/official-docs/ngrok-http-tunnel-official.md#NGROK-C1, raw/official-docs/ngrok-http-tunnel-official.md#NGROK-C3, raw/official-docs/ngrok-http-tunnel-official.md#NGROK-C4, raw/official-docs/google-oauth2-redirect-uri-validation-official.md#GOOGLE-REDIR-C3, raw/official-docs/google-oauth2-redirect-uri-validation-official.md#GOOGLE-REDIR-C5 |
official-vendor-doc + official-vendor-doc + official-vendor-doc |
managed custom domain의 Google 등록과 end-to-end callback은 미검증. child raw/branch-notes/feature-keycloak-public-domain-tunneling는 이 선택을 소비해 운영 profile만 소유 |
| D4 | reverse-proxy deploy invariant — public issuer·discovery·broker callback의 host/scheme/path가 proxy가 전달하는 값과 일치해야 함. raw/branch-notes/feature-keycloak-reverse-proxy-headers D1 — proxy-header parsing invariant. raw/branch-notes/feature-keycloak-reverse-proxy-headers D3 — public path assembly invariant | raw/official-docs/keycloak-hostname-configuration.md#KC-HOST-C2, raw/official-docs/keycloak-hostname-configuration.md#KC-HOST-C5, raw/official-docs/keycloak-reverseproxy-official.md#KC-RP-C2, raw/official-docs/keycloak-reverseproxy-official.md#KC-RP-C3, raw/official-docs/keycloak-reverseproxy-official.md#KC-RP-C4, raw/official-docs/keycloak-reverseproxy-official.md#KC-RP-C5, raw/official-docs/keycloak-reverseproxy-official.md#KC-RP-C6 |
official-vendor-doc + delegated detail |
target proxy chain에서 discovery issuer와 callback을 실측하고 child decision과 대조 필요 |
| D5 | Google email_verified=true + hd 정책 검사 + First Broker Login Flow 로 사용자 매핑 |
raw/official-docs/keycloak-identity-brokering-overview-official.md#KC-IDP-BROKER-C1, raw/official-docs/keycloak-first-broker-login-flow.md#KC-FBL-C1, raw/official-docs/google-oidc-discovery-spec.md#GOOGLE-OIDC-C5, raw/official-docs/google-oidc-discovery-spec.md#GOOGLE-OIDC-C7 |
official-vendor-doc |
KC-FBL-C2/C3/C4 는 모두 needs-confirmation 상태 (2026-05-25 quote, 재검증 보류). 실 동작 검증 시 first-broker-login authenticator UI 직접 확인 필요 |
| D6 | redirect deploy invariant — Keycloak Admin UI가 표시한 broker callback을 Google Cloud Console에 그대로 등록하고 실제 요청값과 exact match시킴. URL 조립·갱신 정책은 raw/branch-notes/feature-keycloak-google-redirect-uri-policy 소유 | raw/official-docs/keycloak-identity-brokering-overview-official.md#KC-IDP-BROKER-C2, raw/official-docs/google-oauth2-redirect-uri-validation-official.md#GOOGLE-REDIR-C3 |
needs-confirmation + official-vendor-doc + delegated detail |
Admin UI 표시값과 실제 요청값의 target-version 일치 여부를 실 로그인으로 확인 필요 |
구현 가이드
본 sub-branch 는 documented-only (D1) — 아래는 실 배포 시 되묻지 않을 config recipe 의 사전 명세이며, 어느 항목도 아직 기동 검증되지 않았다(각 등급 열 =
planned/needs-confirmation). 값의 상세 서술 owner 는 §단일 EC2 + Google federation 추가 제약 이고, 여기서는 Trace(D-ID + Claim ID) + 임의결정 라벨만 정리한다(재진술 금지).
1. Reverse-proxy / hostname integration contract (Reference-Only)
Trace: D4 +
KC-HOST-C2/C5,KC-RP-C2..C6.
- 본 부모가 유지하는 것은 public issuer·discovery·broker callback의 host/scheme/path가 proxy 전달값과 일치한다는 deploy invariant 한 줄이다.
- raw/branch-notes/feature-keycloak-reverse-proxy-headers D1 — proxy-header parsing invariant. raw/branch-notes/feature-keycloak-reverse-proxy-headers D3 — public path assembly invariant.
- raw/branch-notes/feature-keycloak-header-spoofing-defense D6 — trusted proxy boundary owner. raw/branch-notes/feature-keycloak-iss-claim-hostname-mismatch D6 — hostname/issuer bridge profile owner. TLS 종단은 raw/branch-notes/feature-keycloak-https-termination-caddy-nginx가 소유한다. 본 문서에서 값을 복제하지 않는다.
2. Public callback URL 선택 contract (Reference-Only)
Trace: D3 +
CLOUDFLARE-TUNNEL-C1/C2/C4,NGROK-C1/C3/C4,GOOGLE-REDIR-C3/C5.
- stable callback은 Cloudflare named tunnel + managed custom domain, random quick tunnel/ngrok는 dev-only fallback이라는 선택만 본 부모 D3가 소유한다.
- tunnel 생성·DNS·ingress·실행 명령과 fallback 운영 절차는 raw/branch-notes/feature-keycloak-public-domain-tunneling D1/D2가 소유한다.
3. Google callback 등록 contract (Reference-Only)
Trace: D6 +
KC-IDP-BROKER-C2,GOOGLE-REDIR-C3.
- Keycloak Admin UI가 표시한 callback 문자열을 Google Cloud Console에 그대로 등록하고 실제 요청값과 exact match시킨다.
- client type, endpoint URL 조립, trailing slash/case, URL 회전 시 갱신 절차는 raw/branch-notes/feature-keycloak-google-redirect-uri-policy D1/D8이 소유한다. 본 부모는 특정 endpoint 문자열을 copyable 값으로 제공하지 않는다.
4. First Broker Login 사용자 매핑 (consume-only — 정책 owner 는 sibling branch)
Trace: 본 sub-branch(P3B 토폴로지)는 first-broker-login flow 를 consume 만 한다 — 매칭키·소유증명·auto-link 정책 자체는 다른 branch 소유(아래 위임)이며 여기서 재정의하지 않는다. 소비 지점 근거:
keycloak-first-broker-login-flow#KC-FBL-C1(First login flow 존재) ·google-oidc-discovery-spec#GOOGLE-OIDC-C6(sub = unique primary key) ·#GOOGLE-OIDC-C7(hd = Workspace 도메인) ·keycloak-identity-brokering-overview-official#KC-IDP-BROKER-C1.
- OUT_OF_BRANCH_SCOPE (위임, 재정의 금지): (a) linking key
sub→ raw/branch-notes/feature-keycloak-account-linking-sub-vs-emailD1(sub-only 결정, core owned) 소유. (b) 기존 local 계정 link 시 password 재인증 / Confirm Link Existing Account authenticator → raw/branch-notes/feature-keycloak-first-broker-login-flowD2+ raw/branch-notes/feature-keycloak-account-linking-sub-vs-emailD2소유. (c)email_verified=falsesilent auto-link 차단 → raw/branch-notes/feature-keycloak-first-broker-login-flowD4(AutoLink DISABLED = core) 소유.
- P3B 범위 consume 지점: Google ID token claim(
email,email_verified,hd,sub)이 single-EC2 배치의 Keycloak first-broker-login flow 로 유입 → user lookup / first-login 신규 생성. 매칭·link 정책의 종결은 위 owner 브랜치(§엣지·실패·의존 "다른 계약 의존"에도 링크). 본 노트는 그 정책이 어느 배치에서든 동일하게 적용됨을 전제로 P3A 토폴로지 위에서 flow 를 실행할 뿐.
엣지·실패·의존
R4 캡처용. 정상 sequence(§컴포넌트 다이어그램) 외에 실 배포 시 부딪힐 실패/엣지 + 다른 branch 계약 의존. 본 sub-branch 는 documented-only 이므로 아래는 실 기동 시 예상되는 경로다(§Claims To Verify 가 검증 방법 owner).
- 실패·엣지 경로:
redirect_uri_mismatch: Google Console 등록 URI와 Admin UI 표시 callback이 다르면 로그인 거부. 기대 동작과 갱신 절차는 raw/branch-notes/feature-keycloak-google-redirect-uri-policy D1/D8을 따른다.- reverse-proxy public context 유실: proxy chain 어느 홉에서든 public host/scheme/path 계약이 깨지면 discovery·issuer·callback 정합이 무너진다. 정확한 header/env 검증은 raw/branch-notes/feature-keycloak-reverse-proxy-headers가 소유한다.
- random URL 회전: dev-only fallback URL이 바뀌면 등록 callback이 stale해진다. 반복 사용은 D3의 named tunnel + managed custom domain으로 전환한다.
- proxy-header spoofing: trusted proxy 경계가 잘못되면 외부 입력이 public URL 계산에 개입할 수 있다. 구체 방어값과 검증은 raw/branch-notes/feature-keycloak-header-spoofing-defense D6이 소유한다.
- first-broker-login 중복 email: 같은 email 의 local user 선점 시 무단 link 위험 → "Confirm Link Existing Account" authenticator 필요(
KC-FBL-C2, §Claims To Verify #6).
- 다른 계약 의존:
- raw/branch-notes/feature-keycloak-single-ec2-no-google (P3A) 의 단일 EC2 reverse-proxy 토폴로지 에 의존 — 본 브랜치는 그 base 에 brokering 분기만 삽입(§목표). P3A 의 nginx/port 배치 결정이 바뀌면 본 브랜치 config(§구현 가이드 1) 영향.
- raw/branch-notes/feature-keycloak-edge-forwardauth-google-federation (P1B) · raw/branch-notes/feature-keycloak-internal-spa-direct-google-federation (P2B) 와 동일 OIDC brokering sequence — 차이는 배치뿐(§결정 사항 4). brokering flow 결정이 바뀌면 세 브랜치 공동 갱신.
- account-linking / first-broker-login 정책 의존 (§구현 가이드 4 consume-only): raw/branch-notes/feature-keycloak-account-linking-sub-vs-email
D1(sub-only 매칭키)·D2(기존계정 link 재인증) + raw/branch-notes/feature-keycloak-first-broker-login-flowD2(Confirm Link)·D4(email_verified auto-link 차단) 가 소유. 본 브랜치는 그 정책을 배치 무관하게 consume — 정책이 바뀌면 본 노트 §구현 가이드 4 의 consume 서술도 갱신. - sub-sub-branch 관심사 위임: raw/branch-notes/feature-keycloak-public-domain-tunneling(tunnel 상세) · raw/branch-notes/feature-keycloak-reverse-proxy-headers(proxy header 상세) · raw/branch-notes/feature-keycloak-google-redirect-uri-policy(redirect URI 정책) · raw/branch-notes/feature-keycloak-https-termination-caddy-nginx(TLS termination) 가 각 관심사 detail owner.
검증해야 할 주장
공식 문서는 P3B 의 각 요소를 보장하지만, 전체 chain (Cloudflare Tunnel → nginx → Keycloak → Google) 의 결합 동작은 실 구현 시점에서만 검증 가능.
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
| Cloudflare named tunnel + managed custom domain이 Google callback 등록과 실제 brokering에 통과 | 공식 자료는 각 구성요소를 다루지만 결합 chain은 보장하지 않음 | child raw/branch-notes/feature-keycloak-public-domain-tunneling의 acceptance 절차로 managed hostname 등록·실 login 확인 | needs-confirmation |
| proxy chain이 public host/scheme/path를 보존해 discovery issuer와 callback이 동일 public context를 사용하는지 | Keycloak의 parsing ability와 전체 chain 결합 동작은 별개 | raw/branch-notes/feature-keycloak-reverse-proxy-headers의 discovery·header acceptance 결과를 본 D4 invariant와 대조 | planned |
| Keycloak Admin UI 표시 callback과 Google Cloud Console 등록값이 exact match해 실제 login이 성공하는지 | GOOGLE-REDIR-C3 정책은 확보했지만 target-version UI 값과 실제 요청 결합은 미검증 |
raw/branch-notes/feature-keycloak-google-redirect-uri-policy의 exact-match test 수행 | needs-confirmation |
| child owner의 trusted-proxy 설정이 외부 spoofing을 차단하는지 | 옵션 존재와 실제 drop/ignore/log 동작은 별개 | raw/branch-notes/feature-keycloak-header-spoofing-defense D6의 negative test 결과 참조 | planned |
| Keycloak first-broker-login flow 가 Account Linking 시 "비밀번호 확인 후 link" 정책으로 실제 작동 | KC-FBL-C2 등이 needs-confirmation 등급 — 정책 UI 토글 위치/동작 불확실 |
Admin UI → Authentication → First Broker Login → flow copy + Confirm Link Existing Account authenticator 추가 → 같은 email 의 local user 사전 생성 후 Google 로그인 시도 | needs-confirmation |
마주친 문제
- 아직 없음 (문서 단계).
묶음 (자식 sub-sub-branches)
- raw/official-docs/cloudflare-tunnel-routing-official
- raw/official-docs/google-oauth2-redirect-uri-validation-official
- raw/official-docs/keycloak-hostname-configuration
- raw/official-docs/keycloak-identity-brokering-overview-official
- raw/official-docs/keycloak-reverseproxy-official
- raw/official-docs/ngrok-http-tunnel-official
- raw/branch-notes/feature-keycloak-public-domain-tunneling
- raw/branch-notes/feature-keycloak-reverse-proxy-headers
- raw/branch-notes/feature-keycloak-google-redirect-uri-policy
- raw/branch-notes/feature-keycloak-https-termination-caddy-nginx
Sources는 하단 "외부 근거" 섹션. Errors/Interview/Lectures/Blog 는 현재 없음.
관련 일일 노트
관련 sub-branch
- raw/branch-notes/feature-keycloak-patterns (root)
- raw/branch-notes/feature-keycloak-single-ec2-no-google — P3A Single EC2 (no Google) ← P3B의 베이스 토폴로지, vanilla JS 구현 대상
- raw/branch-notes/feature-keycloak-edge-forwardauth-google-federation — P1B Edge + Google federation (다른 배치, 동일 brokering 흐름)
- raw/branch-notes/feature-keycloak-internal-spa-direct-google-federation — P2B Internal + Google federation (다른 배치, 동일 brokering 흐름)
외부 근거 / 대안 조사 (2026-05-25 — P3B Single EC2 + Google IdP Brokering)
본 sub-branch의 단일 EC2 + Google IdP Brokering 채택에 대한 외부 source. P3A에 federation 추가 시 발생하는 public 도메인 + HTTPS 요구사항 중심.
- 채택 결정 (Single EC2 + Public Domain + Keycloak Reverse Proxy 설정 + Google IdP):
- raw/official-docs/google-oauth2-redirect-uri-validation-official — Google OAuth client redirect URI 검증 규칙 (localhost test-only, prod HTTPS 필수)
- raw/official-docs/keycloak-reverseproxy-official — Keycloak behind reverse proxy (KC_PROXY_HEADERS, KC_HTTP_RELATIVE_PATH)
- raw/official-docs/keycloak-hostname-configuration — Keycloak hostname guide (proxy 환경 추가 설정)
- raw/official-docs/keycloak-identity-brokering-overview-official — Identity Broker (P1B/P2B 공유 source)
- raw/official-docs/ngrok-http-tunnel-official — ngrok HTTP tunnel (개발 환경 임시 public URL)
- raw/official-docs/cloudflare-tunnel-routing-official — Cloudflare Tunnel (ngrok 대안, 정적 도메인)
- 검토한 대안:
- 대안 1: P3A 유지 (no Google federation) — Google 학습을 별도 sub-project로. 장: 학습 friction 최소 / 단: federation 학습 누락. 비교 sub-branch: raw/branch-notes/feature-keycloak-single-ec2-no-google.
- 대안 2: localhost-only + Google Workspace SAML — Workspace SAML은 일부 환경에서 localhost 허용. 그러나 일반 Google 계정은 OIDC만 + localhost 제한.
- 대안 3: AWS EC2 public IP + Route53 도메인 + ACM cert — production-like. 장: HTTPS termination 학습 / 단: AWS 비용 + cert provisioning 시간.
- 대안 4: K8s + cert-manager + Let's Encrypt (P2B 진화) — 분리 배치 + 자동 cert. 장: prod-like / 단: P3 목적(단일 host 학습)과 어긋남.
- 대안 5: Cognito + Google federation (Keycloak 제거) — AWS managed. 본 학습 목적에 부적합.
- 비교 핵심: P3A 대비 추가되는 핵심 운영 요구는 public HTTPS callback URL이다. 반복 가능한 학습 환경은 D3의 Cloudflare named tunnel + managed custom domain을 사용하고, random quick tunnel/ngrok는 dev-only fallback으로 취급한다. public issuer·proxy context는 raw/branch-notes/feature-keycloak-reverse-proxy-headers, TLS는 raw/branch-notes/feature-keycloak-https-termination-caddy-nginx, callback exact-match는 raw/branch-notes/feature-keycloak-google-redirect-uri-policy의 결정과 검증을 소비한다.
완료 후 정리
본 sub-branch는 문서까지만. wiki 추출은 root branch의 6 패턴 비교 매트릭스 시점에 일괄 처리.
- PR 링크:
- 리뷰 메모:
- 머지 결과 / 배포 환경: 해당 없음 (문서 단계, P3B 실 구현 안 함).
- 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 전체가