Files
document-haness/docs/keycloak-session-store/final/evidence/raw/d4a-deploy-hook__01-hook-verified.txt
T
DongHyeonkaandClaude Opus 5 b2963105a8 docs(keycloak-session-store): import the session-storage lab as a new project
The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.

Follows the import procedure in README.md.

  source/     the originating repository verbatim — 78 documents, 28 SVGs,
              8 manifests, plus .source-revision recording the commit
  final/      the SSOT
    document.md   729 lines written from the 29 experiment documents, not
                  concatenated: what was predicted, what was measured, and
                  where the measurement itself was wrong
    evidence/raw    125 outputs, flattened to <experiment>__<file> because
                    the originals collided (01-baseline.txt appeared three
                    times) and the audit only globs the top level
    evidence/meta   one per raw file; command and exitCode are null and the
                    README says why rather than inventing them
    evidence/browser  22 captures
    assets/       three diagrams through techviz
    .techviz/     their VizSpecs

A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.

Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.

verify-pipeline.py passes. audit-records.py reports no issues.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 22:51:59 +09:00

126 lines
6.2 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
D-4a — deploy 훅이 실제로 nginx 를 reload 하는가
==================================================
수집: 2026-09-04 12:27 UTC (실제) · test-server
D-4 가 남긴 것
--------------
| 항목 | 상태 |
|---|---|
| deploy 훅을 넣으면 자동 반영되는가 | **미측정. 훅은 아직 넣지 않았다** |
D-4 는 처방을 적어두고 **검증하지 않았다.** 처방이 듣는지 모르는 채로
"이렇게 고치면 된다"고 쓰는 것은 이 실험대가 계속 경계해 온 바로 그 실수다.
[주입] 훅 하나를 넣고 강제 갱신
--------------------------------
/etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
#!/bin/sh
# D-4a: certbot deploy hook. 갱신이 실제로 일어났을 때만 실행된다.
nginx -t && nginx -s reload
install -m755 /tmp/reload-nginx.sh /etc/letsencrypt/renewal-hooks/deploy/
certbot renew --force-renewal
[결과] certbot 출력 — 훅이 실행됐다
------------------------------------
Processing /etc/letsencrypt/renewal/auth.hyeonworks.com.conf
Renewing an existing certificate for auth.hyeonworks.com and 2 more
Hook 'deploy-hook' ran with error output:
2026/09/04 21:29:36 [warn] 37250#37250: could not build optimal types_hash, …
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
2026/09/04 21:29:37 [warn] 37251#37251: could not build optimal types_hash, …
2026/09/04 21:29:37 [notice] 37251#37251: signal process started
Congratulations, all renewals succeeded:
/etc/letsencrypt/live/auth.hyeonworks.com/fullchain.pem (success)
★ 함정 — "Hook 'deploy-hook' ran with error output" 이라고 적혀 있지만
실패가 아니다. nginx 가 types_hash 경고를 stderr 로 내보내서 certbot 이
그것을 "error output" 으로 표시한 것뿐이다. 내용은 전부 성공이다:
· nginx -t → "test is successful"
· nginx -s reload → "signal process started"
로그에서 'error' 를 grep 하면 성공한 훅을 실패로 오독하게 된다.
[검증 1] nginx 워커가 교체됐다
-------------------------------
전 (D-4a 기준선)
585 1 ... Thu Sep 3 19:00:39 nginx: master process
28829 585 ... Fri Sep 4 18:00:35 nginx: worker process ← D-4 에서 사람이 reload 한 것
585 1 95412 Thu Sep 3 19:00:39 nginx: master process ← 마스터는 그대로
37252 585 74 Fri Sep 4 21:29:36 nginx: worker process ← ★ 자동 교체됨
마스터 PID 는 유지되고 워커만 바뀌었다 = reload 의 서명. D-4 에서 세운
진단 방법이 그대로 작동한다.
[검증 2] 서빙 인증서가 바뀌었다
--------------------------------
serial=06F3E0EF4D1BB03DE58130EAAD1176101373
notBefore=Sep 4 11:29:18 2026 GMT
notAfter=Dec 3 11:29:17 2026 GMT
SAN: app1 / app2 / auth .hyeonworks.com
D-4 의 인증서(06C7CB…EA1D)에서 바뀌었다.
[검증 3] ★ 얼마나 빨랐나 — 시계 보정이 필요하다
--------------------------------------------------
훅 로그와 워커 lstart 는 **test-server 시계**다. 그런데 test-server 는
NTP 동기가 꺼져 있다(NTPSynchronized=no).
외부 기준으로 두 시계를 검증했다.
dev → Google 차이 +0초
dev → Let's Encrypt ACME 차이 +0초
test-server → Google 차이 -105초 (즉 test-server 가 105초 빠르다)
ssh 왕복 왜곡 3회 측정: +106.1 / +106.1 / +106.1초 (안정적)
→ **dev 가 정확하고 test-server 가 106초 빠르다.**
독립 검증 — 새 인증서의 SCT (CT 로그가 서명한 시각, 자체 정확 시계):
Signed Certificate Timestamp: Sep 4 12:27:49.054 2026 GMT
Signed Certificate Timestamp: Sep 4 12:27:49.048 2026 GMT
보정한 타임라인 (전부 실제 UTC):
12:27:49.05 인증서 발급 ← SCT. 외부 권위 기준
12:27:50 훅 nginx -t ← 로그 21:29:36 KST 106초
12:27:50 새 워커 37252 기동 ← lstart 21:29:36 KST 106초
12:27:51 훅 nginx -s reload ← 로그 21:29:37 KST 106초
★ 발급 → 서빙까지 **1~2초.**
★ 그리고 보정이 자기 검증된다 — 독립 시계인 SCT 가 보정한 훅 시각의
1초 앞에 정확히 놓인다. 보정하지 않으면 훅이 발급보다 104초 먼저
실행된 것이 되어 물리적으로 불가능해진다.
════ D-4 와의 대조 ════
훅 없음 (D-4) 훅 있음 (D-4a)
갱신 → 서빙 2305초 = 38분 25초 1~2초
무엇이 reload 했나 사람 (`nginx -s reload`) certbot deploy 훅
안 했다면 다음 nginx 재시작까지 해당 없음
= 사실상 무기한
차이 약 1150배
════ 부수 정정 — D-4 의 2199초는 틀렸다 ════
D-4 에서 적은 **2199초(36분 39초)** 는 `archive/cert2.pem` 의 mtime
(test-server 시계)과 일련번호 관측 시각(dev 시계)을 **그대로 뺀** 값이었다.
106초 보정을 적용하면:
새 인증서 디스크 기록 08:20:27 UTC (실제) ← mtime 17:22:13 KST 106초
실제 서빙 시작 08:58:52 UTC (실제) ← dev 관측, 보정 불필요
공백 2305초 = 38분 25초
관련 문서를 전부 정정했다. **두 시계에서 온 값을 빼면서 그 사실을 적지
않으면, 자릿수가 아니라 방향까지 틀릴 수 있다** — 여기서는 그 오차가
100초 단위였고, 1~2초를 재는 D-4a 에서는 결과를 완전히 뒤집었다.
════ 결론 ════
1. **D-4 의 처방은 듣는다.** 훅 파일 하나로 발급 → 서빙이 38분에서 1~2초가 됐다.
2. **certbot 출력의 "ran with error output" 을 실패로 읽으면 안 된다.**
nginx 의 경고가 stderr 로 나갔을 뿐이며, 내용은 전부 성공이다.
3. **진단 방법이 재확인됐다** — 마스터 PID 유지 + 워커 PID 교체 = reload.
4. **시계를 섞어 빼면 안 된다.** test-server 는 NTP 가 꺼져 106초 빠르고,
그 사실을 적지 않은 채 계산한 D-4 의 공백은 106초 짧았다.