Files
keycloak-pattern/docs/evidence/b7a-orphan-session/README.md
T
DongHyeonkaandClaude Opus 5 919547a025 docs(b7a): the orphan sessions can be deleted — oauth2-proxy just cannot do it
B-7 stopped at "could not delete the server-side session". The reason it
gave was right: the ticket carries the session id, the ticket is encrypted
with the cookie secret, so after a rotation the proxy cannot work out which
Redis key to remove. But that is a limitation of the proxy, not of Redis.

Measured across two rotations:

- The orphan does expire. TTL falls one second per second and is not
  refreshed by requests (the startup log says refresh:disabled, and
  --cookie-refresh is unset), so it dies exactly one hour after creation.
- An operator can delete it. `redis-cli del` returned 1, dbsize went 2 to 1,
  and the live session answered /oauth2/userinfo with 200 immediately after.
- But nothing in Redis says which key is the orphan. Same name prefix, same
  type, the same 3510 bytes, and the values are encrypted.
- TTL is the only signal, and because it is never refreshed it is an exact
  function of creation time. Anything created before the rotation is an
  orphan. Derived creation time 11:30:26 against the AuthSuccess log line at
  11:30:27 — one second out. The rule was then run and removed the orphan
  while leaving the live session.
- They accumulate: the session that survived the first rotation became the
  orphan of the second.

The caveat is recorded too: turning on --cookie-refresh breaks the
derivation, and at that point flushing and forcing everyone to
re-authenticate is the more honest option.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 20:37:11 +09:00

1.7 KiB
Raw Blame History

B-7a — 고아 세션의 수명과 정리 증거

2026-09-04 11:29 11:34 UTC 해설: docs/experiment-b7a-orphan-session.md

파일 무엇을 보여주는가
01-orphan-lifecycle.txt 회전 2회로 고아가 누적하는 것 · TTL 이 1초/초로 줄고 요청으로 갱신되지 않는 것 · Redis 만으로는 구분 불가(이름·타입·크기 동일, 값 암호화) · redis-cli del 로 지워도 산 세션은 200 · TTL 역산 정리 규칙이 1초 오차로 맞는 것
b7a-live-session-after-orphan-delete.png 고아를 지운 직후 살아있는 세션이 /oauth2/userinfo 를 정상 응답하는 브라우저 화면

핵심 다섯 줄

  1. 「지울 수 없다」는 oauth2-proxy 의 한계이지 Redis 의 한계가 아니다. 프록시는 티켓을 못 풀어 키를 계산 못 한다. 운영자는 키를 직접 안다 — del 반환 1, dbsize 2→1, 산 세션은 그대로 200.
  2. 고아는 반드시 사라진다 — 생성 후 정확히 1시간. TTL 이 요청으로 갱신되지 않기 때문이다(refresh:disabled). 다만 그 1시간은 남는다.
  3. 회전할 때마다 누적한다. 1차 회전을 살아남은 세션이 2차 회전에서 고아가 됐다. 회전 1회 = 그 시점 로그인 사용자 수만큼.
  4. Redis 값으로는 고아를 못 고른다. 이름 접두사·타입·크기(3510바이트)가 같고 값은 암호화되어 있다. TTL 만이 신호다.
  5. 그 TTL 로 정리 규칙이 유도된다. 생성시각 = 지금 (cookie-expire TTL) 이 회전 시각보다 이르면 고아다. 추정 11:30:26 대 로그 11:30:27 — 1초 오차. 실제로 골라 지웠고 산 세션만 남았다.