fix: 하네스 제거 및 keycloak 문서 보강

This commit is contained in:
DongHyeonka
2026-07-25 12:53:13 +09:00
parent 6c53ded9cb
commit d71669eb59
2329 changed files with 138239 additions and 172816 deletions
@@ -1 +0,0 @@
../../vault/10-projects/keycloak-patterns-overview/branch-notes/feature-keycloak-https-termination-caddy-nginx.md
@@ -0,0 +1,333 @@
---
title: branch / feature-keycloak-https-termination-caddy-nginx (P3B HTTPS termination — Caddy vs nginx + Let's Encrypt)
source_type: branch-note
status: raw
id: BR-KEYCLOAK-CHILD-A34AB4E8
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-https-termination-caddy-nginx
parent_branch: feature-keycloak-patterns
related_projects: [keycloak-patterns]
tags: [branch, keycloak-patterns, p3b, https, tls, caddy, nginx, letsencrypt, acme]
created: 2026-05-25
target_merge:
status_label: in-progress
contract_packet_sha256: 3cb0c15cd9eed9060bbf609a1eceb775ab560d7bdafc292900454af3c43aac1c
---
# branch: feature-keycloak-https-termination-caddy-nginx (P3B HTTPS termination — Caddy vs nginx + Let's Encrypt)
> Layer: `raw/branch-notes/` — [[raw/branch-notes/feature-keycloak-patterns]]의 WI020 child branch. **HTTPS termination 위치와 cert 자동화 옵션 비교**. Cloudflare Tunnel은 edge TLS 자동, EC2 public IP는 Caddy 또는 nginx + certbot 필요.
> 본 sub-sub-branch는 **문서까지만** — 실 Caddy / nginx 설치 / cert 발급 / cron 등록은 진행하지 않음. 등급 `documented-only`.
> `status_label`: `in-progress`
<!-- section-id: branch-parent -->
## 부모 (필수)
[[raw/branch-notes/feature-keycloak-patterns]]
<!-- GENERATED: branch-contract:start -->
<!-- section-id: branch-contract-packet -->
## 브랜치 계약 패킷
- **생성 시 프로젝트 개정**: `1`
- **패킷 스키마**: `contract_packet: 1`
- **완료 조건**: project governance hub가 AP1~AP4 taxonomy와 child progress index를 유지한다
<!-- section-id: inherited-project-decisions -->
### 상속한 프로젝트 결정
| Decision Ref | Project Summary | Branch Application | Source |
|---|---|---|---|
| `DEC-KEYCLOAK-PATTERNS-OVERVIEW-AUTH-TAXONOMY-001@1` | canonical 분류축은 AP1~AP4 인증 통합 아키텍처와 cross-cutting 변형이다 | HTTPS termination을 인증 패턴 공통의 deployment cross-cutting 변형으로 분류한다 | [[raw/project-notes/keycloak-patterns-overview]] |
<!-- section-id: branch-local-decisions -->
### 브랜치 지역 결정
> 기존 branch-local 결정은 아래 `## Decision Evidence Map`의 D-row가 소유하며 이 packet에서 복제하지 않는다.
| Decision ID | Decision | Relation | Supporting Claims | Status |
|---|---|---|---|---|
<!-- section-id: declared-overrides -->
### 선언한 예외
| Override ID | Overrides | Reason | Approval | Status |
|---|---|---|---|---|
없음.
<!-- GENERATED: branch-contract:end -->
<!-- section-id: branch-goal -->
## 목표
Google OAuth가 redirect_uri로 HTTPS를 강제(`-6-3` 참조)하므로 P3B는 어떤 식으로든 HTTPS가 필수. 단일 EC2 학습 환경에서 다음 4개 옵션의 trade-off를 정리:
1. **Caddy** — 1줄 config로 Let's Encrypt 자동 (ACME-TLS-ALPN-01 / HTTP-01)
2. **nginx + certbot** — 직접 cert 발급 + cron으로 renew
3. **Cloudflare Tunnel** — origin은 HTTP, edge가 TLS 종단 (edge-managed certificate)
4. **EC2 + ALB + ACM** — production-like, AWS managed cert
이 결정이 운영 비용(cert renew burden, 만료 사고) + 학습 friction(설치 복잡도)를 좌우.
면접에서 답해야 할 질문:
1. Caddy를 학습용으로 왜 우선 골랐나? → 짧은 config와 자동 ACME로 수동 발급·갱신 부담을 줄이기 때문이다.
2. nginx + certbot vs Caddy의 차이는? → nginx는 명시적 (server block + ssl_certificate path), certbot이 별도 binary로 cert 발급/갱신. Caddy는 통합.
3. HSTS / TLS 1.2+ enforce 어디서? → reverse proxy 레이어. Caddy는 Automatic HTTPS로 HTTP→HTTPS redirect를 제공하지만 **HSTS는 `header` directive로 명시**해야 한다. nginx도 명시 설정한다.
- 이슈:
- PR:
<!-- section-id: branch-scope -->
## 범위
### 포함 범위
- Caddy `auto_https on` (디폴트) + 1줄 config로 Let's Encrypt 발급
- nginx + certbot (또는 acme.sh) CLI 흐름, cron / systemd timer 등록
- Cloudflare Tunnel edge TLS (origin HTTP, edge HTTPS) 흐름
- EC2 + ALB + ACM (production-like 대안) — 비교만
- cert 갱신 자동화 (certbot.timer / cron / Caddy 내장 / Cloudflare 자동)
- TLS 1.2+ enforce 설정 위치
- HSTS 헤더 (`Strict-Transport-Security`) 설정 위치
### 제외 범위
- 실 cert 발급 (도메인 소유 검증 필요 → P3A 완료 후 선택적 확장)
- mTLS / client cert auth
- TLS 1.3 0-RTT
- HPKP (deprecated)
- HAProxy / Traefik 옵션
## 근거 (필수, 최소 1개+)
- (외부 근거는 부모 P3B의 외부 자료 inventory 공유 — 본 sub-sub-branch는 학습 환경 옵션 비교 + 결정 근거에 집중)
- [[raw/official-docs/cloudflare-tunnel-routing-official]] — Cloudflare Tunnel edge TLS 동작 (sub-sub-branch `-6-1`과 공유) — **D1** 근거
- [[raw/official-docs/caddy-automatic-https-docs]] — Caddy Automatic HTTPS 공식 (`official-vendor-doc`) — **D2** 근거 (auto-HTTPS + Let's Encrypt/ZeroSSL + HTTP→HTTPS redirect + background renewal). HSTS default 는 본 raw 로 입증 안 됨 (`CADDY-AHTTPS-C11`)
- [[raw/official-docs/certbot-user-guide]] — EFF Certbot User Guide (`official-vendor-doc`) — **D3** 근거 (subcommand + automated renewal scheduled task + `--nginx` plugin + `--deploy-hook`)
- [[raw/official-docs/aws-acm-managed-renewal]] — AWS ACM Managed Renewal 공식 (`official-vendor-doc`) — **D4** 근거 (DNS-validated cert fully automated renewal + ARN 유지 + ELB/CloudFront attach 자격 + EventBridge alert)
- [[raw/official-docs/rfc8996-tls10-tls11-deprecation]] — RFC 8996 (`official-standard`, IETF Standards Track) — **D5** TLS 1.0/1.1 MUST NOT 근거
- [[raw/official-docs/owasp-hsts-cheat-sheet]] — OWASP HSTS Cheat Sheet (`official-reference`, 표준 아님) — **D5** HSTS 권장 헤더 + preload 경고 근거
## 관련 sub-branch
- [[raw/branch-notes/feature-keycloak-single-ec2-google-federation]] (부모, P3B Single EC2 + Google federation)
- [[raw/branch-notes/feature-keycloak-public-domain-tunneling]] — 학습 환경 public 도메인 확보 **← Cloudflare Tunnel 결정과 결합**
- [[raw/branch-notes/feature-keycloak-reverse-proxy-headers]] — Keycloak reverse proxy 설정 **← Caddy / nginx config의 reverse proxy 측면**
- [[raw/branch-notes/feature-keycloak-google-redirect-uri-policy]] — Google OAuth client 등록 (HTTPS redirect_uri 강제 근거)
## TODO
각 항목 옆에 증거 등급 표기.
- [ ] **Caddy 설치 + 1줄 config 정리**`apt install caddy` 또는 docker image, `Caddyfile``kc.example.com { reverse_proxy localhost:8080 }` 1줄 → `auto_https on` 디폴트로 Let's Encrypt 자동 발급 — 등급: `planned`
- [ ] **nginx + certbot 흐름 정리**`apt install nginx certbot python3-certbot-nginx``certbot --nginx -d kc.example.com` → server block에 `ssl_certificate` 자동 삽입 → `certbot renew --dry-run` 검증 → `systemctl enable certbot.timer` — 등급: `planned`
- [ ] **acme.sh 대안 비교** — certbot 대비 shell-only / 더 가벼움 / 다양한 DNS provider 지원 — 등급: `documented-only`
- [ ] **Cloudflare Tunnel edge TLS 흐름** — origin은 `http://localhost:8080`, edge certificate는 공급자가 관리 → 학습용 1순위 — 등급: `planned`
- [ ] **EC2 + ALB + ACM (production-like)** — Route53 hosted zone + ALB + ACM cert + Target Group → EC2:80. ACM 자동 갱신. 학습 비용 ↑ — 등급: `documented-only`
- [ ] **cert 갱신 자동화 비교표** — certbot.timer / cron `0 3 * * * certbot renew --quiet` / Caddy background 갱신(정확 시점은 issuer 정책 의존) / Cloudflare edge 관리 / ACM managed renewal — 등급: `planned`
- [ ] **TLS 1.2+ enforce 정책** — Caddy 디폴트로 TLS 1.2 minimum, nginx는 `ssl_protocols TLSv1.2 TLSv1.3;` 명시 — 등급: `planned`
- [ ] **HSTS 헤더 정책**`Strict-Transport-Security: max-age=31536000; includeSubDomains`. Caddy는 `header` directive, nginx는 `add_header`, Cloudflare는 dashboard에서 각각 **명시** — 등급: `planned`
## 진행 중 메모
- Caddy Automatic HTTPS 동작: HTTP(80) 요청을 HTTPS로 redirect하고 ACME 인증서 발급·background 갱신을 수행한다. HSTS는 이 기능의 default가 아니며 별도 `header` 설정이 필요하다. 정확한 갱신 시점 수치는 issuer 정책에 의존한다.
- certbot --nginx plugin은 nginx config 자동 수정. 수동 관리하려면 `--webroot` 또는 `--standalone`.
- Let's Encrypt rate limit: 도메인당 주 50회 cert 발급. 학습 중 반복 실수 주의.
- Cloudflare Tunnel origin이 HTTP라도 edge ↔ Cloudflare ↔ origin 구간은 Cloudflare 사설 네트워크. 클라이언트 ↔ edge는 HTTPS. origin port 0 open 가능 (egress only).
- ALB + ACM은 cert 자동 갱신 + AWS-native, 비용은 ALB $20~/월 + 트래픽. 학습 환경에 과함.
### 옵션 비교표 초안
| 항목 | Caddy | nginx + certbot | Cloudflare Tunnel | EC2 + ALB + ACM |
|------|-------|-----------------|-------------------|------------------|
| 설정 복잡도 | 1줄 | server block + certbot CLI | tunnel config (yml) | Terraform / 콘솔 |
| cert 발급 | 자동 (Let's Encrypt) | 수동 1회 (certbot) | 자동 (Cloudflare) | 자동 (ACM) |
| cert 갱신 | 자동 (내장) | `certbot.timer` (자동) | 자동 (Cloudflare) | 자동 (ACM) |
| 만료 사고 위험 | 낮음 | 중 (cron 실패 시) | 낮음(공급자 관리) | 낮음(조건 충족 시 managed renewal) |
| TLS 1.2+ enforce | 디폴트 | 명시 (`ssl_protocols`) | dashboard | ALB Security Policy |
| HSTS | `header` 명시 (default 아님 — `CADDY-AHTTPS-C11`) | `add_header` 명시 | dashboard | ALB / WAF |
| 비용 | 무료 | 무료 | 무료 (Cloudflare account) | ALB ~$20/월 + 트래픽 |
| 학습 환경 적합도 | 높음 | 중 | 매우 높음 (edge-managed certificate) | 낮음 (과함) |
| 운영 환경 적합도 | 중~높음 | 높음 (전통) | 중 (vendor 의존) | 매우 높음 (AWS-native) |
## 결정 사항 (decisions)
- **2026-05-25**: 학습 환경 1순위 **Cloudflare Tunnel** (edge TLS). 이유: certificate lifecycle을 edge 공급자가 관리해 학습자의 수동 발급·갱신 부담이 작다. 갱신 실패가 없다는 보장은 하지 않는다. sub-sub-branch `-6-1` Cloudflare Tunnel 결정과 자연스럽게 연결.
- **2026-05-25**: 학습 환경 2순위 **Caddy** (EC2 public IP를 직접 노출하는 시나리오). 이유: 1줄 config + auto_https + Let's Encrypt 내장. (주의: **HSTS 는 Caddy default 아님**`header` directive 명시 필요. `CADDY-AHTTPS-C11` 이 공식 페이지에 HSTS 언급 부재를 근거로 기록. 초기 메모의 "HSTS 디폴트"는 반증됨.)
- **2026-05-25**: nginx + certbot은 비교 대상으로만. 이유: 전통적 운영 환경에서는 표준이나 학습 friction이 Caddy 대비 높음 (cron renew 실패 사고).
- **2026-05-25**: EC2 + ALB + ACM은 운영 환경 대안으로만 기재. 본 P3B 범위는 단일 EC2 학습 → ALB / multi-AZ는 과함.
- **2026-05-25**: TLS 1.2+ enforce + HSTS는 어떤 옵션을 선택하든 강제. 학습이라도 보안 디폴트 leak 안 함.
- **2026-05-25**: 본 sub-sub-branch 전체 등급 `documented-only`. 실 cert 발급 / Caddy 또는 nginx 구동은 P3A 완료 후 선택적 확장 시점에 재검토.
## 결정-근거 매핑
> 각 결정이 어떤 raw source claim 으로 뒷받침되는지 명시. `Decision ID` 는 본 branch-note 안에서 안정적으로 유지.
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|---|
| D1 | 학습 환경 1순위 **Cloudflare Tunnel** (edge TLS) — certificate lifecycle을 공급자가 관리 | 수동 cert 발급·갱신 부담을 줄이고 public 도메인을 Cloudflare 로 확보할 때 이 결정. 갱신 실패가 없다는 보장은 하지 않는다. EC2 public IP 를 직접 노출해야 하면 → D2(Caddy) | `raw/official-docs/cloudflare-tunnel-routing-official.md#CLOUDFLARE-TUNNEL-C1` (cloudflared outbound-only), `raw/official-docs/cloudflare-tunnel-routing-official.md#CLOUDFLARE-TUNNEL-C2` (firewall inbound 차단 권장), `raw/official-docs/cloudflare-tunnel-routing-official.md#CLOUDFLARE-TUNNEL-C5` (locally-managed tunnel DNS routing 명령) | `official-vendor-doc` | TLS 가 Cloudflare edge ↔ origin 구간에서 어떻게 종단되는지 (origin HTTP) 의 정확한 header 동작과 certificate 갱신 조건은 본 raw 인용으로 직접 보증 안 됨 — 로컬 검증 및 별도 SSL/TLS 공식 문서 필요 (`feature-keycloak-reverse-proxy-headers` 의 X-Forwarded-* 와 결합) |
| D2 | 학습 환경 2순위 **Caddy** (1줄 config + auto_https + Let's Encrypt 내장; HSTS 는 `header` directive 명시 필요 — default 아님, `CADDY-AHTTPS-C11`) | EC2 public IP 를 직접 노출(Cloudflare 미사용)하고 1줄 config 로 cert 자동화를 원할 때. 전통 nginx 스택 표준화가 목표면 → D3 | `raw/official-docs/caddy-automatic-https-docs.md#CADDY-AHTTPS-C1` (TLS cert 자동 발급 + 자동 갱신 — "Automatic HTTPS provisions TLS certificates for all your sites and keeps them renewed"), `#CADDY-AHTTPS-C2` (default 로 모든 site 를 HTTPS 로 serve), `#CADDY-AHTTPS-C3` (public ACME CA — Let's Encrypt 또는 ZeroSSL), `#CADDY-AHTTPS-C4` (HTTP → HTTPS redirect + managed cert 자동 갱신 default), `#CADDY-AHTTPS-C5` (renewal background 수행, subdomain 은 명시 설정 필요), `#CADDY-AHTTPS-C6` (hostname 인식 시 implicit 활성화) | `official-vendor-doc` | **"HSTS 디폴트" 주장은 본 raw 로 입증 불가** — `CADDY-AHTTPS-C11` 은 본 페이지에 HSTS 직접 언급 없음을 명시적 부재 사실로 기록. D2 의 HSTS 부분은 별도 출처 (Caddy `tls` / `header` directive 페이지) 보강 필요. 또한 `CADDY-AHTTPS-C5` 는 renewal background 만 보증, "만료 30일 전" 같은 정확 timing 은 별도 ACME issuer 정책 의존 |
| D3 | nginx + certbot 은 비교 대상으로만 (학습 friction, cron renew 실패 사고 위험) | 기존 nginx 운영 표준에 편입해야 할 때만. 학습·저마찰이 목표면 → D2(Caddy). 본 branch 에서는 비교 baseline 으로만 | `raw/official-docs/certbot-user-guide.md#CERTBOT-UG-C1` (subcommand 체계 — obtain/renew/revoke), `#CERTBOT-UG-C2` (대부분 installation 은 automated renewal preconfigured — `certbot renew` scheduled task), `#CERTBOT-UG-C3` (scheduled task 구체 구현은 OS/installer 의존), `#CERTBOT-UG-C4` (Nginx plugin — "should work for most configurations", `--nginx rollback` 지원), `#CERTBOT-UG-C5` (Certbot 4.0.0 부터 renewal 임계 = lifetime 의 1/3 미만), `#CERTBOT-UG-C6` (`--pre-hook` / `--post-hook` / `--deploy-hook` 지원) | `official-vendor-doc` | "cron renew 실패 사고 위험" 의 정량적 비교는 본 raw 로 직접 보증되지 않음 — `CERTBOT-UG-C3` 가 "OS / installer 의존" 만 진술. 실제 systemd timer vs cron 의 신뢰성 비교는 운영 사례 / wiki 합성 단계에서 별도 분석 필요 |
| D4 | EC2 + ALB + ACM 은 운영 환경 대안으로만 기재 (단일 EC2 학습 범위 초과) | multi-AZ / production-grade managed cert 가 요구될 때. 단일 EC2 학습 범위면 → D1/D2. 본 branch 에서는 운영 대안 기재만 | `raw/official-docs/aws-acm-managed-renewal.md#AWS-ACM-RENEW-C1` (Amazon-issued cert 의 managed renewal — DNS validation 시 자동), `#AWS-ACM-RENEW-C2` (public + private cert 모두 적용), `#AWS-ACM-RENEW-C3` (ELB / CloudFront 등 AWS service attach 시 자동 갱신 ELIGIBLE), `#AWS-ACM-RENEW-C8` (갱신 시 ARN 유지 → listener config 무수정), `#AWS-ACM-RENEW-C9` (regional resource — multi-region 독립 갱신), `#AWS-ACM-RENEW-C11` (DNS validation cert 의 fully automated renewal), `#AWS-ACM-RENEW-C12` (만료 45일 전 갱신 시도, legacy 395-day cert 의 경우 60일 전), `#AWS-ACM-RENEW-C13` (갱신 사전 조건: AWS service 사용 중 + CNAME public DNS 존재), `#AWS-ACM-RENEW-C14` (실패 시 EventBridge alert 30/15/7/3/1일 전) | `official-vendor-doc` | **ALB Security Policy (TLS 1.2 enforce)** 는 본 raw 로 입증 불가 — ACM 은 cert 발급/갱신만 진술, listener TLS policy 는 ELB 측 별도 문서. "ACM cert renew 실패 사고 0" 도 본 raw 가 직접 보증하지 않음 (`C14` 는 alert schedule 만 진술) — Route53 CNAME 영구 유지 + AWS service attach 가 동시 충족되어야 함 (`C13`) |
| D5 | TLS 1.2+ enforce + HSTS 는 어떤 옵션을 선택하든 강제 (학습이라도 보안 디폴트 leak 안 함) | N/A — D1~D4 어느 옵션을 선택하든 무조건 강제 (분기 없음) | TLS 1.0/1.1 deprecation: `raw/official-docs/rfc8996-tls10-tls11-deprecation.md#RFC8996-C1` (TLS 1.0/1.1 formally deprecated → Historic), `#RFC8996-C4` ("TLS 1.0 MUST NOT be used"), `#RFC8996-C5` ("TLS 1.1 MUST NOT be used"), `#RFC8996-C6` (BCP 195 의 SHOULD NOT → MUST NOT 강화). HSTS: `raw/official-docs/owasp-hsts-cheat-sheet.md#OWASP-HSTS-C1` (HSTS 는 opt-in response header), `#OWASP-HSTS-C2` (활성 시 HTTP → HTTPS 자동 redirect), `#OWASP-HSTS-C3` (invalid cert 경고 override 불가), `#OWASP-HSTS-C4` (권장 헤더 예시 `max-age=63072000; includeSubDomains; preload`), `#OWASP-HSTS-C6` (`includeSubDomains` 생략 시 cookie 공격 위험) | TLS 1.0/1.1 deprecation: `official-standard` (RFC 8996 = IETF Standards Track). HSTS: `official-reference` (OWASP cheatsheet — 표준 아님; RFC 6797 별도) | RFC 8996 은 **TLS 1.0/1.1 의 MUST NOT** 만 보증 — "TLS 1.2 가 충분히 안전" 또는 "TLS 1.3 권장" 은 별도 RFC 8446 / 8447 영역. OWASP HSTS 는 cheatsheet (reference) 이므로 official standard 로 격상 금지. `OWASP-HSTS-C5` 의 preload PERMANENT CONSEQUENCES 는 학습 도메인에 preload 금지 권고로 반영 필요 (Claims To Verify §HSTS preload 항목 참조) |
| D6 | 본 sub-sub-branch 전체 등급 `documented-only` (실 cert 발급 / Caddy or nginx 구동 보류) | N/A — 부모 P3B 의 documented-only 정책에 종속, 실 구동은 P3A 완료 후 재검토 | UNSUPPORTED_DECISION (project scope 결정 — 외부 raw 가 아닌 부모 branch P3B 의 `documented-only` 정책에 종속) | `UNSUPPORTED_DECISION` | scope 결정 자체는 외부 raw 인용 불필요 — 부모 branch decision 만 root |
## 구현 가이드
> 본 branch 는 전체 등급 `documented-only` (D6) — 실 cert 발급/구동은 P3A 완료 후 선택적 확장. 따라서 본 §는 *확장 시 되묻지 않도록* 각 옵션의 config-level 명세를 결정별로 catalog 한다.
> **주의 (R2 라벨 원칙)**: config 문법 detail (Caddyfile 정확한 syntax / nginx directive line / `cloudflared` config key / ALB Security Policy) 은 수집한 raw 가 *동작 원리*만 보증하고 *정확한 문법*은 보증하지 않으므로 `UNSUPPORTED_IMPL_DECISION` 라벨 — 실 확장 시 vendor 문법 페이지로 재확인 대상 (Claims To Verify 와 연결).
### 1. Cloudflare Tunnel edge TLS (학습 1순위)
> **Trace**: D1 → `CLOUDFLARE-TUNNEL-C1` (cloudflared outbound-only), `-C2` (inbound firewall 차단), `-C5` (locally-managed tunnel DNS routing).
>
> - **UNSUPPORTED_IMPL_DECISION**: `cloudflared` config 의 정확한 `ingress:` 문법 + `service: http://localhost:8080` 매핑은 수집 raw 에 없음 (routing 원리만 보증) — trade-off: 학습 1순위라 우선 문서화하나 실 확장 시 Cloudflare Tunnel config 페이지 인용 보강 필요.
| 항목 | 명세 | 근거 / 라벨 |
|---|---|---|
| Origin | `http://localhost:8080` (평문, egress-only) | D1 / `CLOUDFLARE-TUNNEL-C1` |
| Edge TLS | Cloudflare edge 가 TLS 종단하고 edge certificate lifecycle을 관리 | D1 (정확한 갱신 보장은 Claims To Verify §Cloudflare 확인 대상) |
| Inbound port | EC2 inbound 전부 차단 (tunnel egress-only) | D1 / `CLOUDFLARE-TUNNEL-C2` |
| DNS routing | locally-managed tunnel → `cloudflared` DNS route 명령 | D1 / `CLOUDFLARE-TUNNEL-C5` |
| X-Forwarded-Proto | edge 가 `https` 주입 → Keycloak 이 소비 | 의존: [[raw/branch-notes/feature-keycloak-reverse-proxy-headers]] D1 (§엣지·실패·의존) |
### 2. Caddy 1줄 config (학습 2순위 — EC2 직접 노출)
> **Trace**: D2 → `CADDY-AHTTPS-C1` (cert 자동 발급+갱신), `-C2` (default HTTPS serve), `-C3` (Let's Encrypt/ZeroSSL ACME), `-C4` (HTTP→HTTPS redirect), `-C5` (background renewal).
>
> - **UNSUPPORTED_IMPL_DECISION**: (a) `Caddyfile` 정확한 문법 `kc.example.com { reverse_proxy localhost:8080 }` 은 수집 raw 미보증(auto-HTTPS 원리만) — trade-off: 관행적으로 널리 쓰이나 문법은 Caddyfile 페이지로 재확인. (b) **"HSTS 디폴트" 는 `CADDY-AHTTPS-C11` 이 부재를 명시** → HSTS 는 Caddy `header` directive 로 *명시* 필요로 가정, default 로 단정 금지 (D2 Open Risk 와 동일).
| 항목 | 명세 | 근거 / 라벨 |
|---|---|---|
| Config | `Caddyfile` 1줄: `kc.example.com { reverse_proxy localhost:8080 }` | D2 / UNSUPPORTED_IMPL_DECISION (문법) |
| Cert 발급 | `auto_https` default → public ACME CA (Let's Encrypt/ZeroSSL) | D2 / `CADDY-AHTTPS-C3` |
| Cert 갱신 | background 자동 (정확한 "만료 N일 전" timing 은 ACME issuer 정책 의존) | D2 / `CADDY-AHTTPS-C5` |
| HTTP→HTTPS | default redirect | D2 / `CADDY-AHTTPS-C4` |
| HSTS | `header Strict-Transport-Security ...` **명시 필요** (default 로 단정 금지) | D2 / `CADDY-AHTTPS-C11` (부재 근거) → UNSUPPORTED_IMPL_DECISION |
| TLS min | TLS 1.2 minimum (Caddy 관행 default) | D5 / UNSUPPORTED_IMPL_DECISION (정확 min version 은 Caddy tls 페이지 재확인) |
### 3. nginx + certbot (운영 비교 baseline)
> **Trace**: D3 → `CERTBOT-UG-C1` (subcommand), `-C2` (automated renewal preconfigured), `-C4` (`--nginx` plugin), `-C5` (4.0.0+ renewal 임계 = lifetime 1/3), `-C6` (deploy-hook).
>
> - **UNSUPPORTED_IMPL_DECISION**: nginx `server` block 의 정확한 directive (`ssl_protocols TLSv1.2 TLSv1.3;`, `add_header Strict-Transport-Security ...`) 는 certbot raw 가 보증 안 함 (certbot 은 cert 발급/갱신만) — trade-off: nginx TLS/HSTS directive 는 nginx 문서 영역이고 본 branch 는 비교 baseline 이라 원리 수준만.
| 항목 | 명세 | 근거 / 라벨 |
|---|---|---|
| 발급 | `certbot --nginx -d kc.example.com` → server block 자동 삽입 | D3 / `CERTBOT-UG-C4` |
| 갱신 | `certbot.timer` (automated renewal preconfigured), 임계 = lifetime 1/3 | D3 / `CERTBOT-UG-C2`, `-C5` |
| deploy-hook | `--deploy-hook` 으로 갱신 후 nginx reload | D3 / `CERTBOT-UG-C6` |
| TLS min | `ssl_protocols TLSv1.2 TLSv1.3;` **명시** | D5 / UNSUPPORTED_IMPL_DECISION (nginx directive) |
| HSTS | `add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;` **명시** | D5 / `OWASP-HSTS-C4` (헤더 값) + UNSUPPORTED_IMPL_DECISION (nginx add_header 문법) |
### 4. EC2 + ALB + ACM (운영 대안 — 기재만)
> **Trace**: D4 → `AWS-ACM-RENEW-C1`/`-C11` (DNS-validated 자동 갱신), `-C3` (ELB attach 자격), `-C8` (ARN 유지 → 무수정 갱신), `-C12` (만료 45/60일 전 갱신), `-C13` (갱신 사전조건), `-C14` (EventBridge alert).
>
> - **UNSUPPORTED_IMPL_DECISION**: ALB **Security Policy (TLS 1.2 enforce)** 는 ACM raw 밖 (ELB listener 문서 영역) — D4 Open Risk 와 동일. trade-off: 운영 대안 기재만이므로 Terraform/console 실배치는 본 branch scope 밖.
| 항목 | 명세 | 근거 / 라벨 |
|---|---|---|
| Cert | ACM DNS-validated → fully automated renewal | D4 / `AWS-ACM-RENEW-C11` |
| Attach | ALB listener 에 attach (ARN 유지 → 무수정 갱신) | D4 / `AWS-ACM-RENEW-C3`, `-C8` |
| 갱신 사전조건 | AWS service 사용 중 + CNAME public DNS 유지 | D4 / `AWS-ACM-RENEW-C13` |
| 실패 alert | EventBridge 30/15/7/3/1일 전 | D4 / `AWS-ACM-RENEW-C14` |
| TLS policy | ALB Security Policy = TLS 1.2 min | D5 / UNSUPPORTED_IMPL_DECISION (ELB 문서 영역) |
### 5. cert 갱신 자동화 + TLS/HSTS enforce 위치 (cross-cutting)
> **Trace**: D5 → `RFC8996-C4`/`-C5` (TLS 1.0/1.1 MUST NOT), `OWASP-HSTS-C4` (권장 헤더값), `-C6` (`includeSubDomains` 생략 위험). 갱신 메커니즘은 옵션별 §1~§4 참조.
>
> - **UNSUPPORTED_IMPL_DECISION**: 각 proxy 의 TLS min / HSTS 를 *어느 config 라인에* 넣는지의 정확한 문법은 §2~§4 라벨 참조 — 값(`max-age`, `includeSubDomains`)은 `OWASP-HSTS-C4` 로 보증, 위치·문법은 vendor 별.
| 옵션 | cert 갱신 | TLS 1.2+ enforce 위치 | HSTS 위치 |
|---|---|---|---|
| Cloudflare Tunnel | edge 자동 (D1) | Cloudflare dashboard | dashboard (edge) |
| Caddy | 내장 background (D2) | `tls` directive (관행 default) | `header` directive **명시** (§2) |
| nginx+certbot | `certbot.timer` (D3) | `ssl_protocols` (§3) | `add_header` (§3) |
| ALB+ACM | ACM 자동 (D4) | ALB Security Policy (§4) | ALB / WAF |
> **HSTS 공통 정책** (D5): 권장값 `max-age=63072000; includeSubDomains` (`OWASP-HSTS-C4`), `includeSubDomains` 생략 시 cookie 공격 노출(`OWASP-HSTS-C6`). **`preload` 는 학습 도메인에 금지** — 되돌리기 PERMANENT (Claims To Verify §HSTS preload).
## 엣지·실패·의존
> R4(깊이 게이트) 캡처. 본 branch 는 `documented-only` 이므로 아래 실패 경로는 *실 확장 시* 부딪힐 함정(진행 중 메모·마주친 문제에서 승격)이고, 의존은 *TLS 종단 위치가 다른 계약에 미치는 영향*이다.
- **실패·엣지 경로**:
- **Let's Encrypt rate limit** — 도메인당 주 50회 발급. 디버깅 반복 시 `--staging` endpoint 사용 (D2/D3 확장 시). → Claims To Verify §rate limit (공식 raw 미수집).
- **ACME-HTTP-01 challenge 는 80 port 점유 필요** — Keycloak 이 80 을 안 쓰는지 확인(충돌 시 발급 실패). Caddy/certbot 공통(D2/D3).
- **certbot.timer 비활성** — Ubuntu default enable 이나 minimal 이미지에서 누락 → cert 만료 사고(D3). → Claims To Verify §certbot.timer.
- **Caddy HSTS 오인** — "default HSTS" 가정 시 실제 미적용 가능(`CADDY-AHTTPS-C11` 부재 근거) → `header` directive 명시로 방어(구현 가이드 §2).
- **HSTS preload 되돌리기 불가** — 한 번 등록 시 subdomain 전체 HTTPS 강제 PERMANENT → 학습 도메인 preload 금지(D5, `OWASP-HSTS-C6` 계열).
- **Cloudflare Tunnel origin verification** — edge 는 self-signed origin 도 허용하나 학습은 HTTP origin 이 단순(D1).
- **다른 계약 의존**:
- [[raw/branch-notes/feature-keycloak-reverse-proxy-headers]] 의 **D1 (`KC_PROXY_HEADERS=xforwarded`)** 에 의존 — TLS 종단 위치가 `X-Forwarded-Proto: https` 의 *출처*를 결정한다. Cloudflare Tunnel(D1)은 origin 이 HTTP 이므로 edge 가 헤더를 주입해야 Keycloak 이 HTTPS 인식; Caddy(D2)/nginx(D3)는 proxy 가 종단하며 헤더를 세팅. **그 계약이 바뀌면(예: `forwarded` 모드 전환)** 본 branch 의 종단-위치별 헤더 주입 가정이 깨진다.
- [[raw/branch-notes/feature-keycloak-public-domain-tunneling]] 에 의존 — D1(Cloudflare Tunnel edge TLS)은 이 branch 의 public 도메인/tunnel 확보를 전제한다. tunnel 미확보면 D1 → D2(Caddy) fallback.
- [[raw/branch-notes/feature-keycloak-google-redirect-uri-policy]] 에 의존(역방향 — 본 branch 의 WHY) — Google OAuth 의 HTTPS `redirect_uri` 강제가 본 branch 의 존재 이유. TLS 종단이 없으면 그 정책을 충족 불가.
## 검증해야 할 주장
> 공식 문서나 사례는 근거지만, 내 프로젝트에서의 동작을 자동으로 보장하지 않는다.
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
| Caddy `Caddyfile` 1줄 (`kc.example.com { reverse_proxy localhost:8080 }`) + `auto_https on` 디폴트로 Let's Encrypt cert 자동 발급 동작 | Caddy 공식 raw 미수집 — 본 branch 의 진행 중 메모는 관행적 사실 | 실제 EC2 또는 로컬 도커에서 Caddy 구동 → DNS A 레코드 매핑 → 첫 요청 시 ACME-HTTP-01 challenge 로그 + 발급된 cert 확인 | `planned` |
| Cloudflare Tunnel edge certificate의 발급·갱신 조건과 실패 시 운영 책임 | `CLOUDFLARE-TUNNEL-C1`/`C2` 는 outbound tunnel 동작만 보증하고 certificate lifecycle 조건은 직접 입증하지 않음 (별도 Cloudflare SSL/TLS 페이지 필요) | Cloudflare dashboard → SSL/TLS → Edge Certificates → auto-renew 정책 확인 + cert expiry 모니터링 | `needs-confirmation` |
| certbot.timer 가 Ubuntu 디폴트로 enable + 정상 동작 | certbot 공식 raw 미수집 — 관행적 사실 | `systemctl list-timers \| grep certbot` + `certbot renew --dry-run` 실행하여 종료 코드 0 확인 | `planned` |
| Let's Encrypt rate limit 도메인당 주 50회 | Let's Encrypt 공식 raw 미수집 — 본 branch 의 진행 중 메모는 관행적 사실 | Let's Encrypt rate limits 페이지 직접 발췌 후 `raw/official-docs/` 등록 | `planned` |
| HSTS preload 등록 후 subdomain 전체 HTTPS 강제 + 학습 도메인 preload 금지 권고 | HSTS preload 공식 raw 미수집 — 관행적 사실 | `hstspreload.org` 정책 페이지 발췌 후 인용 보강 | `planned` |
## 마주친 문제
- 아직 없음 (문서 단계). 실 적용 시 예상되는 함정:
- **Let's Encrypt rate limit**: 도메인당 주 50회 cert 발급. 디버깅 반복 시 staging endpoint (`--staging`) 활용.
- **ACME-HTTP-01 challenge** 시 80 port 점유 필요 → Keycloak이 80을 안 쓰는지 확인.
- **certbot.timer 비활성**: Ubuntu 디폴트로 enable되어 있으나 일부 minimal 이미지에서 누락 → cert 만료 사고.
- **Cloudflare Tunnel origin verification**: edge에서 self-signed cert origin도 허용하나 학습 환경에서는 HTTP origin이 단순.
- **HSTS preload 등록 후 실수**: 한 번 preload에 등록되면 subdomain 전체가 HTTPS 강제 → 학습 도메인에는 preload 금지.
## 묶음
<!-- GENERATED: sources:start -->
- [[raw/official-docs/aws-acm-managed-renewal]]
- [[raw/official-docs/caddy-automatic-https-docs]]
- [[raw/official-docs/certbot-user-guide]]
- [[raw/official-docs/keycloak-hostname-configuration]]
- [[raw/official-docs/keycloak-server-containers-docker]]
- [[raw/official-docs/owasp-hsts-cheat-sheet]]
- [[raw/official-docs/rfc8996-tls10-tls11-deprecation]]
<!-- GENERATED: sources:end -->
> 본 branch 는 leaf — 자식 자료 없음. errors / interview prep / lectures 가 누적되면 본 섹션에서 그룹화.
### 오류 기록
- (없음)
### 면접 준비
- (없음)
## 관련 일일 노트
## 완료 후 정리
> 본 sub-sub-branch는 **문서까지만**. 실 Caddy / nginx 설치 / cert 발급은 P3A 완료 후 선택적 확장.
- PR 링크:
- 리뷰 메모:
- 머지 결과 / 배포 환경: 해당 없음 (문서 단계, P3B 전체 `documented-only`)
- **wiki 추출 대상** (verified만, `wiki/projects/`로만 추출):
- `actually-implemented` 항목: 없음
- `locally-verified` 항목: 없음
- `prod-verified` 항목: 없음
- **추출하지 않을 항목** (planned / documented-only / abandoned):
- 본 sub-sub-branch 전체가 `documented-only`. 추후 `wiki/concepts/keycloak-deployment-patterns.md` 합성 시 "HTTPS termination 옵션 비교표"로 인용 후보.