137 lines
5.6 KiB
Markdown
137 lines
5.6 KiB
Markdown
# Session store lab
|
|
|
|
세션 저장소·refresh token 경쟁·장애 복구를 검증하는 2노드 k3s 실험대.
|
|
네 인증 패턴(AP1~AP4)을 가로지르는 공통층이므로 별도 축으로 관리한다.
|
|
|
|
이 문서는 **절차**만 담는다.
|
|
|
|
| 문서 | 내용 |
|
|
|---|---|
|
|
| [`docs/session-store-lab-roadmap.md`](../../docs/session-store-lab-roadmap.md) | 이 축의 계획과 진행 상황 |
|
|
| [`docs/session-lab-concepts.md`](../../docs/session-lab-concepts.md) | 등장 개념 전체 |
|
|
| [`docs/session-lab-operations.md`](../../docs/session-lab-operations.md) | 관측 도구 · 자주 쓰는 명령 · 훈련 |
|
|
| [`docs/two-hop-proxy-header-contract.md`](../../docs/two-hop-proxy-header-contract.md) | 첫 실험 결과 |
|
|
|
|
## 토폴로지
|
|
|
|
```
|
|
브라우저 / SSH (tailnet)
|
|
│ https://{auth,app1,app2}.hyeonworks.com → 100.83.212.4
|
|
▼
|
|
lab host ── nginx :443 TLS 종료 · X-Forwarded-* 주입
|
|
│ nginx :80 301 → https
|
|
│
|
|
│ virbr0 192.168.122.0/24 (libvirt NAT)
|
|
├──▶ kc-lab-1 .11 k3s server Traefik :80
|
|
└──▶ kc-lab-2 .12 k3s agent Traefik :80
|
|
└──▶ Pod
|
|
```
|
|
|
|
`nginx → Traefik` **2홉**이 운영 구조와 같다는 점이 이 배치의 핵심이다.
|
|
L7 프록시가 두 겹인 이유는 역할이 다르기 때문이다 — nginx는 바깥세상과의
|
|
접점(TLS·인증서·헤더)을, Traefik은 클러스터 내부의 동적 라우팅을 맡는다.
|
|
|
|
## 구성 요소
|
|
|
|
| 경로 | 역할 |
|
|
|---|---|
|
|
| `cloud-init/kc-lab.yaml.example` | 게스트 부트스트랩 템플릿 |
|
|
| `host/nginx-keycloak-lab.conf` | lab host의 `sites-available/keycloak-lab` |
|
|
| `k8s/echo.yaml` | 2홉 헤더 계약 측정용 워크로드 |
|
|
| `scripts/rebuild-seed.sh` | cloud-init 시드 ISO 재생성 + 풀 업로드 |
|
|
| `scripts/build-and-import.sh` | 이미지 빌드 → 각 노드 containerd 반입 |
|
|
| `scripts/measure-proxy-headers.sh` | 헤더 계약 실측 |
|
|
| `scripts/verify-lab.sh` | 인프라 상태 점검 |
|
|
|
|
## 상태 점검
|
|
|
|
```bash
|
|
./deploy/lab/scripts/verify-lab.sh # lab host 에서
|
|
```
|
|
|
|
**`404`가 성공 신호다.** TLS가 종료되고 Traefik까지 도달했으나 매칭되는
|
|
Ingress 규칙이 없다는 뜻이다. `502`나 연결 거부면 체인이 끊긴 것이다.
|
|
|
|
## 첫 실험 — 2홉 헤더 계약
|
|
|
|
[`docs/reverse-proxy-headers.md`](../../docs/reverse-proxy-headers.md)의 계약은
|
|
nginx **1홉**을 가정하고 쓰였다. 실제 배치는 2홉이므로, nginx가 세팅한
|
|
`X-Forwarded-*`를 Traefik이 그대로 넘기는지 덮어쓰는지 **측정해서 확인한다.**
|
|
|
|
이 결론이 뒤의 모든 실험에 깔린다. Keycloak의 `iss` 클레임, redirect URL,
|
|
쿠키 도메인 검증이 전부 이 헤더에 의존하기 때문이다.
|
|
|
|
```bash
|
|
# 워크스테이션: 이미지 빌드 후 두 노드에 반입
|
|
./deploy/lab/scripts/build-and-import.sh
|
|
|
|
# lab host: 배포
|
|
kubectl apply -f deploy/lab/k8s/echo.yaml
|
|
kubectl -n header-lab rollout status deployment/echo
|
|
|
|
# 어디서든: 실측
|
|
./deploy/lab/scripts/measure-proxy-headers.sh
|
|
```
|
|
|
|
관측 대상은 넷이다.
|
|
|
|
1. `X-Forwarded-For` — Traefik이 **덧붙이는가 덮어쓰는가**
|
|
2. `X-Forwarded-Proto` / `-Host` / `-Port` — 그대로 전달되는가
|
|
3. **위조 내성** — 클라이언트가 직접 넣은 `X-Forwarded-*`가 앱까지 도달하는가
|
|
4. `scheme` / `secure` / `requestUrl` — Keycloak이 URL을 만들 때 쓰는 값
|
|
|
|
3번이 신뢰 경계의 핵심이다. 이 헤더들은 누구나 위조할 수 있는 평범한 HTTP
|
|
헤더이므로, 신뢰 경계에 선 프록시가 **반드시 덮어써야** 한다.
|
|
|
|
## 이미지 배포 경로
|
|
|
|
k3s는 containerd를 쓰고 이 실험대에는 레지스트리가 없다.
|
|
|
|
```
|
|
워크스테이션 docker build → docker save
|
|
│ ssh (lab host 경유)
|
|
▼
|
|
게스트 sudo k3s ctr images import
|
|
매니페스트 imagePullPolicy: Never
|
|
```
|
|
|
|
**두 노드 모두에 반입해야 한다.** 스케줄러가 어느 노드에 배치할지 모른다.
|
|
Keycloak·PostgreSQL·Redis는 공식 이미지를 그대로 당겨오므로 이 경로가
|
|
필요한 것은 자체 빌드 이미지뿐이다.
|
|
|
|
**lab host에 Docker를 설치하지 않는다.** k3s의 containerd와 이미지 저장소가
|
|
갈려서 `docker build`한 이미지를 k3s가 보지 못하게 된다.
|
|
|
|
## 게스트 재생성
|
|
|
|
파괴적 실험 후 초기화하는 경로다.
|
|
|
|
```bash
|
|
virsh destroy kc-lab-1
|
|
virsh undefine kc-lab-1 # --remove-all-storage 는 시드 ISO 까지 지운다
|
|
virsh vol-delete --pool default kc-lab-1.qcow2
|
|
|
|
./deploy/lab/scripts/rebuild-seed.sh 1 # user-data 를 고쳤을 때만
|
|
|
|
virt-install --name kc-lab-1 --memory 3584 --vcpus 2 \
|
|
--disk size=20,backing_store=/var/lib/libvirt/images/base.qcow2 \
|
|
--disk vol=default/seed-kc-lab-1.iso,device=disk,bus=virtio,readonly=on \
|
|
--network network=default,mac=52:54:00:aa:bb:11 \
|
|
--import --os-variant debian12 --noautoconsole
|
|
```
|
|
|
|
시드는 **virtio 디스크**로 붙인다. `virt-install --cloud-init`은 시드를 SATA
|
|
CD-ROM으로 붙이는데, Debian `genericcloud` 이미지는 크기를 줄이려고 물리
|
|
하드웨어 드라이버를 제외해서 **AHCI 장치를 보지 못한다.** 그러면 cloud-init이
|
|
데이터소스를 찾지 못하고 아무 오류도 남기지 않은 채 종료한다. 증상은
|
|
hostname이 `localhost`로 남고 SSH가 `Permission denied (publickey)`로 거부되는
|
|
것뿐이다.
|
|
|
|
게스트에 들어갈 수 없을 때는 화면을 직접 뜬다.
|
|
|
|
```bash
|
|
virsh screenshot kc-lab-1 /tmp/kc1.ppm # 확장자와 무관하게 PNG 로 저장된다
|
|
```
|
|
|
|
`localhost login:`이면 cloud-init 미실행, `kc-lab-1 login:`이면 실행된 것이다.
|