--- title: branch / feature-keycloak-public-domain-tunneling (P3B 학습 환경 public 도메인 확보 — ngrok / Cloudflare Tunnel) source_type: branch-note status: raw id: BR-KEYCLOAK-CHILD-89A2896F kind: branch-child project: keycloak-patterns-overview work_item: WI-KEYCLOAK-PATTERNS-OVERVIEW-020 inherits: [DEC-KEYCLOAK-PATTERNS-OVERVIEW-AUTH-TAXONOMY-001@1] refines: [] overrides: [] depends_on: [] contract_packet: 1 branch: feature-keycloak-public-domain-tunneling parent_branch: feature-keycloak-patterns related_projects: [keycloak-patterns] tags: [branch, keycloak-patterns, p3b, public-domain, ngrok, cloudflare-tunnel, https] created: 2026-05-25 target_merge: status_label: in-progress contract_packet_sha256: 5605aa356ecefd27cabba9dff6699e3058ee39235cbb0dd012b97176fb46a417 --- # branch: feature-keycloak-public-domain-tunneling (P3B 학습 환경 public 도메인 확보 — ngrok > Layer: `raw/branch-notes/` — [[raw/branch-notes/feature-keycloak-patterns]] governance Work Item의 child. P3B 의미 계약은 [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]]를 참조한다. **Google OAuth redirect_uri 정책(HTTPS + localhost 외 IP 불가)** 때문에 학습 환경에서 어떻게 public URL을 확보할지 비교. > 본 sub-sub-branch는 **문서까지만** — 실 ngrok 구동 / Cloudflare Tunnel 설치 / EC2 도메인 매핑은 진행하지 않음. 등급 `documented-only` (P3B 전체 등급에 종속). > `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 변형의 public-domain tunnel 경계에 적용한다 | [[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에서는 `localhost:8080`으로 모든 통신이 끝났지만 P3B는 **Google이 Keycloak callback URI로 redirect** 해야 한다. Google OAuth 2.0 client는 **redirect_uri를 HTTPS 도메인으로 제한** (localhost는 dev 한정 예외, raw IP 금지). 따라서 학습 환경에서도 public 접근 가능한 HTTPS URL을 어떻게 확보할지 결정해야 한다. 면접에서 답해야 할 질문: 1. 학습 환경에서 왜 EC2 public IP만으론 부족한가? → Google이 IP 주소 redirect_uri 거부, HTTPS + 도메인 강제. 2. 부모가 선택한 public URL 전략을 어떻게 실행하나? → [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]] D3가 provider 우선순위를 소유하고, 본 문서는 named tunnel·managed custom domain과 임시 random URL의 운영 차이만 구체화한다. 3. 학습 → 운영 전환 시 무엇이 바뀌나? → tunnel 제거하고 EC2 public IP + Route53 A 레코드 + ACM cert로 대체. - 이슈: - PR: ## 범위 ### 포함 범위 - ngrok / Cloudflare Tunnel / EC2 + Route53 도메인 3개 옵션의 trade-off - 비교표: cost / static URL / TLS 자동 / 운영 비용 / inbound port 노출 - Google redirect_uri 정책과 각 옵션의 적합도 - 부모 [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]] D3의 채택 결정을 소비해 Cloudflare named tunnel·managed custom domain, ngrok 임시 URL, EC2 도메인 옵션의 실행 메커니즘을 정리 ### 제외 범위 - 실 ngrok account 생성, Cloudflare account 연동, cloudflared 데몬 설치 - 자체 도메인 구매 / Route53 hosted zone 생성 - 운영용 ACM cert / ALB 구성 (P3B 운영 시나리오는 부모 sub-branch의 "대안 3"로만 언급) - ngrok / Cloudflare Tunnel의 enterprise 기능 (custom domain on free plan 제외, IP allowlist 등) ## 근거 (필수, 최소 1개+) - [[raw/official-docs/ngrok-http-tunnel-official]] — ngrok HTTP tunnel 공식 - [[raw/official-docs/cloudflare-tunnel-routing-official]] — Cloudflare Tunnel routing 공식 - [[raw/official-docs/google-oauth2-redirect-uri-validation-official]] — Google redirect_uri 정책 (HTTPS + localhost 외 IP 불가) ## TODO 각 항목 옆에 증거 등급 표기. - [ ] **ngrok 무료 plan 동작 확인** — `ngrok http 80` → `https://.ngrok-free.app` 임시 URL 발급, 세션 종료 시 URL 변경 — 등급: `planned` - [ ] **Cloudflare Tunnel 동작 확인** — `cloudflared tunnel create ` + `cloudflared tunnel route dns kc.example.com` → named tunnel과 Cloudflare가 관리하는 custom hostname 연결. `trycloudflare.com` quick tunnel의 random URL은 고정 callback으로 사용하지 않음 — 등급: `planned` - [ ] **EC2 public IP + Route53 도메인 옵션 정리** — Route53 hosted zone + A 레코드 + ACM cert + ALB (또는 EC2 직결 + nginx + Let's Encrypt) — 등급: `planned` - [ ] **비교표 작성** — cost / static URL / TLS 자동 / inbound port 노출 / 운영 비용 / Google Console redirect_uri exact match 적합도 — 등급: `planned` - [ ] **부모 결정 수용 확인** — [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]] D3의 Cloudflare named tunnel + managed custom domain 기본 경로와 random URL dev-only fallback을 본 실행 절차에 반영 — 등급: `planned` ## 진행 중 메모 - ngrok free plan은 2026-05 기준 1 세션당 random subdomain. `https://<8자>.ngrok-free.app` 형식. 세션 끊기면 다음 세션은 다른 subdomain. - Cloudflare Tunnel의 `trycloudflare.com` quick tunnel은 무료지만 URL이 random (ngrok와 유사). 정적 도메인 원하면 Cloudflare account + 자체 도메인 (Cloudflare DNS로 위임) + named tunnel 필요. - EC2 public IP는 인스턴스 stop/start 시 변경 (Elastic IP 할당하면 고정). 도메인 매핑 안 하면 Google이 redirect_uri로 IP 거부. - 학습 환경 핵심: **Google Console에 등록한 redirect_uri와 실제 Keycloak issuer URL이 글자 단위로 일치**해야 함 (Google exact match 정책). URL 변경 시마다 Console 업데이트 필요. ### 비교표 초안 | 항목 | ngrok free | Cloudflare Tunnel (named) | EC2 + Route53 + ACM | |------|-----------|---------------------------|---------------------| | cost | 무료 | 무료 (Cloudflare account 필요) | Route53 hosted zone $0.50/월 + ACM 무료 + EC2 비용 | | static URL | ❌ (세션마다 변경) | ✅ (영구) | ✅ | | TLS 자동 | ✅ (ngrok edge) | ✅ (Cloudflare edge) | ACM + ALB (자동) 또는 Let's Encrypt (cron) | | inbound port 노출 | 불필요 (egress only) | 불필요 (egress only) | 필요 (443 open) | | 운영 비용 | 매 세션 Console 갱신 | 도메인 1회 설정 후 무 | DNS / cert / SG 관리 | | Google redirect_uri 적합도 | 낮음 (URL 변경 burden) | 높음 (정적) | 높음 (정적) | ## 결정 사항 (decisions) - **2026-05-25 (Historical / superseded selection wording)**: 본 문서가 Cloudflare 1순위·ngrok 2순위를 직접 결정한다고 적었으나, provider 우선순위의 owner는 부모 [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]] D3이다. 본 문서는 선택 결과의 운영 메커니즘만 소유한다. - **2026-07-18 (Reference-Only)**: 부모 D3가 Cloudflare 경로를 선택하면 **named tunnel + Cloudflare 관리 custom hostname**을 stable Google callback으로 사용한다. `trycloudflare.com` quick tunnel과 ngrok random hostname은 dev-only이며 URL이 바뀌면 Google Console 값을 함께 갱신한다. - **2026-05-25**: 운영 환경 옵션 **EC2 + Route53 + ACM + ALB**. 본 sub-sub-branch에서는 비교 대상으로만 기재, 실 구성은 P3B 전체가 `documented-only`이므로 진행 안 함. - **2026-05-25**: 본 sub-sub-branch 전체 등급 `documented-only`. P3B 부모 결정(문서까지만)에 종속. 실 tunnel 구동 / 도메인 매핑은 P3A 완료 후 선택적 확장 시점에 재검토. ## 결정-근거 매핑 > 각 결정이 어떤 raw source claim 으로 뒷받침되는지 명시. `Decision ID` 는 본 branch-note 안에서 안정적으로 유지. > `선택 조건` 열(R2): "이 조건일 때 이 결정, 다른 조건이면 어떤 대안". 분기 없으면 `N/A`. | Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk | |---|---|---|---|---|---| | D1 | **Cloudflare 운영 profile(부모 D3 소비)** — stable Google callback이 필요하면 named tunnel을 Cloudflare가 관리하는 custom hostname(예: `kc.example.com`)에 연결한다. quick tunnel random URL은 이 profile에 포함하지 않는다. | 부모 [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]] D3가 Cloudflare를 선택하고, 관리 도메인을 확보할 수 있을 때. provider 선택 자체는 본 문서가 재정의하지 않는다. | `raw/official-docs/cloudflare-tunnel-routing-official.md#CLOUDFLARE-TUNNEL-C1` (cloudflared outbound), `raw/official-docs/cloudflare-tunnel-routing-official.md#CLOUDFLARE-TUNNEL-C2` (firewall inbound 차단 권장), `raw/official-docs/cloudflare-tunnel-routing-official.md#CLOUDFLARE-TUNNEL-C3` (tunnel `.cfargotunnel.com` subdomain 자동 부여), `raw/official-docs/cloudflare-tunnel-routing-official.md#CLOUDFLARE-TUNNEL-C4` (사용자 hostname CNAME → cfargotunnel.com), `raw/official-docs/google-oauth2-redirect-uri-validation-official.md#GOOGLE-REDIR-C2` (Google redirect URI raw IP 금지 → 도메인 필요) | `official-vendor-doc + official-vendor-doc` | managed custom hostname의 Google 등록과 실제 callback 성공은 P3B 실측 필요. `.cfargotunnel.com`이나 `trycloudflare.com` URL을 stable callback으로 간주하지 않는다. | | D2 | **ngrok 임시 운영 profile(부모 D3 fallback 소비)** — random URL은 dev-only이며 Google Console redirect_uri 갱신을 동반한다. | 부모 D3가 1회성 데모 fallback을 선택한 경우. 반복 사용·stable callback이면 부모 D3의 Cloudflare named tunnel profile로 돌아간다. | `raw/official-docs/ngrok-http-tunnel-official.md#NGROK-C1` (`ngrok http ` 가 random HTTPS hostname 생성), `raw/official-docs/ngrok-http-tunnel-official.md#NGROK-C3` (random hostname 은 기존 Domain object 와 매칭 안 됨), `raw/official-docs/ngrok-http-tunnel-official.md#NGROK-C4` (고정 URL에는 별도 Domain record + DNS CNAME 필요), `raw/official-docs/google-oauth2-redirect-uri-validation-official.md#GOOGLE-REDIR-C3` (exact match) | `official-vendor-doc + official-vendor-doc` | free plan에서 재시작마다 hostname이 바뀌는지는 `NGROK-C1` 인용에 직접 명시되지 않아 별도 확인 필요 | | D3 | 운영 환경 옵션 **EC2 + Route53 + ACM + ALB** — 비교 대상으로만 기재 | 운영(production) 환경이거나 tunnel 의존을 제거해야 할 때. 학습 환경이면 → **D1/D2**. **본 branch 범위 밖**(§범위 Out of scope: 운영 ACM/ALB 구성 제외 + 부모 note 의 "대안 3"과 동일 tree 관행: AWS 경로 = 명명된 비교 대안, 전용 raw 미첨부) — 비교 축으로만 존재 | UNSUPPORTED_DECISION / OUT_OF_BRANCH_SCOPE (AWS Route53 / ACM / ALB 공식 raw 미수집 — 본 branch 의 Sources 인용 범위 밖이자 운영 구성 결정은 별도 branch 영역) | `UNSUPPORTED_DECISION` | 실 채택 시점에 AWS 공식 raw 인용 보강 필요 (예: ACM cert 자동 갱신 정책) | | D4 | 본 sub-sub-branch 전체 등급 `documented-only` (P3B 부모 결정 종속, 실 tunnel 구동 보류) | P3A 완료 전 학습·문서 단계인 동안 적용. P3A 완료 후 선택적 확장 시점이면 → 실 tunnel 구동 / 도메인 매핑 재검토 (N/A — project scope 결정) | UNSUPPORTED_DECISION (project scope 결정 — 부모 branch P3B 의 `documented-only` 정책에 종속, 외부 raw 인용 불필요) | `UNSUPPORTED_DECISION` | scope 결정 자체는 외부 raw 가 root 가 아님 | ## 구현 가이드 > 본 branch 는 `documented-only` — 실 코드/구동 없음. 따라서 본 §는 "다음 P3B 확장 작업자가 되묻지 않고 각 옵션을 셋업할 수 있는 수준"의 사전 명세 (등급은 전부 `planned`/`documented-only`). 각 sub-section 은 본 branch 의 `Decision ID` + `Supporting Claim ID` 에서 도출된 것만 기재한다. > > **범위 경계**: Keycloak `KC_HOSTNAME` / `KC_PROXY_HEADERS` / relative-path / TLS 종단 config 는 본 branch 결정 영역 밖(sibling `feature-keycloak-reverse-proxy-headers` / `feature-keycloak-https-termination-caddy-nginx` 소유) → 여기 재진술하지 않고 §엣지·실패·의존 에 의존 링크로만 둔다 (R3 OUT_OF_BRANCH_SCOPE). ### 1. Cloudflare Tunnel (D1) — 부모 D3 선택을 실행하는 named tunnel 셋업 절차 > **Trace**: D1 + `CLOUDFLARE-TUNNEL-C1`(outbound-only) / `C2`(inbound 차단 권장) / `C3`(`.cfargotunnel.com` 자동 부여) / `C4`(사용자 hostname CNAME → cfargotunnel.com) / `C5`(`cloudflared tunnel route dns`, running 아니면 트래픽 없음). > > - **UNSUPPORTED_IMPL_DECISION**: (1) tunnel/도메인 명명(`kc.example.com`, ``)은 예시값 — 사용자가 소유·위임한 Cloudflare 관리 도메인에 종속하며 raw 근거 없음(trade-off: 구체 도메인은 실 확장 시점 확정). (2) step 4 ingress `config.yml` 문법(`ingress:` 블록 / `service:` 매핑)은 `CLOUDFLARE-TUNNEL-C1`(outbound-only)이 증명하지 않는 미근거 detail(trade-off: ingress 규칙 공식 페이지 미수집 — 실 셋업 시 Cloudflare Tunnel `config.yml` 문서 참조). documented-only 이므로 둘 다 실 확장 시점 확정. | 단계 | 명령 / 설정 | 근거 | 결과 | |---|---|---|---| | 1. 전제·인증 | Cloudflare account + Cloudflare DNS 로 위임한 도메인 1개 → `cloudflared tunnel login` (브라우저 인증 → `cert.pem`) | (계정 전제 — raw 밖) | named tunnel + 사용자 CNAME 가능 조건 | | 2. tunnel 생성 | `cloudflared tunnel create ` | `CLOUDFLARE-TUNNEL-C3` | tunnel UUID + `.cfargotunnel.com` 자동 부여 | | 3. DNS 라우팅 | `cloudflared tunnel route dns kc.example.com` | `CLOUDFLARE-TUNNEL-C4`, `C5` | 사용자 hostname → cfargotunnel.com CNAME 생성 (단 tunnel running 전엔 트래픽 없음) | | 4. ingress | `config.yml` 의 `ingress:` 블록에 `kc.example.com` → `service: http://localhost:8080`(Keycloak) 매핑 | `CLOUDFLARE-TUNNEL-C1`(outbound-only) + **UNSUPPORTED_IMPL_DECISION**(ingress 문법 미근거) | origin→Cloudflare outbound, ingress 규칙으로 Keycloak 라우팅 | | 5. 구동 | `cloudflared tunnel run ` | `CLOUDFLARE-TUNNEL-C1`, `C2` | EC2 SG inbound 0 개로 public HTTPS 노출, TLS 는 Cloudflare edge 종단 | ### 2. ngrok (D2) — quick tunnel 셋업 절차 > **Trace**: D2 + `NGROK-C1`(`ngrok http ` random HTTPS hostname) / `C3`(random hostname = Domain object 미매칭) / `C4`(bring-your-own-domain 절차) + `GOOGLE-REDIR-C3`(exact match → URL 변경 시 재등록). > > - **UNSUPPORTED_IMPL_DECISION**: "재시작마다 hostname 변경" 은 `NGROK-C1` 인용 범위 밖(관행) → §검증해야 할 주장으로 이관해 별도 확인(trade-off: free plan 정책 페이지 미수집 상태에서 단정 금지). | 단계 | 명령 / 설정 | 근거 | 결과 | |---|---|---|---| | 0. 전제 | 계정 가입 후 `ngrok config add-authtoken ` (authtoken 등록) | (계정 전제 — raw 밖) | ngrok agent 인증 완료 | | 1. 임시 URL | `ngrok http 8080` | `NGROK-C1`, `C2`(scheme https default) | `https://.ngrok.app` 발급 | | 2. URL 변동성 | (재시작) | `NGROK-C3` | random hostname → reserved Domain 미매칭 → 세션마다 URL 변경 가능 → Google Console redirect_uri 재등록(`GOOGLE-REDIR-C3`) | | 3. 고정 URL(선택) | Domain record 생성 + DNS CNAME + matching hostname 으로 endpoint 생성 | `NGROK-C4` | 고정 URL 확보(단 free plan 가부는 미확인 — §검증) | ### 3. Google Cloud Console redirect URI 등록 제약 (D1·D2 공통) > **Trace**: `GOOGLE-REDIR-C2`(host = raw IP 금지, localhost 예외) + `GOOGLE-REDIR-C3`(등록값과 byte-level exact match, 불일치 시 `redirect_uri_mismatch`). > > - **OUT_OF_BRANCH_SCOPE**: 등록할 broker endpoint URL 의 정확한 형식(`/realms/{realm}/broker/google/endpoint` + `KC_HTTP_RELATIVE_PATH` 결합)은 sibling `feature-keycloak-reverse-proxy-headers` / `feature-keycloak-google-redirect-uri-policy` 소유 → 링크만, 재진술 금지. - 등록 host 는 **도메인 필수**(raw IP 금지, `GOOGLE-REDIR-C2`) → D1/D2 의 public URL 이 이 제약을 만족시키는 이유. - 등록값은 실제 요청 redirect_uri 와 **정확히 일치**(`GOOGLE-REDIR-C3`) → D2(ngrok random URL) 의 갱신 burden 이 여기서 발생. - stable callback은 `.cfargotunnel.com` 또는 `trycloudflare.com` 주소가 아니라 Cloudflare가 관리하는 custom hostname을 사용한다. 그 hostname의 Google 등록 성공은 §검증해야 할 주장으로 남긴다. ## 엣지·실패·의존 > 정상 경로(public URL 확보 → Google redirect 통과) 외에 실 확장 시 부딪힐 실패/엣지와 다른 branch 계약 의존을 미리 열거. - **실패·엣지 경로**: - **ngrok URL drift** — free plan 재시작 시 hostname 변경 가능 → 등록 redirect_uri 와 불일치 → `redirect_uri_mismatch`(`GOOGLE-REDIR-C3`). 기대 동작: dev-only로 제한하고 URL 변경 시 Console 갱신, stable callback은 부모 D3가 고른 D1 profile 사용. - **Cloudflare 라우팅 ≠ 가용** — `cloudflared` 미실행 시 CNAME 은 있어도 트래픽 안 흐름(`CLOUDFLARE-TUNNEL-C5`). 기대: `cloudflared tunnel run` 데몬 상시 실행(systemd 등). - **CNAME 전파 지연** — `cloudflared tunnel route dns` 직후 DNS 전파 지연(수초~수분)으로 등록 URL 이 일시 미해석 → Google redirect 일시 실패 가능. 기대: `dig ` 로 전파 확인 후 Google 등록/로그인 시도. - **cfargotunnel 도메인 정책 미검증** — Google 이 `.cfargotunnel.com` generic subdomain 을 거부할 가능성(`GOOGLE-REDIR-C2` 는 raw IP 만 금지, generic subdomain 은 미보증). 기대: 거부 시 사용자 소유 도메인 CNAME 으로 우회(`CLOUDFLARE-TUNNEL-C4`). → §검증. - **outbound 443 차단 환경** — 방화벽이 outbound 를 막으면 cloudflared 미동작(`CLOUDFLARE-TUNNEL-C1` "Does not prove" 단서). 기대: egress 443 허용 확인. - **quick tunnel 혼동** — `trycloudflare.com` quick tunnel 은 random URL(ngrok 유사). 정적 도메인이 목표면 named tunnel + 계정 도메인 필요(진행 중 메모). - **다른 계약 의존**: - [[raw/branch-notes/feature-keycloak-reverse-proxy-headers]] `D7`(`KC_HOSTNAME=https://kc.example.com`) + `D1`(`KC_PROXY_HEADERS=xforwarded`) + `D6`(`KC_HTTP_ENABLED=true` + `KC_PROXY_TRUSTED_ADDRESSES`) — 본 branch 가 고른 public host 를 그 branch 가 Keycloak issuer 로 주입. 그 계약(hostname 형식 / `D3` relative path `/keycloak`)이 바뀌면 본 branch 의 redirect URI 등록값도 영향. - [[raw/branch-notes/feature-keycloak-google-redirect-uri-policy]] `D1`(broker endpoint URL 을 Authorized redirect URIs 에 등록) + `D8`(ngrok 운영 burden → Cloudflare 정적 도메인 채택 정당화) — 본 branch D2(ngrok URL 변경 burden)가 그 branch 의 갱신 운영(`D8`)과 결합. - [[raw/branch-notes/feature-keycloak-https-termination-caddy-nginx]] `D1`(Cloudflare edge TLS 종단) — 본 branch D1(Cloudflare Tunnel)과 짝: edge 종단이므로 EC2 내부는 HTTP forward. 본 branch D3(EC2 직결)로 가면 그 branch `D2`(Caddy) / `D3`(nginx) + Let's Encrypt 가 TLS 담당. - 부모 [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]] D3가 provider 우선순위와 채택 조건의 owner다. 본 sub-sub-branch D1/D2는 선택된 provider의 운영 profile만 제공하는 Reference-Only 문서다. ## 검증해야 할 주장 > 공식 문서나 사례는 근거지만, 내 프로젝트에서의 동작을 자동으로 보장하지 않는다. | Claim | Why uncertain | How to verify | Status | |---|---|---|---| | Cloudflare named tunnel에 연결한 managed custom hostname(예: `kc.example.com`)이 Google Cloud Console authorized redirect URI 등록과 실제 callback에 통과 | `GOOGLE-REDIR-C2`는 raw IP 금지만 보증하고, Cloudflare DNS·TLS·tunnel 조합의 종단 동작을 직접 보증하지 않음 | P3B에서 managed custom hostname을 등록하고 실제 broker login을 수행해 exact match와 callback 성공 확인 | `needs-confirmation` | | ngrok free plan 에서 재시작 시마다 hostname 이 변경 | `NGROK-C1` 은 random hostname 만 보증, 재시작 시 변경 정책은 본 raw 인용에 직접 없음 | ngrok pricing/free plan 페이지를 `raw/official-docs/` 로 등록 → free plan 의 reserved domain 정책 verbatim 확보 | `planned` | | Cloudflare Tunnel `trycloudflare.com` quick tunnel 이 무료 + URL random | 본 branch 의 진행 중 메모만 — `cloudflare-tunnel-routing-official` 인용에 직접 없음 | Cloudflare quick tunnel 공식 페이지 발췌 후 `raw/official-docs/` 등록 | `planned` | | Keycloak `KC_HOSTNAME=` 설정 시 issuer `iss` 가 정확히 `https:///realms/{realm}` 형식으로 발급 | Keycloak hostname 동작은 별도 raw (`keycloak-hostname-configuration`) 필요 | P3B 시연 시 token 발급 후 jwt.io 로 `iss` 디코딩 → backend `issuer-uri` 와 byte-level 비교 | `needs-confirmation` | ## 마주친 문제 - 아직 없음 (문서 단계). ## 관련 sub-branch - [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]] (부모, P3B Single EC2 + Google federation) - [[raw/branch-notes/feature-keycloak-reverse-proxy-headers]] — Keycloak reverse proxy 설정 (KC_PROXY_HEADERS + KC_HOSTNAME) - [[raw/branch-notes/feature-keycloak-google-redirect-uri-policy]] — Google OAuth client 등록 + ngrok URL 변경 시 갱신 - [[raw/branch-notes/feature-keycloak-https-termination-caddy-nginx]] — HTTPS termination (Caddy vs nginx + Let's Encrypt) ## 묶음 - [[raw/official-docs/google-oauth2-redirect-uri-validation-official]] - [[raw/official-docs/ngrok-http-tunnel-official]] > 본 branch 는 leaf — 자식 자료 없음. errors / interview prep / lectures 가 누적되면 본 섹션에서 그룹화. ### 오류 기록 - (없음) ### 면접 준비 - (없음) ## 관련 일일 노트 ## 완료 후 정리 > 본 sub-sub-branch는 **문서까지만**. 실 tunnel 구동 / 도메인 매핑 / Google Console 등록 흐름은 P3A 완료 후 선택적 확장. - PR 링크: - 리뷰 메모: - 머지 결과 / 배포 환경: 해당 없음 (문서 단계, P3B 전체 `documented-only`) - **wiki 추출 대상** (verified만, `wiki/projects/`로만 추출): - `actually-implemented` 항목: 없음 - `locally-verified` 항목: 없음 - `prod-verified` 항목: 없음 - **추출하지 않을 항목** (planned / documented-only / abandoned): - 본 sub-sub-branch 전체가 `documented-only`. 추후 부모 P3B의 6 패턴 비교 매트릭스 내 "public 도메인 확보 비교표"로만 인용.