docs: map deploy/ assets and record why unapplied configs are kept
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
bcfdeb93ee
commit
a831792c5c
@@ -2672,6 +2672,160 @@ pacman-key --list-keys | head
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 9층. `deploy/` — 무엇이 살아 있고 무엇이 참조인가
|
||||||
|
|
||||||
|
저장소에 있으나 지금 적용되지 않는 설정이 여럿이다. 죽은 코드가 아니라
|
||||||
|
**의도적으로 남겨둔 참조 자산**이며, 그 구분을 여기 기록한다.
|
||||||
|
|
||||||
|
### 전체 지도
|
||||||
|
|
||||||
|
| 경로 | 상태 | 대상 배포 형태 | 검증 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `lab/host/nginx-keycloak-lab.conf` | **적용 중** | 2노드 k3s 실험대 | `lab/scripts/verify-lab.sh` |
|
||||||
|
| `lab/cloud-init/kc-lab.yaml.example` | **적용 중**(템플릿) | 실험대 게스트 | 게스트 부팅 |
|
||||||
|
| `lab/k8s/echo.yaml` | **적용 중** | 실험대 | `kubectl apply` |
|
||||||
|
| `reverse-proxy/nginx-keycloak.conf` | 참조 | 단일 호스트 Compose | `scripts/verify-reverse-proxy-headers.sh` |
|
||||||
|
| `reverse-proxy/keycloak.env.example` | 참조 | 위와 한 쌍 | 동일 |
|
||||||
|
| `tls/nginx.conf` | 참조 | 단일 호스트, 운영자가 인증서 관리 | `scripts/verify-https-termination-config.sh` |
|
||||||
|
| `tls/Caddyfile` | 참조 | 단일 호스트, ACME 자동화 | 동일 |
|
||||||
|
| `tunnel/cloudflared-config.yml` | **미채택** | 공개 도메인 터널 | `scripts/verify-public-tunnel-config.sh` |
|
||||||
|
|
||||||
|
**세 가지 상태**
|
||||||
|
|
||||||
|
- **적용 중** — 지금 실험대에서 실제로 도는 설정
|
||||||
|
- **참조** — 다른 배포 형태의 예제. 실행되지는 않지만 **문법·계약 검증은 받는다**
|
||||||
|
- **미채택** — 조건이 맞지 않아 고르지 않은 경로. 근거를 남기려고 보존한다
|
||||||
|
|
||||||
|
### 왜 적용하지 않는 것을 남겨두는가
|
||||||
|
|
||||||
|
**1. 이 저장소의 목적이 비교다.** 네 인증 패턴을 같은 인프라에서 비교하는
|
||||||
|
학습 프로젝트이므로, **배포 형태도 선택지를 나란히 두고 트레이드오프를
|
||||||
|
기록하는 것 자체가 산출물**이다. 하나만 남기면 "왜 이걸 골랐는가"의 근거가
|
||||||
|
사라지고, 조건이 바뀌었을 때 재검토할 자료가 없어진다.
|
||||||
|
|
||||||
|
**2. 죽은 코드가 아니라 테스트되는 코드다.** 각 파일에 대응하는
|
||||||
|
`scripts/verify-*.sh`가 붙어 있다.
|
||||||
|
|
||||||
|
```
|
||||||
|
scripts/verify-reverse-proxy-headers.sh → deploy/reverse-proxy/ 두 파일의 계약 짝
|
||||||
|
scripts/verify-https-termination-config.sh → deploy/tls/ 두 파일을 실제 이미지로 validate
|
||||||
|
scripts/verify-public-tunnel-config.sh → deploy/tunnel/ ingress 구조
|
||||||
|
```
|
||||||
|
|
||||||
|
특히 두 번째는 임시 자체서명 인증서를 만들어 **nginx와 Caddy 두 벤더 이미지에서
|
||||||
|
각각 설정을 검증하고** 임시 파일을 지운다. 실행되지 않을 뿐 **깨지면 드러난다.**
|
||||||
|
|
||||||
|
**3. 배포 형태가 바뀌면 되살아난다.** 지금은 2노드 k3s지만 단일 호스트로
|
||||||
|
옮기면 `reverse-proxy/`가 곧바로 쓰인다. 그래서 **실험대 전용 설정은
|
||||||
|
`lab/` 아래로 분리**해 일반 배포 설정과 섞이지 않게 두었다.
|
||||||
|
|
||||||
|
### `reverse-proxy/` — 1홉 계약의 원본
|
||||||
|
|
||||||
|
**`keycloak.env.example`** — Keycloak 쪽이 지켜야 할 네 줄이다.
|
||||||
|
|
||||||
|
| 설정 | 의미 | 없거나 틀리면 |
|
||||||
|
|---|---|---|
|
||||||
|
| `KC_HTTP_ENABLED=true` | 프록시가 TLS를 끊었으므로 Keycloak은 평문 HTTP를 받는다 | 기동 거부 |
|
||||||
|
| `KC_PROXY_HEADERS=xforwarded` | **`X-Forwarded-*`를 신뢰하겠다는 명시적 옵트인** | 헤더를 통째로 무시한다 |
|
||||||
|
| `KC_HOSTNAME=https://auth.example.test` | 외부에서 보이는 주소를 고정 | 내부 주소가 `iss`에 박힌다 |
|
||||||
|
| `KC_HOSTNAME_STRICT=true` | Host 헤더를 믿지 않고 위 값만 쓴다 | Host 조작으로 흐름을 돌릴 여지 |
|
||||||
|
|
||||||
|
**두 번째 줄이 이 실험대의 핵심 개념과 직결된다.** `/api/echo`에서 확인한
|
||||||
|
Spring의 `forward-headers-strategy`와 **정확히 같은 성격의 스위치**다.
|
||||||
|
프레임워크는 기본적으로 forwarded 헤더를 믿지 않으며, 신뢰는 명시적으로
|
||||||
|
켜야 한다. 켜지 않으면 프록시가 아무리 올바른 헤더를 넣어도 무시된다.
|
||||||
|
|
||||||
|
**`nginx-keycloak.conf`** — 프록시 쪽 짝이다. **이것이 1홉을 가정한 원본**이며,
|
||||||
|
[`docs/reverse-proxy-headers.md`](reverse-proxy-headers.md)가 문서화한 계약이다.
|
||||||
|
|
||||||
|
실험대의 `lab/host/nginx-keycloak-lab.conf`와 세 곳이 다르다.
|
||||||
|
|
||||||
|
| | `reverse-proxy/` (원본) | `lab/host/` (실험대) |
|
||||||
|
|---|---|---|
|
||||||
|
| upstream | `keycloak:8080` 단일 | 노드 2개 (`.11`, `.12`) |
|
||||||
|
| TLS | 없음 (앞단이 따로 종료) | 여기서 종료 (Let's Encrypt) |
|
||||||
|
| `X-Forwarded-For` | `$proxy_add_x_forwarded_for` (덧붙이기) | `$remote_addr` (**덮어쓰기**) |
|
||||||
|
|
||||||
|
세 번째 줄이 신뢰 경계의 차이다. 덧붙이면 클라이언트가 위조한 값이
|
||||||
|
사슬 앞부분에 남고, 덮어쓰면 사라진다. **이 차이를 실측으로 확정하는 것이
|
||||||
|
첫 실험의 목적이다.**
|
||||||
|
|
||||||
|
### `tls/` — 같은 일을 하는 두 구현
|
||||||
|
|
||||||
|
`nginx.conf`와 `Caddyfile`은 **동일한 결과**를 만든다. 공개 443에서 TLS를
|
||||||
|
종료하고 사설 네트워크의 `keycloak:8080`으로 평문 전달한다.
|
||||||
|
|
||||||
|
```
|
||||||
|
nginx Caddy
|
||||||
|
ssl_certificate …crt tls /etc/tls/tls.crt /etc/tls/tls.key
|
||||||
|
ssl_certificate_key …key
|
||||||
|
proxy_set_header Host $host header_up Host {host}
|
||||||
|
proxy_set_header X-Forwarded-* header_up X-Forwarded-*
|
||||||
|
```
|
||||||
|
|
||||||
|
**차이는 인증서 수명주기를 누가 관리하는가 하나뿐이다.**
|
||||||
|
|
||||||
|
| | nginx | Caddy |
|
||||||
|
|---|---|---|
|
||||||
|
| 발급·갱신 | **운영자**가 담당 (certbot 등) | **프록시가 ACME로 자동** |
|
||||||
|
| 설정 분량 | 많다 | 적다 |
|
||||||
|
| 통제력 | 세밀 | 자동화에 위임 |
|
||||||
|
|
||||||
|
**이 실험대는 nginx + certbot을 골랐다.** DNS-01 와일드카드가 필요했고,
|
||||||
|
인증서 발급 시점과 방식을 직접 통제해야 했기 때문이다.
|
||||||
|
|
||||||
|
**둘을 동시에 진입점으로 띄우지 않는다.** 같은 443을 두 프로세스가 잡을 수
|
||||||
|
없다. 예제가 둘인 것은 선택지를 보여주기 위해서다.
|
||||||
|
|
||||||
|
### `tunnel/` — 채택하지 않은 이유를 남긴 자산
|
||||||
|
|
||||||
|
`cloudflared-config.yml`은 Cloudflare named tunnel 설정이다.
|
||||||
|
**아웃바운드 연결만 쓰므로 포트포워딩 없이 공개 HTTPS 이름을 얻는다.**
|
||||||
|
공유기를 건드릴 수 없는 환경에서 매력적인 선택지다.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
ingress:
|
||||||
|
- hostname: auth.example.test
|
||||||
|
service: http://reverse-proxy:8080 # ← 127.0.0.1 이 아니다
|
||||||
|
- service: http_status:404 # ← catch-all
|
||||||
|
```
|
||||||
|
|
||||||
|
- `service:`에 `127.0.0.1`을 쓰면 **cloudflared 컨테이너 자신**을 가리킨다.
|
||||||
|
Compose 서비스 DNS 이름을 써야 한다
|
||||||
|
- 마지막 catch-all은 알 수 없는 hostname을 404로 끝낸다. 없으면 오류가 난다
|
||||||
|
|
||||||
|
**그런데 이 실험대는 채택하지 않았다.** 이유가 실험의 성격과 맞물린다.
|
||||||
|
|
||||||
|
```
|
||||||
|
터널 사용 : 브라우저 → Cloudflare 엣지 → nginx → Traefik → Pod (3홉)
|
||||||
|
현재 구성 : 브라우저 → nginx → Traefik → Pod (2홉)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cloudflare 엣지가 TLS를 끊고 다시 맺으면서 홉이 하나 늘고**,
|
||||||
|
`CF-Connecting-IP` 같은 자체 헤더가 섞인다. 이 실험대가 측정하려는 것이
|
||||||
|
정확히 **`nginx → Traefik` 2홉의 forwarded 헤더 계약**이므로,
|
||||||
|
앞에 한 겹이 더 붙으면 **측정이 오염된다.**
|
||||||
|
|
||||||
|
그래서 tailnet 직결을 택했다. 조건이 바뀌어(예: 다른 회선으로 이전) 공개
|
||||||
|
접근이 필요해지면 이 파일이 그대로 쓰인다.
|
||||||
|
|
||||||
|
### `.example` 접미사 관례
|
||||||
|
|
||||||
|
`keycloak.env.example`, `kc-lab.yaml.example`처럼 **비밀이 들어갈 자리가 있는
|
||||||
|
파일은 `.example`로 커밋하고 실파일은 무시한다.** 저장소가 `.env.example`에
|
||||||
|
쓰는 것과 같은 규칙이다.
|
||||||
|
|
||||||
|
```
|
||||||
|
.env.example → .env (gitignore)
|
||||||
|
deploy/lab/cloud-init/kc-lab.yaml.example → kc-lab-1.yaml, kc-lab-2.yaml (gitignore)
|
||||||
|
```
|
||||||
|
|
||||||
|
`kc-lab.yaml.example`이 감추는 것은 `plain_text_passwd`(콘솔 비상용 비밀번호)와
|
||||||
|
SSH 공개키 두 줄이다. 공개키 자체는 비밀이 아니지만, **저장소가 공개이므로
|
||||||
|
호스트 신원 정보를 불필요하게 노출하지 않는다.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 아직 기록하지 않은 개념
|
## 아직 기록하지 않은 개념
|
||||||
|
|
||||||
실험 설계 단계에서 아래 항목을 이 문서에 추가한다.
|
실험 설계 단계에서 아래 항목을 이 문서에 추가한다.
|
||||||
|
|||||||
Reference in New Issue
Block a user