fix(setup): 실험대에서 35편을 끝까지 밟고 어긋난 명령·결과 31건을 고친다
test-server 를 비우고 다시 세운 뒤 Setup 기록 35편(virtualization 9 ·
keycloak-session-store 26)을 문서에 적힌 명령 그대로 쳤다. 어긋난 자리를
기록과 SSOT 양쪽에 실측과 함께 넣었다.
막히던 것
- 04 의 인증서 경로가 live/hyeonworks.com 이라 nginx 가 [emerg] 로 안 떴다.
실제 계보는 live/auth.hyeonworks.com 이고 「문제가 생기면」은 진단이 거꾸로였다
- 인증서가 와일드카드가 아니다. SAN 이 auth·app1·app2 셋뿐이라 그 밖의 이름은
TLS 에서 끊기고 curl 이 exit 60 · %{http_code} 000 을 낸다. SSOT 안에서
두 문단이 서로 어긋나 있었다
- A-7 14번 ①이 kc-lab-1 에서 여섯 줄 다 실패하는데 마지막 date 만 「차단」을 찍는다
검사가 실패할 수 없던 자리
- B-1 의 세션 키 고르기는 앞 단계가 $KEY 를 채워 둬서 루프가 한 건도 못 맞혀도
통과한다. KEY= 로 비우고 키마다 1/0 을 찍게 바꿨다
- k3s-agent 유닛의 sed -i 는 패턴에 $HOME 이 들어 있어 아무 줄도 안 바꾼 채 성공한다
certbot
- renew --dry-run 의 종료 코드는 성공도 0, 실패도 0, 다른 사유의 실패는 1 이다.
본문의 renew failure(s) 로만 판정할 수 있다
- --dry-run 은 staging 서버를 쓰는데 renewal/*.conf 의 account= 는 운영 계정을
가리킨다. 실패한 dry-run 이 staging 계정을 하나 더 만들어 다음 실행이 계속 멎는다
- 훅을 755 로 놓고 시뮬레이션이 성공해도 Running deploy-hook command 는 안 나온다.
certbot 2.1.0 에는 --run-deploy-hooks 도 없다
- 강제 갱신은 실제로 쳤고 서빙까지 닿았다. serial 06F3E0EF…1373 → 065547…3DF1,
notAfter Dec 3 → Dec 16, nginx worker 2629 4712 → 4745 4754
독자가 칠 수 있는 형태로
- 안 되는 형태가 번호 붙은 단계에 앉아 있던 8곳을 뒤집고, 되는 형태를 ①로 올렸다
- 랩 안에서 공개 이름을 치는 curl 65줄에 --resolve 를 붙였다. 붙인 형태를 실제로
쳐서 문서가 적은 값과 같은지 확인했다
- 힙독·sed -i·echo >>·&&·|| 를 편집기 + 파일 리스팅 + 분할 형태로 바꿨다
- 닫는 코드펜스가 빠져 뒤 200여 줄의 블록 종류가 뒤집혀 있던 곳을 포함해 3곳을 고쳤다
관문: check_body PASS · check_prose error 0 · check_evidence 두 프로젝트 문제 없음 ·
verify-tech-log-tree error 0 · verify-project-layout error 0 · 코드펜스 전수 0건
남은 것: B-0 주입은 keycloak-pattern 저장소의 소스를 고치고 이미지를 다시 구워야
해서 안 했다(unknown).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
4a457afde9
commit
32e39e20aa
@@ -0,0 +1,4 @@
|
||||
[ 60061ms] [ERROR] Failed to load resource: the server responded with a status of 422 (Unprocessable Entity) @ https://hyeonworks.com/api/v1/studio/documents?limit=200:0
|
||||
[ 65184ms] [ERROR] Failed to load resource: the server responded with a status of 422 (Unprocessable Entity) @ https://hyeonworks.com/api/v1/studio/documents?limit=200:0
|
||||
[ 87640ms] [ERROR] Failed to load resource: the server responded with a status of 405 (Method Not Allowed) @ https://hyeonworks.com/api/v1/studio/documents/7e7fb64d-f3a5-4f1e-8351-04596929aaf0:0
|
||||
[ 98850ms] [ERROR] Failed to load resource: the server responded with a status of 404 (Not Found) @ https://hyeonworks.com/api/v1/studio/documents/7e7fb64d-f3a5-4f1e-8351-04596929aaf0:0
|
||||
@@ -0,0 +1,133 @@
|
||||
- generic [ref=f6e3]:
|
||||
- link "본문으로 건너뛰기" [ref=f6e4] [cursor=pointer]:
|
||||
- /url: "#main-content"
|
||||
- banner [ref=f6e5]:
|
||||
- generic [ref=f6e6]:
|
||||
- link "TechLog Studio" [ref=f6e7] [cursor=pointer]:
|
||||
- /url: /studio
|
||||
- text: TechLog
|
||||
- generic [ref=f6e8]: Studio
|
||||
- navigation "Studio 주 탐색" [ref=f6e10]:
|
||||
- generic [ref=f6e11]:
|
||||
- link "작업" [ref=f6e12] [cursor=pointer]:
|
||||
- /url: /studio/documents
|
||||
- link "구조" [ref=f6e13] [cursor=pointer]:
|
||||
- /url: /studio/taxonomy
|
||||
- link "자료" [ref=f6e14] [cursor=pointer]:
|
||||
- /url: /studio/assets
|
||||
- link "게시" [ref=f6e15] [cursor=pointer]:
|
||||
- /url: /studio/publications
|
||||
- generic [ref=f6e16]:
|
||||
- link "작업본" [ref=f6e17] [cursor=pointer]:
|
||||
- /url: /studio/documents
|
||||
- link "새 문서" [ref=f6e18] [cursor=pointer]:
|
||||
- /url: /studio/documents/new
|
||||
- generic [ref=f6e19]:
|
||||
- link "공개 사이트 보기" [ref=f6e20] [cursor=pointer]:
|
||||
- /url: /
|
||||
- button "로그아웃" [ref=f6e21]
|
||||
- main [ref=f6e22]:
|
||||
- generic [ref=f6e23]:
|
||||
- generic [ref=f6e24]:
|
||||
- generic "현재 문서" [ref=f6e25]:
|
||||
- generic [ref=f6e26]: CASE
|
||||
- generic [aria-hidden] [ref=f6e27]: ·
|
||||
- generic [ref=f6e28]: v1
|
||||
- complementary [ref=f6e29]:
|
||||
- heading "작업 상태" [level=2] [ref=f6e30]
|
||||
- status "편집 상태" [ref=f6e31]: 저장됨
|
||||
- generic [ref=f6e33]:
|
||||
- button "저장" [disabled] [ref=f6e34]
|
||||
- button "게시" [ref=f6e35]
|
||||
- main "문서 편집" [ref=f6e36]:
|
||||
- region "문서 기본 정보" [ref=f6e37]:
|
||||
- generic [ref=f6e39]: 검증 기록
|
||||
- heading "제목 없는 작업본" [level=1] [ref=f6e40]:
|
||||
- generic [ref=f6e41]:
|
||||
- generic [ref=f6e42]: 제목
|
||||
- textbox "제목" [ref=f6e43]:
|
||||
- /placeholder: 제목을 입력하세요
|
||||
- generic [ref=f6e44]:
|
||||
- generic [ref=f6e45]: 요약
|
||||
- textbox "요약" [ref=f6e46]:
|
||||
- /placeholder: 이 기록에서 다루는 핵심을 한두 문장으로 적어 주세요.
|
||||
- generic [ref=f6e47]:
|
||||
- generic [ref=f6e48]: 목록 카드에는 약 90자까지 보입니다.
|
||||
- generic [aria-hidden] [ref=f6e49]: 0 / 2000
|
||||
- group [ref=f6e50]:
|
||||
- generic "속성 프로젝트 없음 · 주제 없음" [ref=f6e51] [cursor=pointer]:
|
||||
- generic [ref=f6e52]: 속성
|
||||
- generic [ref=f6e53]: 프로젝트 없음 · 주제 없음
|
||||
- generic [aria-hidden] [ref=f6e54]: 접기
|
||||
- generic [ref=f6e55]:
|
||||
- generic [ref=f6e56]:
|
||||
- generic [ref=f6e57]: 프로젝트
|
||||
- group [ref=f6e59]:
|
||||
- generic "Project" [ref=f6e60] [cursor=pointer]:
|
||||
- generic [ref=f6e61]: 프로젝트 없음
|
||||
- generic [aria-hidden] [ref=f6e62]: ⌄
|
||||
- generic [ref=f6e63]:
|
||||
- generic [ref=f6e64]: 주제
|
||||
- group [ref=f6e66]:
|
||||
- generic "Topic" [ref=f6e67] [cursor=pointer]:
|
||||
- generic [ref=f6e68]: 주제 없음
|
||||
- generic [aria-hidden] [ref=f6e69]: ⌄
|
||||
- generic [ref=f6e70]:
|
||||
- generic [ref=f6e71]: URL 이름
|
||||
- generic [ref=f6e72]:
|
||||
- generic [aria-hidden] [ref=f6e73]: /
|
||||
- textbox "slug" [ref=f6e74]:
|
||||
- /placeholder: 비우면 제목에서 자동 생성
|
||||
- generic [ref=f6e75]: 직접 정하지 않아도 저장할 때 제목을 기준으로 만들어집니다.
|
||||
- group [ref=f6e76]:
|
||||
- generic "연결된 기록 필요할 때 추가 +" [ref=f6e77] [cursor=pointer]:
|
||||
- generic [ref=f6e78]: 연결된 기록
|
||||
- generic [ref=f6e79]: 필요할 때 추가
|
||||
- text: +
|
||||
- text: +
|
||||
- status [ref=f6e80]
|
||||
- region [ref=f6e81]:
|
||||
- generic [ref=f6e82]:
|
||||
- paragraph [ref=f6e83]: CASE
|
||||
- heading "문제와 검증" [level=2] [ref=f6e84]
|
||||
- paragraph [ref=f6e85]: 문제와 결론을 먼저 고정하고, 그 사이의 검증 과정을 본문 블록으로 이어서 작성합니다.
|
||||
- generic [ref=f6e86]:
|
||||
- generic [ref=f6e87]:
|
||||
- generic [ref=f6e88]: 문제
|
||||
- textbox "문제" [ref=f6e89]:
|
||||
- /placeholder: 어떤 현상이 문제였는지 한 문단으로 적어 주세요.
|
||||
- generic [ref=f6e90]:
|
||||
- generic [ref=f6e91]: 결론
|
||||
- textbox "결론" [ref=f6e92]:
|
||||
- /placeholder: 검증을 통해 무엇을 확인했는지 적어 주세요.
|
||||
- group [ref=f6e93]:
|
||||
- generic "검증 세부정보 0개 입력됨" [ref=f6e94] [cursor=pointer]:
|
||||
- generic [ref=f6e95]: 검증 세부정보
|
||||
- generic [ref=f6e96]: 0개 입력됨
|
||||
- generic [ref=f6e97]:
|
||||
- generic [ref=f6e98]:
|
||||
- generic [ref=f6e99]:
|
||||
- text: 본문
|
||||
- paragraph [ref=f6e100]: 작성 화면이 곧 문서입니다. 빈 블록에서 / 를 입력해 제목·목록·코드 블록을 추가할 수 있습니다.
|
||||
- generic [ref=f6e101]:
|
||||
- button "본문에 자료 넣기" [ref=f6e103]
|
||||
- generic [ref=f6e104]:
|
||||
- generic [ref=f6e105]: 업로드 종류
|
||||
- combobox "업로드 종류" [ref=f6e106]:
|
||||
- option "이미지" [selected]
|
||||
- option "다이어그램"
|
||||
- option "첨부파일"
|
||||
- button "Asset 업로드" [ref=f6e107]: 업로드
|
||||
- region "본문" [ref=f6e108]:
|
||||
- generic [ref=f6e110]:
|
||||
- generic "텍스트 블록 작업" [ref=f6e111]:
|
||||
- button "1번째 블록 메뉴" [ref=f6e112]: ⋮⋮
|
||||
- textbox "1번째 텍스트" [ref=f6e114]:
|
||||
- /placeholder: 내용을 입력하거나 / 를 눌러 블록을 추가하세요
|
||||
- generic "1번째 블록 순서와 삭제":
|
||||
- button "위로 이동" [disabled]: ↑
|
||||
- button "아래로 이동" [disabled]: ↓
|
||||
- button "블록 삭제": 삭제
|
||||
- button "+ 블록 추가" [ref=f6e115]
|
||||
- paragraph [ref=f6e116]: 빈 블록에서 / 를 입력하면 제목·목록·코드 같은 블록으로 바꿀 수 있습니다.
|
||||
- paragraph [ref=f6e117]: 검증 기록 작업본을 만들었습니다.
|
||||
@@ -0,0 +1,135 @@
|
||||
- generic [ref=f6e3]:
|
||||
- link "본문으로 건너뛰기" [ref=f6e4] [cursor=pointer]:
|
||||
- /url: "#main-content"
|
||||
- banner [ref=f6e5]:
|
||||
- generic [ref=f6e6]:
|
||||
- link "TechLog Studio" [ref=f6e7] [cursor=pointer]:
|
||||
- /url: /studio
|
||||
- text: TechLog
|
||||
- generic [ref=f6e8]: Studio
|
||||
- navigation "Studio 주 탐색" [ref=f6e10]:
|
||||
- generic [ref=f6e11]:
|
||||
- link "작업" [ref=f6e12] [cursor=pointer]:
|
||||
- /url: /studio/documents
|
||||
- link "구조" [ref=f6e13] [cursor=pointer]:
|
||||
- /url: /studio/taxonomy
|
||||
- link "자료" [ref=f6e14] [cursor=pointer]:
|
||||
- /url: /studio/assets
|
||||
- link "게시" [ref=f6e15] [cursor=pointer]:
|
||||
- /url: /studio/publications
|
||||
- generic [ref=f6e16]:
|
||||
- link "작업본" [ref=f6e17] [cursor=pointer]:
|
||||
- /url: /studio/documents
|
||||
- link "새 문서" [ref=f6e18] [cursor=pointer]:
|
||||
- /url: /studio/documents/new
|
||||
- generic [ref=f6e19]:
|
||||
- link "공개 사이트 보기" [ref=f6e20] [cursor=pointer]:
|
||||
- /url: /
|
||||
- button "로그아웃" [ref=f6e21]
|
||||
- main [ref=f6e22]:
|
||||
- generic [ref=f6e23]:
|
||||
- generic [ref=f6e24]:
|
||||
- generic "현재 문서" [ref=f6e25]:
|
||||
- generic [ref=f6e26]: CASE
|
||||
- generic [aria-hidden] [ref=f6e27]: ·
|
||||
- generic [ref=f6e28]: v2
|
||||
- complementary [ref=f6e29]:
|
||||
- heading "작업 상태" [level=2] [ref=f6e30]
|
||||
- status "편집 상태" [ref=f6e31]: 저장됨
|
||||
- generic [ref=f6e33]:
|
||||
- button "저장" [disabled] [ref=f6e34]
|
||||
- button "게시" [ref=f6e35]
|
||||
- main "문서 편집" [ref=f6e36]:
|
||||
- region "문서 기본 정보" [ref=f6e37]:
|
||||
- generic [ref=f6e39]: 검증 기록
|
||||
- heading "zz 시험 작업본 — 지울 것" [level=1] [ref=f6e118]:
|
||||
- generic [ref=f6e41]:
|
||||
- generic [ref=f6e42]: 제목
|
||||
- textbox "제목" [ref=f6e43]:
|
||||
- /placeholder: 제목을 입력하세요
|
||||
- text: zz 시험 작업본 — 지울 것
|
||||
- generic [ref=f6e44]:
|
||||
- generic [ref=f6e45]: 요약
|
||||
- textbox "요약" [ref=f6e46]:
|
||||
- /placeholder: 이 기록에서 다루는 핵심을 한두 문장으로 적어 주세요.
|
||||
- generic [ref=f6e47]:
|
||||
- generic [ref=f6e48]: 목록 카드에는 약 90자까지 보입니다.
|
||||
- generic [aria-hidden] [ref=f6e49]: 0 / 2000
|
||||
- group [ref=f6e50]:
|
||||
- generic "속성 프로젝트 없음 · 주제 없음" [ref=f6e51] [cursor=pointer]:
|
||||
- generic [ref=f6e52]: 속성
|
||||
- generic [ref=f6e53]: 프로젝트 없음 · 주제 없음
|
||||
- generic [aria-hidden] [ref=f6e54]: 접기
|
||||
- generic [ref=f6e55]:
|
||||
- generic [ref=f6e56]:
|
||||
- generic [ref=f6e57]: 프로젝트
|
||||
- group [ref=f6e59]:
|
||||
- generic "Project" [ref=f6e60] [cursor=pointer]:
|
||||
- generic [ref=f6e61]: 프로젝트 없음
|
||||
- generic [aria-hidden] [ref=f6e62]: ⌄
|
||||
- generic [ref=f6e63]:
|
||||
- generic [ref=f6e64]: 주제
|
||||
- group [ref=f6e66]:
|
||||
- generic "Topic" [ref=f6e67] [cursor=pointer]:
|
||||
- generic [ref=f6e68]: 주제 없음
|
||||
- generic [aria-hidden] [ref=f6e69]: ⌄
|
||||
- generic [ref=f6e70]:
|
||||
- generic [ref=f6e71]: URL 이름
|
||||
- generic [ref=f6e72]:
|
||||
- generic [aria-hidden] [ref=f6e73]: /
|
||||
- textbox "slug" [ref=f6e74]:
|
||||
- /placeholder: 비우면 제목에서 자동 생성
|
||||
- text: zz-siheom-jakeobbon-jiul-geos
|
||||
- generic [ref=f6e75]: 직접 정하지 않아도 저장할 때 제목을 기준으로 만들어집니다.
|
||||
- group [ref=f6e76]:
|
||||
- generic "연결된 기록 필요할 때 추가 +" [ref=f6e77] [cursor=pointer]:
|
||||
- generic [ref=f6e78]: 연결된 기록
|
||||
- generic [ref=f6e79]: 필요할 때 추가
|
||||
- text: +
|
||||
- text: +
|
||||
- status [ref=f6e80]
|
||||
- region [ref=f6e81]:
|
||||
- generic [ref=f6e82]:
|
||||
- paragraph [ref=f6e83]: CASE
|
||||
- heading "문제와 검증" [level=2] [ref=f6e84]
|
||||
- paragraph [ref=f6e85]: 문제와 결론을 먼저 고정하고, 그 사이의 검증 과정을 본문 블록으로 이어서 작성합니다.
|
||||
- generic [ref=f6e86]:
|
||||
- generic [ref=f6e87]:
|
||||
- generic [ref=f6e88]: 문제
|
||||
- textbox "문제" [ref=f6e89]:
|
||||
- /placeholder: 어떤 현상이 문제였는지 한 문단으로 적어 주세요.
|
||||
- generic [ref=f6e90]:
|
||||
- generic [ref=f6e91]: 결론
|
||||
- textbox "결론" [ref=f6e92]:
|
||||
- /placeholder: 검증을 통해 무엇을 확인했는지 적어 주세요.
|
||||
- group [ref=f6e93]:
|
||||
- generic "검증 세부정보 0개 입력됨" [ref=f6e94] [cursor=pointer]:
|
||||
- generic [ref=f6e95]: 검증 세부정보
|
||||
- generic [ref=f6e96]: 0개 입력됨
|
||||
- generic [ref=f6e97]:
|
||||
- generic [ref=f6e98]:
|
||||
- generic [ref=f6e99]:
|
||||
- text: 본문
|
||||
- paragraph [ref=f6e100]: 작성 화면이 곧 문서입니다. 빈 블록에서 / 를 입력해 제목·목록·코드 블록을 추가할 수 있습니다.
|
||||
- generic [ref=f6e101]:
|
||||
- button "본문에 자료 넣기" [ref=f6e103]
|
||||
- generic [ref=f6e104]:
|
||||
- generic [ref=f6e105]: 업로드 종류
|
||||
- combobox "업로드 종류" [ref=f6e106]:
|
||||
- option "이미지" [selected]
|
||||
- option "다이어그램"
|
||||
- option "첨부파일"
|
||||
- button "Asset 업로드" [ref=f6e107]: 업로드
|
||||
- region "본문" [ref=f6e108]:
|
||||
- generic [ref=f6e110]:
|
||||
- generic "텍스트 블록 작업" [ref=f6e111]:
|
||||
- button "1번째 블록 메뉴" [ref=f6e112]: ⋮⋮
|
||||
- textbox "1번째 텍스트" [ref=f6e114]:
|
||||
- /placeholder: 내용을 입력하거나 / 를 눌러 블록을 추가하세요
|
||||
- generic "1번째 블록 순서와 삭제":
|
||||
- button "위로 이동" [disabled]: ↑
|
||||
- button "아래로 이동" [disabled]: ↓
|
||||
- button "블록 삭제": 삭제
|
||||
- button "+ 블록 추가" [ref=f6e115]
|
||||
- paragraph [ref=f6e116]: 빈 블록에서 / 를 입력하면 제목·목록·코드 같은 블록으로 바꿀 수 있습니다.
|
||||
- paragraph [ref=f6e117]: 버전 2으로 저장했습니다.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -165,3 +165,103 @@ SSOT 의 「2026-09-17 재현 — 어디까지 밟았고 무엇이 막았나」
|
||||
|
||||
비밀은 어느 파일에도 값으로 들어 있지 않다. 비밀번호는 길이(19·22)만 적었고, 화면에
|
||||
찍혀 나온 토큰은 <REDACTED n자> 로 가렸다.
|
||||
|
||||
--- 2026-09-17 추가 (인증서 대기 중에 잰 것) ---
|
||||
ext-01..02 밖에서 http 로 닿는지, X-Forwarded-For 가 오는지
|
||||
ext-03..05, ext-09,11 traefik-forwarded-headers.yaml 적용 전/후/되돌린 뒤 앱이 받은 헤더
|
||||
ext-06..07 인증서 상태와 발급 전제 (플러그인 O, cloudflare.ini X)
|
||||
ext-08 http 만으로 어디까지 되는지 (well-known 200 · token 401)
|
||||
ext-10, ext-12 출발지를 덮는 것이 무엇인지 — 호스트 sudo 가 막아 못 가림
|
||||
ext-13 BFF 로그인 체인이 https://auth 로 가서 막히는 것
|
||||
b6-01..09 B-6 키 회전을 문서대로 밟은 기록. 키 조작은 재현, 401/200 판정은 못 냄
|
||||
ext-14 파드에서 공개 이름이 100.83.212.4 로 풀리고 80·443 이 닫혀 있는 것
|
||||
ext-15 CoreDNS 를 *.override 로 고치려다 CrashLoopBackOff 난 기록
|
||||
ext-16 *.server 로 고쳐 넣어 CoreDNS 가 뜬 기록
|
||||
ext-17 고친 뒤 파드에서 엣지 192.168.122.10:80 이 열리는 것
|
||||
d4-01 D-4 5·6·7 절. 7 절이 test-server 에서 빈손이고 nginx 는 엣지에 있다
|
||||
d4a-01 D-4a 5~8 절. 훅 작성·설치·실행과 워커 PID 가 갈리는 것
|
||||
b7-01, b7-02 CoreDNS 를 고친 뒤 oauth2-proxy 가 두드리는 주소가
|
||||
100.83.212.4 에서 192.168.122.10 으로 바뀐 것과, 빌린 Grafana Ingress 복구
|
||||
misc-01 오래 미검증이던 명령 넷 — cookie secret 길이 32·32, R 함수가 빈 출력,
|
||||
certbot renew --dry-run 이 인증서 0장에서 내는 줄
|
||||
b2-01 --scan | xargs del 이 tr -d '\r' 없이도 도는 것과, od -c 로 본 줄 끝
|
||||
b2-02 b2 ②③④ 의 세션 수 — DB 5 와 관리 API 4 가 다른 것
|
||||
b0-01..03 TLS 뒤 b0 상태 확인 — BFF 가 B-1 상태이고 /actuator/beans 가 밖에서 200
|
||||
b1-01..05 B-1 을 끝까지 — 로그인, Redis 키 둘, head -1 이 엉뚱한 키를 집는 것
|
||||
b6-10..18 B-6 을 끝까지 — 대조군 200, 추가는 무중단, 제거 뒤 401/200 이 번갈아 나오는 것
|
||||
b7-03..08 B-7 을 끝까지 — 클라이언트가 없어 Client not found, 만든 뒤 회전까지
|
||||
b7a-01 회전 뒤 남은 고아 세션과 TTL 이 갱신 없이 줄어드는 것
|
||||
d4a-07-dryrun-after-removing-duplicate-staging-account.txt
|
||||
kc-lab-edge 에서 `sudo certbot renew --dry-run`. staging ACME 계정이 둘이라
|
||||
"Please choose an account" 로 멎던 것을, 나중에 생긴 계정 하나를 지운 뒤 다시 잰 것.
|
||||
certbot exit=0 · "Congratulations, all simulated renewals succeeded".
|
||||
실패했을 때도 0 이 나온 적이 있어 종료 코드로는 성공과 실패가 안 갈린다는 근거.
|
||||
|
||||
--- 2026-09-17 저녁 추가 (A-6 관찰·복구를 마저 밟은 기록) ---
|
||||
a6-05-observe-prep.txt A-6 준비 1~5 — 배치와 파드 IP, a6-probe 파드, PW 길이 19,
|
||||
구간별 시간 한 번, 두 노드 20회씩 기준선(k1 44ms · k0 40ms),
|
||||
`grep "^agroal_"` 가 레이블과 값까지 열일곱 줄로 나오는 것
|
||||
a6-06-observe.txt A-6 주입 재현과 관찰 1~5 — flannel.1 세 줄, 카운터 0 pkt → 18 pkt,
|
||||
주입 뒤 k1 1865ms · k0 40ms, 동시 20건 1.87→22.25 초 계단 스무 줄,
|
||||
sort / sort -g 가 같고 sort -g -k2 만 듣는 것, 부하 직후 풀 지표
|
||||
(blocking_time_max 20000.0 · max_used_count 18.0),
|
||||
readiness 프로브 context deadline exceeded, 낙관적 락 로그 0
|
||||
a6-07-revert-checklist.txt A-6 복구와 확인표 여덟 줄 — flannel.1 noqueue, enp1s0 은
|
||||
기본값 fq_codel, 회복 뒤 k1 42ms · k0 39ms, 엔드포인트 주소 둘,
|
||||
awaiting/active 0, 탐침 NotFound, 밖에서 auth.hyeonworks.com 이
|
||||
100.83.212.4 로 풀려 443 이 닫혀 000 이고 --resolve 로 짚으면 200
|
||||
|
||||
--- 2026-09-17 저녁 추가 (A-7 을 1번부터 복구까지 다시 밟은 기록) ---
|
||||
a7-06-prep-and-switch.txt A-7 1~11 — 전환 전 args ["start"], DB 143행, 탐침, 교차 refresh 200,
|
||||
기능 목록이 두 줄, DELETE 144, patch 가 "patched" 를 내는 것,
|
||||
전환 뒤 로그인 5회 200 과 DB (0 rows), 캐시 지표 96줄 원문
|
||||
a7-07-observe.txt A-7 12~15 — 교차 refresh 200, 롤링 재시작 뒤 400 Session not active,
|
||||
14 ① 블록을 kc-lab-1 에서 문서 그대로 쳤을 때 kubectl 이 막히고
|
||||
iptables 가 Bad argument 를 내며 ssh 가 Host key verification failed 이고
|
||||
그래도 "차단" 시각이 찍히는 것, 규칙이 0개인 것, lab host 에서 다시 친
|
||||
형태와 cluster_size 2→1(+75초)·해제 뒤 1→2(+60초), coord=t 둘,
|
||||
대조군 200 · 시험군 400, DB 정지 뒤 500 / 200
|
||||
a7-08-revert-checklist.txt A-7 복구와 확인표 아홉 줄 — args ["start"], git diff 빈 출력,
|
||||
로그인 뒤 세션 행 1, raw PREROUTING 비어 있음, cluster_size 양쪽 2,
|
||||
탐침 NotFound, 밖은 000 이고 --resolve 로 짚으면 200
|
||||
|
||||
--- 2026-09-17 저녁 추가 (B-5 를 1번부터 복구까지 다시 밟은 기록) ---
|
||||
b5-04-baseline.txt B-5 준비 1~5 — 파드 배치, --scan 이 빈 출력(키 0), save 가
|
||||
3600 1 300 100 60 10000 이고 appendonly yes, spec.volumes 에
|
||||
kube-api-access-* 가 함께 있는 것, PVC 둘 Bound, 공개 이름으로는
|
||||
세 경로가 000 이고 --resolve 로 짚으면 200/302/200, health 그룹 셋
|
||||
b5-05-redis-down.txt B-5 주입 1 과 관찰 — Redis 0/0, BFF 로그가 pollConnect 가 아니라
|
||||
ConnectionWatchdog "Cannot reconnect ... Connection refused",
|
||||
bff 둘 1/1 RESTARTS 0, 엔드포인트 true,true, 세 경로 200/000/000,
|
||||
/actuator/health 는 --max-time 10 이면 000 이고 60.046452 초 뒤 503
|
||||
(redis: QueryTimeoutException), token-boundary 는 90초까지 무응답
|
||||
b5-06-persistence.txt B-5 주입 2 와 지속성 시험 — 볼륨을 떼도 spec.volumes 가 빈 줄이
|
||||
아니라 kube-api-access-* 하나, appendonlydir 생성, 파드 삭제 뒤
|
||||
dbsize 0 인데 appendonly 는 yes(매니페스트 args 가 이미 yes),
|
||||
PVC 를 되돌린 뒤 dbsize 4 와 written-on-pvc, 네 지표 시계열 0개
|
||||
b5-07-revert-checklist.txt B-5 복구와 확인표 여덟 줄 — apply 후 redis 1/1, PVC Bound,
|
||||
appendonly yes, bff 둘 1/1, 엔드포인트 둘, b5:* 삭제 1건이고 남은 키는
|
||||
bff:session:sessions 셋, 밖은 000 이고 --resolve 로 짚으면 200
|
||||
d4a-09-dryrun-with-deploy-hook.txt
|
||||
/etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh 를 755 로 놓은 뒤의
|
||||
`sudo certbot renew --dry-run`. 시뮬레이션은 성공(exit=0)했는데
|
||||
"Running deploy-hook command" 줄은 없다 — certbot 2.1.0 의 dry-run 은 deploy 훅을 건너뛴다.
|
||||
d4a-10-dryrun-dns-propagation-flake.txt
|
||||
같은 명령이 바로 앞뒤로는 성공했는데 이 판만 실패한 것. 사유는 DNS 전파로,
|
||||
"During secondary validation: DNS problem: NXDOMAIN looking up TXT for
|
||||
_acme-challenge.auth.hyeonworks.com" · propagation-seconds 기본값 30. certbot exit=1.
|
||||
d4a-11-deploy-hook-not-called-in-dry-run.txt
|
||||
위 판정의 근거 넷 — 훅 파일의 권한·크기, 성공한 출력에서 "deploy-hook" 을 센 값 0,
|
||||
certbot 2.1.0, `--help all` 에 --run-deploy-hooks 가 없다는 것(센 값 0).
|
||||
c2-05-probe-reachability-relive.txt
|
||||
C-2 §5 의 임시 탐침 파드(curlimages/curl:8.11.1)를 2026-09-17 재구성 랩에서 다시 띄운 것.
|
||||
app1.hyeonworks.com 이 192.168.122.10(엣지 게스트)으로 풀리고 HTTPS 200.
|
||||
원래 실행의 100.83.212.4(tailnet 헤어핀)와 주소가 다르다 — 지금은 CoreDNS 의
|
||||
coredns-custom 항목이 그 일을 한다. networkpolicy 는 여전히 없다.
|
||||
d4-01-before-force-renewal.txt / d4-02-force-renewal.txt / d4-03-after-force-renewal.txt
|
||||
D-4·D-4a 의 강제 갱신을 2026-09-17 에 kc-lab-edge 에서 실제로 친 것.
|
||||
01 = 치기 전 archive 목록·nginx worker PID·서빙 인증서의 serial/날짜
|
||||
02 = `sudo certbot renew --force-renewal` 전문. 배포 훅이 돌았고 certbot exit=0
|
||||
03 = 친 뒤의 같은 세 가지 + 세 이름의 HTTPS 응답.
|
||||
serial 06F3E0EF…1373 → 065547991777…3DF1, notAfter Dec 3 → Dec 16,
|
||||
worker 2629 4712 → 4745 4754. 갱신이 서빙까지 닿았다는 근거.
|
||||
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
=== a6 준비 1 ① 배치와 IP ===
|
||||
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
|
||||
bff-5d97897676-nmlqs 1/1 Running 0 150m 10.42.0.22 kc-lab-1 <none> <none>
|
||||
bff-5d97897676-zvfhp 1/1 Running 0 150m 10.42.1.51 kc-lab-2 <none> <none>
|
||||
keycloak-0 1/1 Running 0 121m 10.42.1.64 kc-lab-2 <none> <none>
|
||||
keycloak-1 1/1 Running 0 121m 10.42.0.29 kc-lab-1 <none> <none>
|
||||
oauth2-proxy-d9b587458-7x9jt 1/1 Running 0 55m 10.42.1.78 kc-lab-2 <none> <none>
|
||||
oauth2-proxy-d9b587458-njxdw 1/1 Running 0 55m 10.42.1.79 kc-lab-2 <none> <none>
|
||||
postgres-7b474b88c8-48lrr 1/1 Running 0 160m 10.42.1.46 kc-lab-2 <none> <none>
|
||||
redis-f94bc6dbf-s674z 1/1 Running 0 123m 10.42.1.63 kc-lab-2 <none> <none>
|
||||
=== a6 준비 1 ② 세 값을 셸 변수에 ===
|
||||
K0=10.42.1.64 K1=10.42.0.29 PG=10.42.1.46
|
||||
=== a6 준비 2 ① 탐침 파드를 띄운다 ===
|
||||
pod/a6-probe created
|
||||
exit=0
|
||||
=== a6 준비 2 ② 뜰 때까지 기다린다 ===
|
||||
pod/a6-probe condition met
|
||||
exit=0
|
||||
=== a6 준비 2 ③ 값이 아니라 길이만 확인한다 ===
|
||||
K0=10.42.1.64 K1=10.42.0.29 PW=19자
|
||||
=== a6 준비 3 ① 구간별 시간을 함께 찍는다 ===
|
||||
connect 0.000344 ttfb 0.110990 total 0.111040
|
||||
=== a6 준비 4 ① keycloak-1 에 20회 ===
|
||||
=== a6 준비 4 ② 원본을 먼저 본다 (k1) ===
|
||||
0.044959
|
||||
0.046268
|
||||
0.046746
|
||||
0.041681
|
||||
0.040931
|
||||
0.048671
|
||||
0.040027
|
||||
0.052310
|
||||
0.040426
|
||||
0.039144
|
||||
0.042341
|
||||
0.044985
|
||||
0.042190
|
||||
0.044052
|
||||
0.043110
|
||||
0.044736
|
||||
0.039418
|
||||
0.058032
|
||||
0.040404
|
||||
0.038562
|
||||
=== a6 준비 4 ③ 그다음 줄여서 본다 (k1) ===
|
||||
20회 평균 44 ms
|
||||
=== a6 준비 4 대조군 — $K1 을 $K0 로, 파일 이름도 /tmp/base-k0 으로 ===
|
||||
=== 원본 (k0) ===
|
||||
0.046606
|
||||
0.069418
|
||||
0.044654
|
||||
0.039537
|
||||
0.037198
|
||||
0.038300
|
||||
0.037252
|
||||
0.039732
|
||||
0.036486
|
||||
0.037554
|
||||
0.036501
|
||||
0.035420
|
||||
0.036633
|
||||
0.036898
|
||||
0.052301
|
||||
0.035256
|
||||
0.036421
|
||||
0.034673
|
||||
0.035721
|
||||
0.040525
|
||||
=== 평균 (k0) ===
|
||||
20회 평균 40 ms
|
||||
=== a6 준비 5 ① 지표 이름 목록 ===
|
||||
agroal_invalid_count_total{datasource="default"} 0.0
|
||||
agroal_flush_count_total{datasource="default"} 0.0
|
||||
agroal_leak_detection_count_total{datasource="default"} 0.0
|
||||
agroal_reap_count_total{datasource="default"} 3.0
|
||||
agroal_blocking_time_max_milliseconds{datasource="default"} 112.0
|
||||
agroal_max_used_count{datasource="default"} 3.0
|
||||
agroal_acquire_count_total{datasource="default"} 1908.0
|
||||
agroal_active_count{datasource="default"} 0.0
|
||||
agroal_awaiting_count{datasource="default"} 0.0
|
||||
agroal_blocking_time_average_milliseconds{datasource="default"} 0.0
|
||||
agroal_creation_time_total_milliseconds{datasource="default"} 160.0
|
||||
agroal_creation_time_average_milliseconds{datasource="default"} 32.0
|
||||
agroal_destroy_count_total{datasource="default"} 3.0
|
||||
agroal_available_count{datasource="default"} 2.0
|
||||
agroal_creation_count_total{datasource="default"} 5.0
|
||||
agroal_creation_time_max_milliseconds{datasource="default"} 105.0
|
||||
agroal_blocking_time_total_milliseconds{datasource="default"} 285.0
|
||||
@@ -0,0 +1,225 @@
|
||||
K0=10.42.1.64 K1=10.42.0.29 PG=10.42.1.46
|
||||
=== 주입 전에 flannel.1 에 무엇이 걸려 있나 ===
|
||||
qdisc noqueue 0: root refcnt 2
|
||||
=== 주입 ① 밴드 3개짜리 분류기 ===
|
||||
exit=0
|
||||
=== 주입 ② 3번 밴드에 200ms ===
|
||||
exit=0
|
||||
=== 주입 ③ 출발지가 postgres 인 패킷을 3번 밴드로 ===
|
||||
exit=0
|
||||
=== 주입 ④ 주입 시각 ===
|
||||
17:56:37 주입
|
||||
=== 주입 검증 ① 넣은 직후의 카운터 ===
|
||||
qdisc prio 1: root refcnt 2 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
|
||||
Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
|
||||
backlog 0b 0p requeues 0
|
||||
qdisc netem 30: parent 1:3 limit 1000 delay 200ms
|
||||
Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
|
||||
backlog 0b 0p requeues 0
|
||||
=== 주입 검증 ② 요청을 한 번 보낸다 ===
|
||||
1.855960
|
||||
=== 주입 검증 ③ 다시 센다 ===
|
||||
qdisc netem 30: parent 1:3 limit 1000 delay 200ms
|
||||
Sent 1556 bytes 18 pkt (dropped 0, overlimits 0 requeues 0)
|
||||
backlog 0b 0p requeues 0
|
||||
=== 관찰 1 ① 구간별 시간 (keycloak-1) ===
|
||||
connect 0.000552 ttfb 1.864861 total 1.864966
|
||||
=== 관찰 1 ② 20회 반복 — keycloak-1 ===
|
||||
1.860758
|
||||
1.870170
|
||||
1.872980
|
||||
1.876086
|
||||
1.857782
|
||||
1.859351
|
||||
1.858796
|
||||
1.860100
|
||||
1.864847
|
||||
1.874546
|
||||
1.856623
|
||||
1.870452
|
||||
1.879456
|
||||
1.867865
|
||||
1.861147
|
||||
1.861699
|
||||
1.867978
|
||||
1.862271
|
||||
1.864539
|
||||
1.857025
|
||||
20회 평균 1865 ms 최대 1879 ms
|
||||
=== 관찰 1 ③ 20회 반복 — keycloak-0 (대조군) ===
|
||||
0.039154
|
||||
0.043190
|
||||
0.052382
|
||||
0.037677
|
||||
0.036750
|
||||
0.037014
|
||||
0.038348
|
||||
0.035596
|
||||
0.036738
|
||||
0.038740
|
||||
0.036093
|
||||
0.040349
|
||||
0.038105
|
||||
0.040798
|
||||
0.035273
|
||||
0.042598
|
||||
0.045344
|
||||
0.038030
|
||||
0.046025
|
||||
0.034717
|
||||
20회 평균 40 ms 최대 52 ms
|
||||
=== 관찰 2 ① 동시 20건 ===
|
||||
17:57:39 부하 시작
|
||||
17:58:02 부하 끝
|
||||
=== 관찰 3 ① 부하 직후에 읽는다 ===
|
||||
agroal_blocking_time_max_milliseconds{datasource="default"} 20000.0
|
||||
agroal_max_used_count{datasource="default"} 18.0
|
||||
agroal_acquire_count_total{datasource="default"} 2020.0
|
||||
agroal_active_count{datasource="default"} 0.0
|
||||
agroal_awaiting_count{datasource="default"} 0.0
|
||||
agroal_blocking_time_average_milliseconds{datasource="default"} 114.0
|
||||
agroal_available_count{datasource="default"} 18.0
|
||||
agroal_blocking_time_total_milliseconds{datasource="default"} 230680.0
|
||||
=== 관찰 2 ② 다 모였는지부터 센다 ===
|
||||
20 /tmp/load.txt
|
||||
=== 관찰 2 ③ 원본을 본다 ===
|
||||
200 1.889034
|
||||
200 1.871238
|
||||
200 1.967936
|
||||
200 3.399275
|
||||
200 4.813854
|
||||
200 6.247018
|
||||
200 7.652515
|
||||
200 9.066673
|
||||
200 10.495914
|
||||
200 11.919137
|
||||
200 13.326469
|
||||
200 14.736787
|
||||
200 16.159992
|
||||
200 17.588220
|
||||
200 21.854297
|
||||
200 22.214107
|
||||
200 22.207834
|
||||
200 22.216690
|
||||
200 22.245645
|
||||
200 22.242271
|
||||
=== 관찰 2 ④ 상태 코드와 시간을 나눠 본다 ===
|
||||
20 200
|
||||
1.871238
|
||||
1.889034
|
||||
1.967936
|
||||
3.399275
|
||||
4.813854
|
||||
6.247018
|
||||
7.652515
|
||||
9.066673
|
||||
10.495914
|
||||
11.919137
|
||||
13.326469
|
||||
14.736787
|
||||
16.159992
|
||||
17.588220
|
||||
21.854297
|
||||
22.207834
|
||||
22.214107
|
||||
22.216690
|
||||
22.242271
|
||||
22.245645
|
||||
=== 관찰 2 ⑤ 정렬 방식을 갈라 본다 — sort (사전순) ===
|
||||
200 1.871238
|
||||
200 1.889034
|
||||
200 1.967936
|
||||
200 10.495914
|
||||
200 11.919137
|
||||
200 13.326469
|
||||
200 14.736787
|
||||
200 16.159992
|
||||
200 17.588220
|
||||
200 21.854297
|
||||
200 22.207834
|
||||
200 22.214107
|
||||
200 22.216690
|
||||
200 22.242271
|
||||
200 22.245645
|
||||
200 3.399275
|
||||
200 4.813854
|
||||
200 6.247018
|
||||
200 7.652515
|
||||
200 9.066673
|
||||
=== 관찰 2 ⑤ sort -g ===
|
||||
200 1.871238
|
||||
200 1.889034
|
||||
200 1.967936
|
||||
200 10.495914
|
||||
200 11.919137
|
||||
200 13.326469
|
||||
200 14.736787
|
||||
200 16.159992
|
||||
200 17.588220
|
||||
200 21.854297
|
||||
200 22.207834
|
||||
200 22.214107
|
||||
200 22.216690
|
||||
200 22.242271
|
||||
200 22.245645
|
||||
200 3.399275
|
||||
200 4.813854
|
||||
200 6.247018
|
||||
200 7.652515
|
||||
200 9.066673
|
||||
=== 관찰 2 ⑥ sort -g -k2 ===
|
||||
200 1.871238
|
||||
200 1.889034
|
||||
200 1.967936
|
||||
200 3.399275
|
||||
200 4.813854
|
||||
200 6.247018
|
||||
200 7.652515
|
||||
200 9.066673
|
||||
200 10.495914
|
||||
200 11.919137
|
||||
200 13.326469
|
||||
200 14.736787
|
||||
200 16.159992
|
||||
200 17.588220
|
||||
200 21.854297
|
||||
200 22.207834
|
||||
200 22.214107
|
||||
200 22.216690
|
||||
200 22.242271
|
||||
200 22.245645
|
||||
=== 관찰 4 ① 최근 이벤트 ===
|
||||
57m Normal ScalingReplicaSet deployment/oauth2-proxy Scaled up replica set oauth2-proxy-d9b587458 from 0 to 1
|
||||
57m Normal Pulled pod/oauth2-proxy-d9b587458-7x9jt Container image "quay.io/oauth2-proxy/oauth2-proxy:v7.7.1" already present on machine and can be accessed by the pod
|
||||
57m Normal SuccessfulCreate replicaset/oauth2-proxy-d9b587458 Created pod: oauth2-proxy-d9b587458-7x9jt
|
||||
57m Normal Created pod/oauth2-proxy-d9b587458-7x9jt Container created
|
||||
57m Normal Started pod/oauth2-proxy-d9b587458-7x9jt Container started
|
||||
57m Normal Created pod/oauth2-proxy-d9b587458-njxdw Container created
|
||||
57m Normal Killing pod/oauth2-proxy-6c56c4c94f-gq484 Stopping container oauth2-proxy
|
||||
57m Normal SuccessfulDelete replicaset/oauth2-proxy-6c56c4c94f Deleted pod: oauth2-proxy-6c56c4c94f-gq484
|
||||
57m Normal Pulled pod/oauth2-proxy-d9b587458-njxdw Container image "quay.io/oauth2-proxy/oauth2-proxy:v7.7.1" already present on machine and can be accessed by the pod
|
||||
57m Normal ScalingReplicaSet deployment/oauth2-proxy Scaled up replica set oauth2-proxy-d9b587458 from 1 to 2
|
||||
57m Normal Started pod/oauth2-proxy-d9b587458-njxdw Container started
|
||||
57m Normal SuccessfulCreate replicaset/oauth2-proxy-d9b587458 Created pod: oauth2-proxy-d9b587458-njxdw
|
||||
57m Normal ScalingReplicaSet deployment/oauth2-proxy Scaled down replica set oauth2-proxy-6c56c4c94f from 2 to 1
|
||||
57m Normal SuccessfulDelete replicaset/oauth2-proxy-6c56c4c94f Deleted pod: oauth2-proxy-6c56c4c94f-szr6j
|
||||
57m Normal ScalingReplicaSet deployment/oauth2-proxy Scaled down replica set oauth2-proxy-6c56c4c94f from 1 to 0
|
||||
57m Normal Killing pod/oauth2-proxy-6c56c4c94f-szr6j Stopping container oauth2-proxy
|
||||
115s Normal Created pod/a6-probe Container created
|
||||
115s Normal Pulled pod/a6-probe Container image "curlimages/curl:8.11.1" already present on machine and can be accessed by the pod
|
||||
114s Normal Started pod/a6-probe Container started
|
||||
19s Warning Unhealthy pod/keycloak-1 Readiness probe failed: Get "http://10.42.0.29:9000/health/ready": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
|
||||
=== 관찰 4 ② 파드 상태 ===
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
a6-probe 1/1 Running 0 115s
|
||||
bff-5d97897676-nmlqs 1/1 Running 0 152m
|
||||
bff-5d97897676-zvfhp 1/1 Running 0 152m
|
||||
keycloak-0 1/1 Running 0 123m
|
||||
keycloak-1 1/1 Running 0 123m
|
||||
oauth2-proxy-d9b587458-7x9jt 1/1 Running 0 57m
|
||||
oauth2-proxy-d9b587458-njxdw 1/1 Running 0 57m
|
||||
postgres-7b474b88c8-48lrr 1/1 Running 0 162m
|
||||
redis-f94bc6dbf-s674z 1/1 Running 0 125m
|
||||
=== 관찰 5 ① 미검증 — 충돌 로그를 센다 ===
|
||||
0
|
||||
exit=1
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
=== 복구 1 ① 해제 시각 ===
|
||||
17:58:20 해제
|
||||
=== 복구 1 ② root 를 지운다 ===
|
||||
exit=0
|
||||
=== 복구 1 ③ 무엇이 남았는지 본다 ===
|
||||
qdisc noqueue 0: root refcnt 2
|
||||
=== 복구 2 회복 확인 — 20회 반복 측정을 그대로 다시 (keycloak-1) ===
|
||||
keycloak-1 20회 평균 42 ms
|
||||
=== 복구 2 회복 확인 — keycloak-0 ===
|
||||
keycloak-0 20회 평균 39 ms
|
||||
=== 확인표 qdisc (flannel.1) ===
|
||||
qdisc noqueue 0: root refcnt 2
|
||||
=== 확인표 (물리 쪽도) enp1s0 ===
|
||||
qdisc fq_codel 0: root refcnt 2 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64
|
||||
=== 확인표 파드 ===
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
a6-probe 1/1 Running 0 2m9s
|
||||
bff-5d97897676-nmlqs 1/1 Running 0 152m
|
||||
bff-5d97897676-zvfhp 1/1 Running 0 152m
|
||||
keycloak-0 1/1 Running 0 123m
|
||||
keycloak-1 1/1 Running 0 123m
|
||||
oauth2-proxy-d9b587458-7x9jt 1/1 Running 0 57m
|
||||
oauth2-proxy-d9b587458-njxdw 1/1 Running 0 57m
|
||||
postgres-7b474b88c8-48lrr 1/1 Running 0 162m
|
||||
redis-f94bc6dbf-s674z 1/1 Running 0 125m
|
||||
=== 확인표 Service ===
|
||||
NAME ADDRESSTYPE PORTS ENDPOINTS AGE
|
||||
keycloak-lxk8h IPv4 8080 10.42.0.29,10.42.1.64 4h22m
|
||||
=== 확인표 풀 ===
|
||||
agroal_active_count{datasource="default"} 0.0
|
||||
agroal_awaiting_count{datasource="default"} 0.0
|
||||
=== 탐침 파드를 지운다 ===
|
||||
pod "a6-probe" deleted from keycloak-lab namespace
|
||||
=== 확인표 탐침 파드 ===
|
||||
Error from server (NotFound): pods "a6-probe" not found
|
||||
exit=1
|
||||
=== 확인표 밖 ===
|
||||
000
|
||||
=== 확인표 밖 — 같은 줄을 -s 없이 다시 ===
|
||||
curl: (7) Failed to connect to auth.hyeonworks.com:443 after 3 ms: Could not connect to server
|
||||
000
|
||||
exit=7
|
||||
=== 이름이 무엇으로 풀리는가 ===
|
||||
100.83.212.4 auth.hyeonworks.com
|
||||
=== 엣지 쪽에서 같은 줄 ===
|
||||
000
|
||||
exit=7
|
||||
=== 엣지 주소로 직접 (이름만 헤더로) ===
|
||||
200
|
||||
exit=0
|
||||
=== http 로 ===
|
||||
301
|
||||
exit=0
|
||||
+172
File diff suppressed because one or more lines are too long
@@ -0,0 +1,148 @@
|
||||
=== a7 12 로그인하고 반대 노드에서 갱신한다 ===
|
||||
200
|
||||
=== a7 13 ① 토큰을 담고 access token 의 클레임을 편다 ===
|
||||
{"exp":1789635852,"iat":1789635792,"jti":"onltro:81f8f0e3-06aa-890c-3b2b-bc1080d617bd","iss":"https://auth.hyeonworks.com/realms/master","typ":"Bearer","azp":"admin-cli","sid":"7HNHaJ1RxIKwxI-CUn86vUSe","scope":"profile email
|
||||
=== a7 13 ② 시각을 남기고 롤링 재시작을 건다 ===
|
||||
18:04:47 재시작
|
||||
statefulset.apps/keycloak restarted
|
||||
Waiting for partitioned roll out to finish: 0 out of 2 new pods have been updated...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for partitioned roll out to finish: 1 out of 2 new pods have been updated...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for 1 pods to be ready...
|
||||
partitioned roll out complete: 2 new pods have been updated...
|
||||
=== a7 13 ③ 롤아웃 뒤 IP 를 다시 잡는다 ===
|
||||
10.42.1.84 10.42.0.38
|
||||
=== a7 13 ④ 재시작 전 토큰으로 갱신을 시도한다 ===
|
||||
{"error":"invalid_grant","error_description":"Session not active"}
|
||||
400
|
||||
=== (참고) 재시작 뒤 sessions 캐시 ===
|
||||
"pod":"keycloak-1"}
|
||||
"151"]}
|
||||
"pod":"keycloak-0"}
|
||||
"0"]}]}}
|
||||
######## a7 14 ① 을 kc-lab-1 에서 문서 그대로 친 결과
|
||||
time="2026-09-17T09:04:49Z" level=warning msg="Unable to read /etc/rancher/k3s/k3s.yaml, please start server with --write-kubeconfig-mode or --write-kubeconfig-group to modify kube config permissions"
|
||||
error: error loading config file "/etc/rancher/k3s/k3s.yaml": open /etc/rancher/k3s/k3s.yaml: permission denied
|
||||
time="2026-09-17T09:04:49Z" level=warning msg="Unable to read /etc/rancher/k3s/k3s.yaml, please start server with --write-kubeconfig-mode or --write-kubeconfig-group to modify kube config permissions"
|
||||
error: error loading config file "/etc/rancher/k3s/k3s.yaml": open /etc/rancher/k3s/k3s.yaml: permission denied
|
||||
Bad argument `7800'
|
||||
Try `iptables -h' or 'iptables --help' for more information.
|
||||
Bad argument `57800'
|
||||
Try `iptables -h' or 'iptables --help' for more information.
|
||||
Host key verification failed.
|
||||
Host key verification failed.
|
||||
09:04:49 차단
|
||||
remote_exit=0
|
||||
######## 그 뒤 두 노드의 raw PREROUTING — 규칙이 하나도 안 들어갔다
|
||||
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
|
||||
pkts bytes target prot opt in out source destination
|
||||
--- kc-lab-2 ---
|
||||
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
|
||||
pkts bytes target prot opt in out source destination
|
||||
K0=10.42.1.84 K1=10.42.0.38
|
||||
=== a7 14 ① 양쪽 노드에 raw DROP 을 넣는다 (lab host 에서 두 노드 모두 ssh 한 줄로) ===
|
||||
18:06:40 차단
|
||||
=== a7 14 ② 두 노드의 규칙과 카운터를 본다 ===
|
||||
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
|
||||
pkts bytes target prot opt in out source destination
|
||||
0 0 DROP 6 -- * * 0.0.0.0/0 10.42.0.38 tcp dpt:57800
|
||||
0 0 DROP 6 -- * * 0.0.0.0/0 10.42.0.38 tcp dpt:7800
|
||||
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
|
||||
pkts bytes target prot opt in out source destination
|
||||
0 0 DROP 6 -- * * 0.0.0.0/0 10.42.1.84 tcp dpt:57800
|
||||
2 116 DROP 6 -- * * 0.0.0.0/0 10.42.1.84 tcp dpt:7800
|
||||
=== a7 14 ③ 두 노드가 각각 아는 멤버 수를 본다 ===
|
||||
+25초
|
||||
"pod":"keycloak-1"}
|
||||
"2"]}
|
||||
"pod":"keycloak-0"}
|
||||
"2"]}]}}
|
||||
+50초
|
||||
"pod":"keycloak-1"}
|
||||
"2"]}
|
||||
"pod":"keycloak-0"}
|
||||
"2"]}]}}
|
||||
+75초
|
||||
"pod":"keycloak-1"}
|
||||
"1"]}
|
||||
"pod":"keycloak-0"}
|
||||
"1"]}]}}
|
||||
+100초
|
||||
"pod":"keycloak-1"}
|
||||
"1"]}
|
||||
"pod":"keycloak-0"}
|
||||
"1"]}]}}
|
||||
+125초
|
||||
"pod":"keycloak-1"}
|
||||
"1"]}
|
||||
"pod":"keycloak-0"}
|
||||
"1"]}]}}
|
||||
=== a7 14 ② 다시 — 카운터가 올라갔나 ===
|
||||
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
|
||||
pkts bytes target prot opt in out source destination
|
||||
20 1184 DROP 6 -- * * 0.0.0.0/0 10.42.0.38 tcp dpt:57800
|
||||
2 120 DROP 6 -- * * 0.0.0.0/0 10.42.0.38 tcp dpt:7800
|
||||
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
|
||||
pkts bytes target prot opt in out source destination
|
||||
0 0 DROP 6 -- * * 0.0.0.0/0 10.42.1.84 tcp dpt:57800
|
||||
22 4002 DROP 6 -- * * 0.0.0.0/0 10.42.1.84 tcp dpt:7800
|
||||
=== a7 14 ④ 디스커버리 테이블의 코디네이터를 센다 ===
|
||||
name | ip | coord
|
||||
------------------+-----------------+-------
|
||||
keycloak-0-41852 | 10.42.1.84:7800 | t
|
||||
keycloak-1-65118 | 10.42.0.38:7800 | t
|
||||
(2 rows)
|
||||
|
||||
|
||||
[exited with code 0]
|
||||
K0=10.42.1.84 K1=10.42.0.38
|
||||
=== a7 14 ⑤ 대조군 — 로그인한 노드에서 갱신한다 ===
|
||||
same-node 200
|
||||
=== a7 14 ⑥ 시험군 — 새로 로그인해서 반대 노드에서 갱신한다 ===
|
||||
{"error":"invalid_grant","error_description":"Session not active"}
|
||||
cross-node 400
|
||||
=== a7 14 차단을 푼다 (두 노드) ===
|
||||
18:09:09 해제
|
||||
Chain PREROUTING (policy ACCEPT)
|
||||
target prot opt source destination
|
||||
Chain PREROUTING (policy ACCEPT)
|
||||
target prot opt source destination
|
||||
=== 양쪽 cluster_size 가 2 로 돌아오는가 ===
|
||||
+20초
|
||||
"pod":"keycloak-1"}
|
||||
"1"]}
|
||||
"pod":"keycloak-0"}
|
||||
"1"]}]}}
|
||||
+40초
|
||||
"pod":"keycloak-1"}
|
||||
"1"]}
|
||||
"pod":"keycloak-0"}
|
||||
"1"]}]}}
|
||||
+60초
|
||||
"pod":"keycloak-1"}
|
||||
"2"]}
|
||||
"pod":"keycloak-0"}
|
||||
"2"]}]}}
|
||||
둘 다 2
|
||||
|
||||
[exited with code 0]
|
||||
K0=10.42.1.84 K1=10.42.0.38
|
||||
=== a7 15 ① 로그인만 해서 /tmp/rt 를 채운다 ===
|
||||
{"exp":1789636190,"iat":1789636130,"jti":"onltro:66c69a56-72aa-998d-3a65-669945a48ac9","iss":"https://auth.hyeonworks.com/realms/master","typ":"Bearer","azp":"admin-cli","sid":"x8EWkde54QSEnlY-lDKizez3","scope":"profile email
|
||||
=== a7 15 ② 시각을 남기고 DB 를 0 replica 로 내린다 ===
|
||||
18:10:24 정지
|
||||
deployment.apps/postgres scaled
|
||||
pod/postgres-7b474b88c8-48lrr condition met
|
||||
=== a7 15 ③ 캐시를 가진 노드에서 refresh ===
|
||||
500
|
||||
=== a7 15 ④ 새 로그인 ===
|
||||
200
|
||||
=== a7 15 ⑤ DB 를 다시 올린다 ===
|
||||
deployment.apps/postgres scaled
|
||||
Waiting for deployment "postgres" rollout to finish: 0 out of 1 new replicas have been updated...
|
||||
Waiting for deployment "postgres" rollout to finish: 0 of 1 updated replicas are available...
|
||||
deployment "postgres" successfully rolled out
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
=== a7 복구 ① 두 노드의 raw 규칙을 확인한다 ===
|
||||
Chain PREROUTING (policy ACCEPT)
|
||||
target prot opt source destination
|
||||
Chain PREROUTING (policy ACCEPT)
|
||||
target prot opt source destination
|
||||
=== a7 복구 ② DB 파드를 본다 ===
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
postgres-7b474b88c8-kvt96 1/1 Running 0 30s
|
||||
=== a7 복구 ③ args 를 기본값으로 되돌린다 ===
|
||||
statefulset.apps/keycloak patched
|
||||
18:10:55 원복
|
||||
Waiting for partitioned roll out to finish: 0 out of 2 new pods have been updated...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for partitioned roll out to finish: 1 out of 2 new pods have been updated...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for 1 pods to be ready...
|
||||
partitioned roll out complete: 2 new pods have been updated...
|
||||
=== a7 복구 ④ 매니페스트의 변경을 확인한다 (patch 로 바꿨으므로 파일은 안 건드렸다) ===
|
||||
git diff exit=0 (출력 없음이면 변경 없음)
|
||||
=== a7 복구 ⑤ 새 IP 로 탐침을 다시 띄운다 ===
|
||||
pod "a7-probe" deleted from keycloak-lab namespace
|
||||
K0=10.42.1.86 K1=10.42.0.39
|
||||
pod/a7-probe created
|
||||
pod/a7-probe condition met
|
||||
=== a7 복구 ⑥ 로그인을 한 번 한다 (상태 코드만) ===
|
||||
200
|
||||
=== a7 복구 ⑦ 로그인 뒤 온라인 세션 행을 센다 ===
|
||||
1
|
||||
=== 확인표 args ===
|
||||
["start"]
|
||||
=== 확인표 파드 ===
|
||||
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
|
||||
a7-probe 1/1 Running 0 2s 10.42.1.87 kc-lab-2 <none> <none>
|
||||
bff-5d97897676-nmlqs 1/1 Running 0 166m 10.42.0.22 kc-lab-1 <none> <none>
|
||||
bff-5d97897676-zvfhp 1/1 Running 0 166m 10.42.1.51 kc-lab-2 <none> <none>
|
||||
keycloak-0 1/1 Running 0 72s 10.42.1.86 kc-lab-2 <none> <none>
|
||||
keycloak-1 1/1 Running 0 105s 10.42.0.39 kc-lab-1 <none> <none>
|
||||
oauth2-proxy-d9b587458-7x9jt 1/1 Running 0 72m 10.42.1.78 kc-lab-2 <none> <none>
|
||||
oauth2-proxy-d9b587458-njxdw 1/1 Running 0 71m 10.42.1.79 kc-lab-2 <none> <none>
|
||||
postgres-7b474b88c8-kvt96 1/1 Running 0 2m18s 10.42.1.85 kc-lab-2 <none> <none>
|
||||
redis-f94bc6dbf-s674z 1/1 Running 0 139m 10.42.1.63 kc-lab-2 <none> <none>
|
||||
=== 확인표 DB ===
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
postgres-7b474b88c8-kvt96 1/1 Running 0 2m18s
|
||||
=== 확인표 iptables ===
|
||||
Chain PREROUTING (policy ACCEPT)
|
||||
target prot opt source destination
|
||||
Chain PREROUTING (policy ACCEPT)
|
||||
target prot opt source destination
|
||||
=== 확인표 클러스터 ===
|
||||
"pod":"keycloak-1"}
|
||||
"2"]}
|
||||
"pod":"keycloak-0"}
|
||||
"2"]}]}}
|
||||
=== a7 복구 ⑧ 탐침 파드를 지운다 ===
|
||||
pod "a7-probe" deleted from keycloak-lab namespace
|
||||
=== 확인표 탐침 파드 ===
|
||||
Error from server (NotFound): pods "a7-probe" not found
|
||||
=== 확인표 밖 ===
|
||||
000
|
||||
200
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
=== 지금 bff 가 어느 편의 상태인가 ===
|
||||
2 replicas, image=keycloak-pattern-bff:lab
|
||||
--- SessionRepository 계열 빈이 있나 (b0 2절과 같은 질문)
|
||||
@@ -0,0 +1,10 @@
|
||||
=== actuator/beans 가 응답하나 ===
|
||||
sh: curl: not found
|
||||
command terminated with exit code 127
|
||||
--- 빈 수
|
||||
sh: curl: not found
|
||||
command terminated with exit code 127
|
||||
0
|
||||
--- session 이 이름에 든 빈
|
||||
sh: curl: not found
|
||||
command terminated with exit code 127
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
=== b0 1단계 ①②③ (문서 형태) ===
|
||||
bff-5d97897676-nmlqs
|
||||
155395 /tmp/beans.json
|
||||
{"contexts":{"keycloak-bff":{"beans":{"applicationTaskExecutor":{"aliases":["bootstrapExecutor"],"scope":"singleton","type":"org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor","resource
|
||||
|
||||
=== 밖에서 /actuator/beans 는 정말 Bad Gateway 인가 (TLS 가 선 지금) ===
|
||||
code=200 size=155395
|
||||
{"contexts":{"keycloak-bff":{"beans":{"applicationTaskExecutor":{"aliases":["bootstrapExecutor"],"scope":"singleton","ty
|
||||
|
||||
=== b0 2단계 저장소 계열 빈 ===
|
||||
236
|
||||
"org.springframework.boot.autoconfigure.session.RedisSessionConfiguration"
|
||||
"org.springframework.boot.autoconfigure.session.RedisSessionProperties"
|
||||
"org.springframework.boot.autoconfigure.session.SessionRepositoryFilterConfiguration"
|
||||
"org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration"
|
||||
"org.springframework.session.data.redis.RedisSessionRepository"
|
||||
"org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"
|
||||
"org.springframework.session.web.http.SessionRepositoryFilter"
|
||||
"sessionRepository"
|
||||
"sessionRepositoryFilterRegistration"
|
||||
"springBootSessionRepositoryCustomizer"
|
||||
"springSessionRepositoryFilter"
|
||||
@@ -0,0 +1,11 @@
|
||||
=== ① 로그인 페이지까지 따라간다 ===
|
||||
도착: https://app1.hyeonworks.com/...
|
||||
상태: 0 개의 form 단서
|
||||
form action: ...
|
||||
|
||||
=== ② 자격을 제출한다 ===
|
||||
결과: 000
|
||||
|
||||
=== ③ 토큰 경계를 읽는다 (b0 5절 · b1 관찰) ===
|
||||
|
||||
=== ④ 쿠키 항아리에 무엇이 남았나 (값은 길이만) ===
|
||||
@@ -0,0 +1,20 @@
|
||||
=== ①/oauth2/authorization/keycloak 로 시작 ===
|
||||
�착: https://auth.hyeonworks.com/realms/keycloak-patterns/protocol/openid-connect/auth?response
|
||||
바�트: 7021
|
||||
form action: https://auth.hyeonworks.com/realms/keycloak-patterns/login-actions/authenticate?session_code=ySbuIX9Mo31v8XcKl
|
||||
|
||||
=== â‘¡ ìž�격 ì œì¶œ ===
|
||||
ê²°ê³¼: 200 https://app1.hyeonworks.com/
|
||||
본문 앞: <!doctype html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AP3 Â
|
||||
|
||||
=== â‘¢ í† í�° 경계 ===
|
||||
{"pattern":"AP3-backend-for-frontend","principal":"labuser","accessTokenStoredOnServer":true,"refreshTokenStoredOnServer":true,"browserTokenCount":0,"csrfProtectionEnabled":true}
|
||||
|
||||
=== â‘£ ì¿ í‚¤ (ê°’ì�€ 길ì�´ë§Œ) ===
|
||||
auth.hyeonworks.com KC_AUTH_SESSION_HASH 66�
|
||||
auth.hyeonworks.com KEYCLOAK_SESSION 64�
|
||||
@@ -0,0 +1,20 @@
|
||||
=== 쿠키 전부 (HttpOnly 포함 · 값은 길이만) ===
|
||||
auth.hyeonworks.com KC_AUTH_SESSION_HASH 66자
|
||||
auth.hyeonworks.com AUTH_SESSION_ID 165자
|
||||
app1.hyeonworks.com AP3_SESSION 48자
|
||||
auth.hyeonworks.com KEYCLOAK_IDENTITY 594자
|
||||
auth.hyeonworks.com KEYCLOAK_SESSION 64자
|
||||
|
||||
=== b1 관찰 2 · Redis 를 직접 연다 ===
|
||||
dbsize=2
|
||||
bff:session:sessions:b66634a2-1381-4071-8ceb-0a006fbe1327 type=hash ttl=1783
|
||||
bff:session:sessions:c5f7b0c7-cd17-4749-bf3e-6d42c814bb1c type=hash ttl=1790
|
||||
|
||||
=== b1 관찰 3 · 필드와 바이트 ===
|
||||
키: bff:session:sessions:b66634a2-1381-4071-8ceb-0a006fbe1327
|
||||
--- 필드 이름 (값은 안 본다)
|
||||
sessionAttr:SPRING_SECURITY_SAVED_REQUEST
|
||||
maxInactiveInterval
|
||||
creationTime
|
||||
lastAccessedTime
|
||||
--- 전체 바이트: 2224
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
=== b1 관찰 2 ① 문서 그대로 ===
|
||||
2
|
||||
bff:session:sessions:b66634a2-1381-4071-8ceb-0a006fbe1327
|
||||
bff:session:sessions:c5f7b0c7-cd17-4749-bf3e-6d42c814bb1c
|
||||
|
||||
=== b1 관찰 2 ② 문서 그대로 (head -1) ===
|
||||
bff:session:sessions:b66634a2-1381-4071-8ceb-0a006fbe1327
|
||||
--- 그 키의 타입과 필드
|
||||
hash
|
||||
sessionAttr:SPRING_SECURITY_SAVED_REQUEST
|
||||
maxInactiveInterval
|
||||
creationTime
|
||||
lastAccessedTime
|
||||
--- TTL: 1771
|
||||
|
||||
=== 키가 둘인데 각각 무엇을 담고 있나 ===
|
||||
bff:session:sessions:b66634a2-1381-4071-8ceb-0a006fbe1327
|
||||
sessionAttr:SPRING_SECURITY_SAVED_REQUEST
|
||||
maxInactiveInterval
|
||||
creationTime
|
||||
lastAccessedTime
|
||||
bff:session:sessions:c5f7b0c7-cd17-4749-bf3e-6d42c814bb1c
|
||||
lastAccessedTime
|
||||
maxInactiveInterval
|
||||
sessionAttr:org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizationRequestRepository.AUTHORIZATION_REQUEST
|
||||
creationTime
|
||||
sessionAttr:SPRING_SECURITY_LAST_EXCEPTION
|
||||
sessionAttr:SPRING_SECURITY_CONTEXT
|
||||
@@ -0,0 +1,6 @@
|
||||
=== SPRING_SECURITY_CONTEXT 를 가진 키를 골라서 관찰 3 ② ===
|
||||
인증된 세션 키: bff:session:sessions:c5f7b0c7-cd17-4749-bf3e-6d42c814bb1c
|
||||
TTL: 1767
|
||||
--- --no-raw hgetall 앞 두 줄
|
||||
1) "lastAccessedTime"
|
||||
2) "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01\xa0\xaeW\xad\xa3"
|
||||
@@ -0,0 +1,20 @@
|
||||
=== 시험용 키 둘을 넣는다 ===
|
||||
OK
|
||||
OK
|
||||
bff:session:sessions:e22840df-61f2-4126-99a9-7f1dd7fddcc1
|
||||
bff:session:probe2
|
||||
bff:session:sessions:8a132645-4322-4b73-b97a-e3604ad1e766
|
||||
bff:session:sessions:503e5c35-4e15-4d59-a034-5b9decc0ec54
|
||||
bff:session:probe1
|
||||
|
||||
=== b2 ② 를 문서 그대로 (tr -d '
|
||||
' 없이) ===
|
||||
5
|
||||
|
||||
=== 정말 지워졌나 ===
|
||||
(위가 비면 지워진 것)
|
||||
|
||||
=== 스캔 출력에 CR 이 실제로 붙어 오나 ===
|
||||
0000000 b f f : s e s s i o n : p r o b
|
||||
0000020 e 3 \n
|
||||
0000023
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
=== b2 ② 토큰 행 수 ===
|
||||
count
|
||||
-------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
|
||||
=== b2 ③ Keycloak 세션을 DB 쪽에서 센다 ===
|
||||
offline_flag | count
|
||||
--------------+-------
|
||||
0 | 5
|
||||
(1 row)
|
||||
|
||||
|
||||
=== b2 ④ 관리 API 로 세는 형태 ===
|
||||
[ {
|
||||
"offline" : "0",
|
||||
"clientId" : "bff-confidential",
|
||||
"active" : "4",
|
||||
"id" : "7ae3362a-2bed-4902-b6af-d7307ea4ad0b"
|
||||
} ]
|
||||
@@ -0,0 +1,13 @@
|
||||
=== B-2 ② 로그인 뒤 토큰 행 수 ===
|
||||
count
|
||||
-------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
|
||||
=== 빈 목록에 JDBC 계열이 있나 ===
|
||||
"authorizedClientRepository"
|
||||
"authorizedClientService"
|
||||
"org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager"
|
||||
"org.springframework.security.oauth2.client.JdbcOAuth2AuthorizedClientService"
|
||||
"org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository"
|
||||
@@ -0,0 +1,18 @@
|
||||
=== B-2 7단계 ① 행 수·해시·발급 시각 ===
|
||||
client_registration_id | principal_name | access_token_issued_at | at_md5
|
||||
------------------------+----------------+----------------------------+----------------------------------
|
||||
keycloak | labuser | 2026-09-17 08:01:46.958592 | 722769ac041a42164d08060e5446d02b
|
||||
(1 row)
|
||||
|
||||
|
||||
=== B-2 7단계 ② 두 토큰의 바이트 수 ===
|
||||
client_registration_id | principal_name | access_token_type | at_len | rt_len
|
||||
------------------------+----------------+-------------------+--------+--------
|
||||
keycloak | labuser | Bearer | 1437 | 744
|
||||
(1 row)
|
||||
|
||||
|
||||
=== B-2 관찰 2 ① rt 바이트 수 ===
|
||||
744
|
||||
=== B-2 관찰 2 ② 앞 36자만 (자격증명이라 36자에서 끊는다) ===
|
||||
eyJhbGciOiJIUzUxMiIsInR5cCIgOiAiSldU
|
||||
@@ -0,0 +1,12 @@
|
||||
=== 대조군 (브라우저 A) ===
|
||||
행 수 1
|
||||
at_md5 722769ac041a42164d08060e5446d02b
|
||||
|
||||
=== 주입: 새 브라우저(B)로 같은 사용자 로그인 ===
|
||||
로그인 폼을 거쳐 200
|
||||
{"pattern":"AP3-backend-for-frontend","principal":"labuser","accessTokenStoredOnServer":tr
|
||||
|
||||
=== 관찰 1: 행이 늘었나 덮어써졌나 ===
|
||||
행 수 1
|
||||
at_md5 5c38b11f27f490ea1d9ee07e73aef2b2
|
||||
발급 시각 2026-09-17 08:05:52.156416
|
||||
@@ -0,0 +1,43 @@
|
||||
=== b5 1 파드 배치를 본다 ===
|
||||
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
|
||||
bff-5d97897676-nmlqs 1/1 Running 0 168m 10.42.0.22 kc-lab-1 <none> <none>
|
||||
bff-5d97897676-zvfhp 1/1 Running 0 168m 10.42.1.51 kc-lab-2 <none> <none>
|
||||
keycloak-0 1/1 Running 0 3m 10.42.1.86 kc-lab-2 <none> <none>
|
||||
keycloak-1 1/1 Running 0 3m33s 10.42.0.39 kc-lab-1 <none> <none>
|
||||
oauth2-proxy-d9b587458-7x9jt 1/1 Running 0 73m 10.42.1.78 kc-lab-2 <none> <none>
|
||||
oauth2-proxy-d9b587458-njxdw 1/1 Running 0 73m 10.42.1.79 kc-lab-2 <none> <none>
|
||||
postgres-7b474b88c8-kvt96 1/1 Running 0 4m6s 10.42.1.85 kc-lab-2 <none> <none>
|
||||
redis-f94bc6dbf-s674z 1/1 Running 0 141m 10.42.1.63 kc-lab-2 <none> <none>
|
||||
=== b5 2 Redis 의 내용과 영속화 설정을 본다 ===
|
||||
PONG
|
||||
save
|
||||
3600 1 300 100 60 10000
|
||||
appendonly
|
||||
yes
|
||||
=== b5 3 ① 파드에 볼륨이 붙어 있는가 ===
|
||||
[{"name":"data","persistentVolumeClaim":{"claimName":"redis-data"}},{"name":"kube-api-access-g4scs","projected":{"defaultMode":420,"sources":[{"serviceAccountToken":{"expirationSeconds":3607,"path":"token"}},{"configMap":{"items":[{"key":"ca.crt","path":"ca.crt"}],"name":"kube-root-ca.crt"}},{"downwardAPI":{"items":[{"fieldRef":{"apiVersion":"v1","fieldPath":"metadata.namespace"},"path":"namespace"}]}}]}}]
|
||||
=== b5 3 ② 어디에 붙었는지와 PVC 상태를 본다 ===
|
||||
[{"mountPath":"/data","name":"data"},{"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount","name":"kube-api-access-g4scs","readOnly":true}]
|
||||
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
|
||||
postgres-data Bound pvc-fe269834-3dd1-4b1f-82f6-a53413310a30 5Gi RWO local-path <unset> 4h38m
|
||||
redis-data Bound pvc-76a6565c-ca60-4a93-b08f-51400c5680ce 1Gi RWO local-path <unset> 168m
|
||||
=== b5 4 세 경로의 상태 코드를 뽑는다 ===
|
||||
/ 000
|
||||
/bff/token-boundary 000
|
||||
/actuator/health 000
|
||||
=== (진단) 이름이 무엇으로 풀리나 ===
|
||||
100.83.212.4 app1.hyeonworks.com
|
||||
=== (진단) 엣지 주소를 짚어 같은 셋 ===
|
||||
/ 200
|
||||
/bff/token-boundary 302
|
||||
/actuator/health 200
|
||||
=== b5 5 ① health 그룹 셋의 본문을 받는다 ===
|
||||
|
||||
|
||||
|
||||
=== (진단) 같은 셋을 엣지 주소로 ===
|
||||
{"status":"UP","groups":["liveness","readiness"],"components":{"db":{"status":"UP","details":{"database":"PostgreSQL","validationQuery":"isValid()"}},"diskSpace":{"status":"UP","details":{"total":20922114048,"free":13518041088,"threshold":10485760,"path":"/app/.","exists":true}},"livenessState":{"status":"UP"},"ping":{"status":"UP"},"readinessState":{"status":"UP"},"redis":{"status":"UP","details":{"version":"7.4.11"}},"ssl":{"status":"UP","details":{"validChains":[],"invalidChains":[]}}}}
|
||||
{"status":"UP"}
|
||||
{"status":"UP"}
|
||||
=== b5 5 ② kubelet 이 보는 경로를 확인한다 ===
|
||||
/actuator/health/readiness
|
||||
@@ -0,0 +1,56 @@
|
||||
=== b5 주입 1 시각을 남기고 Redis 를 0대로 내린다 ===
|
||||
18:14:47 정지
|
||||
deployment.apps/redis scaled
|
||||
pod/redis-f94bc6dbf-s674z condition met
|
||||
=== b5 주입 검증 ① Redis 가 0대인가 ===
|
||||
No resources found in keycloak-lab namespace.
|
||||
NAME READY UP-TO-DATE AVAILABLE AGE
|
||||
redis 0/0 0 0 168m
|
||||
=== b5 주입 검증 ② BFF 로그에서 연결 시도를 찾는다 ===
|
||||
2026-09-17T09:09:46.531Z WARN 1 --- [keycloak-bff] [l-1:housekeeper] com.zaxxer.hikari.pool.PoolBase : HikariPool-1 - Failed to validate connection org.postgresql.jdbc.PgConnection@13f41550 (This connection has been closed.). Possibly consider using a shorter maxLifetime value.
|
||||
2026-09-17T09:09:54.173Z WARN 1 --- [keycloak-bff] [l-1:housekeeper] com.zaxxer.hikari.pool.PoolBase : HikariPool-1 - Failed to validate connection org.postgresql.jdbc.PgConnection@75a79757 (This connection has been closed.). Possibly consider using a shorter maxLifetime value.
|
||||
2026-09-17T09:09:55.362Z WARN 1 --- [keycloak-bff] [l-1:housekeeper] com.zaxxer.hikari.pool.PoolBase : HikariPool-1 - Failed to validate connection org.postgresql.jdbc.PgConnection@43aef356 (This connection has been closed.). Possibly consider using a shorter maxLifetime value.
|
||||
2026-09-17T09:09:57.318Z WARN 1 --- [keycloak-bff] [l-1:housekeeper] com.zaxxer.hikari.pool.PoolBase : HikariPool-1 - Failed to validate connection org.postgresql.jdbc.PgConnection@7be4bd3b (This connection has been closed.). Possibly consider using a shorter maxLifetime value.
|
||||
2026-09-17T09:09:57.955Z WARN 1 --- [keycloak-bff] [l-1:housekeeper] com.zaxxer.hikari.pool.PoolBase : HikariPool-1 - Failed to validate connection org.postgresql.jdbc.PgConnection@32b0803f (This connection has been closed.). Possibly consider using a shorter maxLifetime value.
|
||||
2026-09-17T09:10:19.741Z WARN 1 --- [keycloak-bff] [l-1:housekeeper] com.zaxxer.hikari.pool.PoolBase : HikariPool-1 - Failed to validate connection org.postgresql.jdbc.PgConnection@5b2e9f1c (This connection has been closed.). Possibly consider using a shorter maxLifetime value.
|
||||
2026-09-17T09:13:13.527Z INFO 1 --- [keycloak-bff] [xecutorLoop-1-2] i.l.core.protocol.ConnectionWatchdog : Reconnecting, last destination was redis.keycloak-lab.svc/10.43.44.209:6379
|
||||
2026-09-17T09:13:13.528Z INFO 1 --- [keycloak-bff] [xecutorLoop-1-1] i.l.core.protocol.ConnectionWatchdog : Reconnecting, last destination was redis.keycloak-lab.svc/10.43.44.209:6379
|
||||
2026-09-17T09:13:13.529Z WARN 1 --- [keycloak-bff] [ioEventLoop-4-2] i.l.core.protocol.ConnectionWatchdog : Cannot reconnect to [redis.keycloak-lab.svc/<unresolved>:6379]: Connection refused: redis.keycloak-lab.svc/10.43.44.209:6379
|
||||
2026-09-17T09:13:13.530Z WARN 1 --- [keycloak-bff] [ioEventLoop-4-1] i.l.core.protocol.ConnectionWatchdog : Cannot reconnect to [redis.keycloak-lab.svc/<unresolved>:6379]: Connection refused: redis.keycloak-lab.svc/10.43.44.209:6379
|
||||
=== b5 주입 검증 ③ 엉뚱한 것을 죽이지 않았는지 본다 ===
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
bff-5d97897676-nmlqs 1/1 Running 0 168m
|
||||
bff-5d97897676-zvfhp 1/1 Running 0 168m
|
||||
keycloak-0 1/1 Running 0 3m17s
|
||||
keycloak-1 1/1 Running 0 3m50s
|
||||
oauth2-proxy-d9b587458-7x9jt 1/1 Running 0 74m
|
||||
oauth2-proxy-d9b587458-njxdw 1/1 Running 0 74m
|
||||
postgres-7b474b88c8-kvt96 1/1 Running 0 4m23s
|
||||
=== b5 관찰 세 경로를 다시 친다 (문서 그대로) ===
|
||||
/ 000
|
||||
/bff/token-boundary 000
|
||||
/actuator/health 000
|
||||
=== (진단) 엣지 주소를 짚어 같은 셋 ===
|
||||
/ 200
|
||||
/bff/token-boundary 000
|
||||
/actuator/health 000
|
||||
=== (진단) token-boundary 응답 본문 ===
|
||||
[본문 끝]
|
||||
=== b5 관찰 health 그룹 셋을 코드와 본문으로 본다 (엣지 주소를 짚어서) ===
|
||||
health 000
|
||||
health/readiness 200
|
||||
health/liveness 200
|
||||
|
||||
{"status":"UP"}
|
||||
=== b5 관찰 엔드포인트가 아직 ready 인지 본다 ===
|
||||
NAME ADDR READY
|
||||
bff-ptf2d [10.42.1.51],[10.42.0.22] true,true
|
||||
=== (진단) /actuator/health 를 더 길게 기다려 본다 ===
|
||||
health 503 total 60.046452
|
||||
exit=0
|
||||
{"status":"DOWN","groups":["liveness","readiness"],"components":{"db":{"status":"UP","details":{"database":"PostgreSQL","validationQuery":"isValid()"}},"diskSpace":{"status":"UP","details":{"total":20922114048,"free":13516791808,"threshold":10485760,"path":"/app/.","exists":true}},"livenessState":{"status":"UP"},"ping":{"status":"UP"},"readinessState":{"status":"UP"},"redis":{"status":"DOWN","details":{"error":"org.springframework.dao.QueryTimeoutException: Redis command timed out"}},"ssl":{"status":"UP","details":{"validChains":[],"invalidChains":[]}}}}
|
||||
=== (진단) /bff/token-boundary 도 길게 ===
|
||||
token-boundary 000 total 90.001609
|
||||
exit=28
|
||||
|
||||
[exited with code 0]
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
=== b5 관찰 ① Redis 를 다시 올린다 ===
|
||||
18:18:32 복구
|
||||
deployment.apps/redis scaled
|
||||
Waiting for deployment "redis" rollout to finish: 0 out of 1 new replicas have been updated...
|
||||
Waiting for deployment "redis" rollout to finish: 0 of 1 updated replicas are available...
|
||||
deployment "redis" successfully rolled out
|
||||
=== b5 관찰 ② 회복했는지와 재시작 횟수를 본다 (엣지 주소를 짚어서) ===
|
||||
/actuator/health 200
|
||||
/bff/token-boundary 302
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
bff-5d97897676-nmlqs 1/1 Running 0 173m
|
||||
bff-5d97897676-zvfhp 1/1 Running 0 173m
|
||||
=== b5 주입 2 ① 볼륨 참조를 떼고 롤아웃을 기다린다 ===
|
||||
deployment.apps/redis patched
|
||||
Waiting for deployment "redis" rollout to finish: 0 out of 1 new replicas have been updated...
|
||||
Waiting for deployment "redis" rollout to finish: 1 old replicas are pending termination...
|
||||
Waiting for deployment "redis" rollout to finish: 1 old replicas are pending termination...
|
||||
deployment "redis" successfully rolled out
|
||||
=== b5 주입 검증 ④ 볼륨이 정말 떨어졌는가 ===
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
redis-547fb5fcc7-wcqg8 1/1 Running 0 11s
|
||||
redis-f94bc6dbf-l9q6x 0/1 Completed 0 47s
|
||||
[{"name":"kube-api-access-d7bbm","projected":{"defaultMode":420,"sources":[{"serviceAccountToken":{"expirationSeconds":3607,"path":"token"}},{"configMap":{"items":[{"key":"ca.crt","path":"ca.crt"}],"name":"kube-root-ca.crt"}},{"downwardAPI":{"items":[{"fieldRef":{"apiVersion":"v1","fieldPath":"metadata.namespace"},"path":"namespace"}]}}]}}]
|
||||
=== (진단) volumeMounts 쪽도 ===
|
||||
[{"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount","name":"kube-api-access-d7bbm","readOnly":true}]
|
||||
=== b5 주입 2 ② AOF 를 켜고 키를 심는다 ===
|
||||
OK
|
||||
appendonly
|
||||
yes
|
||||
OK
|
||||
1
|
||||
total 12
|
||||
drwxr-xr-x 3 redis redis 4096 Sep 17 09:17 .
|
||||
drwxr-xr-x 1 root root 4096 Sep 17 09:17 ..
|
||||
drwx------ 2 redis redis 4096 Sep 17 09:17 appendonlydir
|
||||
=== b5 관찰 ③ 볼륨 없이 파드를 지우고 남은 것을 센다 ===
|
||||
pod "redis-547fb5fcc7-wcqg8" deleted from keycloak-lab namespace
|
||||
Waiting for deployment "redis" rollout to finish: 0 of 1 updated replicas are available...
|
||||
deployment "redis" successfully rolled out
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
redis-547fb5fcc7-4xv8m 1/1 Running 0 12s
|
||||
0
|
||||
|
||||
appendonly
|
||||
yes
|
||||
=== b5 관찰 ④ 볼륨을 되돌리고 같은 시험을 다시 한다 ===
|
||||
secret/bff-secrets configured
|
||||
persistentvolumeclaim/redis-data unchanged
|
||||
deployment.apps/redis configured
|
||||
service/redis unchanged
|
||||
deployment.apps/bff unchanged
|
||||
service/bff unchanged
|
||||
ingress.networking.k8s.io/bff unchanged
|
||||
Waiting for deployment "redis" rollout to finish: 1 old replicas are pending termination...
|
||||
Waiting for deployment "redis" rollout to finish: 1 old replicas are pending termination...
|
||||
deployment "redis" successfully rolled out
|
||||
appendonly
|
||||
yes
|
||||
OK
|
||||
pod "redis-547fb5fcc7-4xv8m" deleted from keycloak-lab namespace
|
||||
pod "redis-f94bc6dbf-lqrgp" deleted from keycloak-lab namespace
|
||||
Waiting for deployment "redis" rollout to finish: 0 of 1 updated replicas are available...
|
||||
deployment "redis" successfully rolled out
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
redis-f94bc6dbf-b7zdk 1/1 Running 0 12s
|
||||
4
|
||||
written-on-pvc
|
||||
=== b5 PVC 의 스토리지 클래스를 본다 ===
|
||||
local-path
|
||||
=== b5 B층 구성 요소의 지표가 있는가 ===
|
||||
redis_up 시계열 0개
|
||||
redis_connected_clients 시계열 0개
|
||||
pg_up 시계열 0개
|
||||
pg_stat_database_numbackends 시계열 0개
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
=== b5 복구 1 매니페스트를 다시 적용한다 ===
|
||||
secret/bff-secrets configured
|
||||
persistentvolumeclaim/redis-data unchanged
|
||||
deployment.apps/redis unchanged
|
||||
service/redis unchanged
|
||||
deployment.apps/bff unchanged
|
||||
service/bff unchanged
|
||||
ingress.networking.k8s.io/bff unchanged
|
||||
deployment "redis" successfully rolled out
|
||||
=== b5 복구 2 실험 키만 지우고 남은 키를 본다 ===
|
||||
1
|
||||
bff:session:sessions:[REDACTED]
|
||||
bff:session:sessions:[REDACTED]
|
||||
bff:session:sessions:[REDACTED]
|
||||
=== b5 복구 3 확인표 — Redis ===
|
||||
NAME READY UP-TO-DATE AVAILABLE AGE
|
||||
redis 1/1 1 1 174m
|
||||
=== 확인표 볼륨 ===
|
||||
[{"name":"data","persistentVolumeClaim":{"claimName":"redis-data"}},{"name":"kube-api-access-6mxzf","projected":{"defaultMode":420,"sources":[{"serviceAccountToken":{"expirationSeconds":3607,"path":"token"}},{"configMap":{"items":[{"key":"ca.crt","path":"ca.crt"}],"name":"kube-root-ca.crt"}},{"downwardAPI":{"items":[{"fieldRef":{"apiVersion":"v1","fieldPath":"metadata.namespace"},"path":"namespace"}]}}]}}]
|
||||
=== 확인표 PVC ===
|
||||
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
|
||||
postgres-data Bound pvc-fe269834-3dd1-4b1f-82f6-a53413310a30 5Gi RWO local-path <unset> 4h44m
|
||||
redis-data Bound pvc-76a6565c-ca60-4a93-b08f-51400c5680ce 1Gi RWO local-path <unset> 174m
|
||||
=== 확인표 영속화 ===
|
||||
appendonly
|
||||
yes
|
||||
=== 확인표 BFF ===
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
bff-5d97897676-nmlqs 1/1 Running 0 174m
|
||||
bff-5d97897676-zvfhp 1/1 Running 0 174m
|
||||
=== 확인표 엔드포인트 ===
|
||||
NAME ADDRESSTYPE PORTS ENDPOINTS AGE
|
||||
bff-ptf2d IPv4 8083 10.42.1.51,10.42.0.22 174m
|
||||
=== 확인표 밖 (문서 그대로) ===
|
||||
000
|
||||
=== 확인표 밖 (엣지 주소를 짚어서) ===
|
||||
200
|
||||
=== (마무리) git 은 안 건드렸다 ===
|
||||
git status exit=0
|
||||
@@ -0,0 +1,25 @@
|
||||
=== b6 ① kcadm 로그인 ===
|
||||
Logging into http://localhost:8080 as user admin of realm master
|
||||
exit=0
|
||||
|
||||
=== b6 ② 비밀번호 길이만 ===
|
||||
19
|
||||
|
||||
=== b6 2단계 공급자 목록 ===
|
||||
"id" : "5be506c2-8472-442b-8258-9c6692f45a13", "name" : "Trusted Hosts", "providerId" : "trusted-hosts"
|
||||
"id" : "e1686b9f-15a2-4979-a302-8fc18a4d6b22", "name" : "Full Scope Disabled", "providerId" : "scope"
|
||||
"id" : "6a0b8379-b2b1-4d2f-bc3b-fa1673723730", "name" : "Allowed Client Scopes", "providerId" : "allowed-client-templates"
|
||||
"id" : "7dc6fe06-06c3-4d25-b93a-1fe245e4837c", "name" : "Consent Required", "providerId" : "consent-required"
|
||||
"id" : "06777327-7c87-4ff4-92da-3335462ccb3b", "name" : "Allowed Client Scopes", "providerId" : "allowed-client-templates"
|
||||
"id" : "3c9062a0-fc6d-4fef-870e-7bfc10270279", "name" : "Allowed Protocol Mapper Types", "providerId" : "allowed-protocol-mappers"
|
||||
"id" : "a03ee0cb-765b-4eea-9d6c-e76bcee3adf4", "name" : "Allowed Registration Web Origins", "providerId" : "registration-web-origins"
|
||||
"id" : "d47b58ee-7c34-4be0-a3f3-30f49b4577c1", "name" : "rsa-enc-generated", "providerId" : "rsa-enc-generated"
|
||||
"id" : "807e653f-deaf-41cd-bbaa-5b19eaf74a2a", "name" : "hmac-generated-hs512", "providerId" : "hmac-generated"
|
||||
"id" : "404e38a3-d3c3-4996-9228-200a912de08b", "name" : "Allowed Registration Web Origins", "providerId" : "registration-web-origins"
|
||||
"id" : "27216d59-950c-4c8c-b0a8-e1d8108e0c0f", "name" : "aes-generated", "providerId" : "aes-generated"
|
||||
"id" : "142c7871-4556-4faa-b9af-83d2376da5c6", "name" : "Max Clients Limit", "providerId" : "max-clients"
|
||||
"id" : "a09ec151-6c8c-4e55-84c0-f02781221b83", "name" : "rsa-generated", "providerId" : "rsa-generated"
|
||||
"id" : "212bde50-f539-4742-85bc-97f4a31a604a", "name" : "Allowed Protocol Mapper Types", "providerId" : "allowed-protocol-mappers"
|
||||
|
||||
=== b6 2단계 -q type=... 형태 ===
|
||||
"name" : "rsa-enc-generated" "name" : "hmac-generated-hs512" "name" : "aes-generated" "name" : "rsa-generated"
|
||||
@@ -0,0 +1,18 @@
|
||||
=== b6 3단계를 문서 그대로: [lab host] 에서 공개 URL 로 ===
|
||||
https 000 (Failed to connect to auth.hyeonworks.com:443 after 22 ms: Could not connect to server)
|
||||
http 000 (Failed to connect to auth.hyeonworks.com:80 after 4 ms: Could not connect to server)
|
||||
|
||||
=== 같은 것을 dev 에서 http 로 ===
|
||||
{"keys":[{"kid":"HKy0uQhg-vlQackK6-oj3hW6vKbDj-95Wlvdgl37cGg","kty":"RSA","alg":"RS256","use":"sig","x5c":["MIICsTCCAZkC
|
||||
|
||||
=== 3단계 ② kid 만 ===
|
||||
{"keys":[{"kid":"HKy0uQhg-vlQackK6-oj3hW6vKbDj-95Wlvdgl37cGg"
|
||||
{"kid":"5voCsAVhALEjGliTG9Z2bx6WSkHeAUFUXiYOYic-niI"
|
||||
|
||||
=== 4단계 ① 키 단위로 잘라 RS256 만 센다 ===
|
||||
1
|
||||
=== 4단계 ② kcadm get keys ===
|
||||
"kid" : "abfdb1a2-539c-4be6-b651-30e8a8e5c917", "status" : "ACTIVE", "algorithm" : "AES",
|
||||
"kid" : "24d796a2-ca3c-477c-bf9f-c19f81e0e64c", "status" : "ACTIVE", "algorithm" : "HS512",
|
||||
"kid" : "HKy0uQhg-vlQackK6-oj3hW6vKbDj-95Wlvdgl37cGg", "status" : "ACTIVE", "algorithm" : "RS256",
|
||||
"kid" : "5voCsAVhALEjGliTG9Z2bx6WSkHeAUFUXiYOYic-niI", "status" : "ACTIVE", "algorithm" : "RSA-OAEP",
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
=== 왜 못 닿나 ===
|
||||
100.83.212.4 auth.hyeonworks.com
|
||||
--- 호스트가 80/443 을 듣나
|
||||
(리스너 없음)
|
||||
|
||||
=== 고쳐 치는 형태: --resolve 로 엣지를 직접 가리킨다 ===
|
||||
{"keys":[{"kid":"HKy0uQhg-vlQackK6-oj3hW6vKbDj-95Wlvdgl37cGg"
|
||||
{"kid":"5voCsAVhALEjGliTG9Z2bx6WSkHeAUFUXiYOYic-niI"
|
||||
@@ -0,0 +1,7 @@
|
||||
=== b6 5단계: 문서 그대로 [lab host] 에서 (https 공개 URL) ===
|
||||
0자
|
||||
|
||||
=== 같은 것을 --resolve 로 고쳐서 ===
|
||||
길이 0자
|
||||
응답(토큰 없음): {"error":"invalid_grant","error_description":"Invalid user credentials"}
|
||||
헤더:
|
||||
@@ -0,0 +1,8 @@
|
||||
=== 비밀번호를 B-6 이 박아 둔 값으로 맞춘다 ===
|
||||
exit=0
|
||||
|
||||
=== b6 5·6단계 다시 ===
|
||||
5단계 길이: 1406자
|
||||
6단계 헤더: {"alg":"RS256","typ" : "JWT","kid" : "HKy0uQhg-vlQackK6-oj3hW6vKbDj-95Wlvdgl37cGg"}
|
||||
6단계 kid : HKy0uQhg-vlQackK6-oj3hW6vKbDj-95Wlvdgl37cGg
|
||||
(토큰은 랩 호스트의 /tmp/old.jwt 에만 둔다)
|
||||
@@ -0,0 +1,30 @@
|
||||
=== 5. 옛 토큰 ===
|
||||
1406자 · kid HKy0uQhg-vlQackK6-oj3hW6vKbDj-95Wlvdgl37cGg
|
||||
=== 7. 지금 통하는가 ===
|
||||
old 401
|
||||
=== 8. priority 200 공급자 추가 ===
|
||||
Created new component with id 'a8b5aecc-ffb6-4b17-8d5b-3eef5ecb9b72'
|
||||
16:19:04 추가
|
||||
=== 9. JWKS 에 옛 키가 남아 있는가 ===
|
||||
{"keys":[{"kid":"iq4fSn_kovyqBsgaemqsVcsRJlWIYO5HTyiTO5WI9T4"
|
||||
{"kid":"HKy0uQhg-vlQackK6-oj3hW6vKbDj-95Wlvdgl37cGg"
|
||||
{"kid":"5voCsAVhALEjGliTG9Z2bx6WSkHeAUFUXiYOYic-niI"
|
||||
RS256 키 수: 2
|
||||
=== 10. 새 토큰의 kid ===
|
||||
1406자 · kid iq4fSn_kovyqBsgaemqsVcsRJlWIYO5HTyiTO5WI9T4
|
||||
=== 11. 둘 다 통하는가 ===
|
||||
old 401
|
||||
new 401
|
||||
exp 1789629509 · now 1789629545
|
||||
=== 12. 지울 대상 ===
|
||||
지울 id: a09ec151-6c8c-4e55-84c0-f02781221b83
|
||||
=== 13. 옛 공급자 제거 ===
|
||||
16:19:07 제거
|
||||
=== 14. JWKS 에서 사라졌는가 ===
|
||||
{"keys":[{"kid":"iq4fSn_kovyqBsgaemqsVcsRJlWIYO5HTyiTO5WI9T4"
|
||||
{"kid":"5voCsAVhALEjGliTG9Z2bx6WSkHeAUFUXiYOYic-niI"
|
||||
RS256 키 수: 1
|
||||
=== 15. 두 토큰을 다시 ===
|
||||
old 401
|
||||
new 401
|
||||
exp 1789629509 · now 1789629547
|
||||
@@ -0,0 +1,47 @@
|
||||
=== echo 가 왜 401 을 내나 ===
|
||||
at java.base/sun.nio.ch.Net.connect0(Native Method) ~[na:na]
|
||||
at java.base/sun.nio.ch.Net.connect(Unknown Source) ~[na:na]
|
||||
at java.base/sun.nio.ch.Net.connect(Unknown Source) ~[na:na]
|
||||
at java.base/sun.nio.ch.NioSocketImpl.connect(Unknown Source) ~[na:na]
|
||||
at java.base/java.net.SocksSocketImpl.connect(Unknown Source) ~[na:na]
|
||||
at java.base/java.net.Socket.connect(Unknown Source) ~[na:na]
|
||||
at java.base/sun.security.ssl.SSLSocketImpl.connect(Unknown Source) ~[na:na]
|
||||
at java.base/sun.security.ssl.BaseSSLSocketImpl.connect(Unknown Source) ~[na:na]
|
||||
at java.base/sun.net.NetworkClient.doConnect(Unknown Source) ~[na:na]
|
||||
at java.base/sun.net.www.http.HttpClient.openServer(Unknown Source) ~[na:na]
|
||||
at java.base/sun.net.www.http.HttpClient.openServer(Unknown Source) ~[na:na]
|
||||
at java.base/sun.net.www.protocol.https.HttpsClient.<init>(Unknown Source) ~[na:na]
|
||||
at java.base/sun.net.www.protocol.https.HttpsClient.New(Unknown Source) ~[na:na]
|
||||
at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(Unknown Source) ~[na:na]
|
||||
at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(Unknown Source) ~[na:na]
|
||||
at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source) ~[na:na]
|
||||
at java.base/sun.net.www.protocol.http.HttpURLConnection.connect(Unknown Source) ~[na:na]
|
||||
at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source) ~[na:na]
|
||||
at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(Unknown Source) ~[na:na]
|
||||
at org.springframework.http.client.SimpleClientHttpRequest.executeInternal(SimpleClientHttpRequest.java:79) ~[spring-web-6.2.19.jar!/:6.2.19]
|
||||
at org.springframework.http.client.AbstractStreamingClientHttpRequest.executeInternal(AbstractStreamingClientHttpRequest.java:88) ~[spring-web-6.2.19.jar!/:6.2.19]
|
||||
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:81) ~[spring-web-6.2.19.jar!/:6.2.19]
|
||||
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:900) ~[spring-web-6.2.19.jar!/:6.2.19]
|
||||
... 101 common frames omitted
|
||||
|
||||
|
||||
=== echo 의 issuer 설정 ===
|
||||
[{"name":"SERVER_PORT","value":"8081"},{"name":"SERVER_FORWARD_HEADERS_STRATEGY","value":"native"},{"name":"JAVA_TOOL_OPTIONS","value":"-XX:MaxRAMPercentage=70"},{"name":"SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI","value":"https://auth.hyeonworks.com/realms/keycloak-patterns"},{"name":"SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI","value":"https://auth.hyeonworks.com/realms/keycloak-patterns/protocol/openid-connect/certs"}]
|
||||
|
||||
=== 401 의 WWW-Authenticate ===
|
||||
HTTP/1.1 401 Unauthorized
|
||||
Server: nginx/1.22.1
|
||||
Date: Thu, 17 Sep 2026 07:17:43 GMT
|
||||
Content-Length: 0
|
||||
Connection: keep-alive
|
||||
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
|
||||
Expires: 0
|
||||
Pragma: no-cache
|
||||
|
||||
=== realm 의 accessTokenLifespan ===
|
||||
{
|
||||
"accessTokenLifespan" : 60,
|
||||
"ssoSessionIdleTimeout" : 1800
|
||||
}=== 시계 차이 ===
|
||||
host 1789629559
|
||||
kc-0 1789629465
|
||||
@@ -0,0 +1,18 @@
|
||||
=== 기계마다의 시각 (같은 순간에 친다) ===
|
||||
lab host 1789629566 07:19:26
|
||||
kc-lab-1 1789629472 07:17:52
|
||||
kc-lab-2 1789629473 07:17:53
|
||||
kc-lab-edge 1789629473 07:17:53
|
||||
kc-0 pod 1789629473
|
||||
--- 시간 동기 상태
|
||||
== kc-lab-1
|
||||
NTP=yes
|
||||
NTPSynchronized=yes
|
||||
TimeUSec=Thu 2026-09-17 07:17:53 UTC
|
||||
== kc-lab-2
|
||||
NTP=yes
|
||||
NTPSynchronized=yes
|
||||
TimeUSec=Thu 2026-09-17 07:17:54 UTC
|
||||
== lab host
|
||||
NTP=no
|
||||
NTPSynchronized=no
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
=== b6 원상복구 확인표 ===
|
||||
--- 서명 키
|
||||
{"keys":[{"kid":"iq4fSn_kovyqBsgaemqsVcsRJlWIYO5HTyiTO5WI9T4"
|
||||
{"kid":"5voCsAVhALEjGliTG9Z2bx6WSkHeAUFUXiYOYic-niI"
|
||||
--- 파드
|
||||
echo-cd47dccc6-nq62j 1/1 Running 0 41m
|
||||
echo-cd47dccc6-q46lk 1/1 Running 0 41m
|
||||
keycloak-0 1/1 Running 0 24m
|
||||
keycloak-1 1/1 Running 0 25m
|
||||
--- 공급자 목록
|
||||
"name" : "rsa-enc-generated"
|
||||
"name" : "rsa-rotated"
|
||||
--- 새 토큰 + /api/me
|
||||
토큰 1406자
|
||||
/api/me 401
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
=== echo 를 다시 띄워 JWKS 를 받게 한다 ===
|
||||
deployment "echo" successfully rolled out
|
||||
|
||||
=== b6 7단계 대조군: 토큰이 지금 통하는가 ===
|
||||
토큰 0자
|
||||
old 000
|
||||
|
||||
=== echo 로그에 JWKS 오류가 남아 있나 ===
|
||||
0
|
||||
0
|
||||
@@ -0,0 +1,7 @@
|
||||
=== b6 5·7단계 (dev 에서) ===
|
||||
5단계 토큰 1406자
|
||||
6단계 kid iq4fSn_kovyqBsgaemqsVcsRJlWIYO5HTyiTO5WI9T4
|
||||
7단계 대조군:
|
||||
old 200
|
||||
(본문과 WWW-Authenticate)
|
||||
HTTP/2 200
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
=== 출발 상태: 지금 있는 RSA 공급자 ===
|
||||
}, { "id" : "a8b5aecc-ffb6-4b17-8d5b-3eef5ecb9b72", "name" : "rsa-rotated",
|
||||
=== 5. 옛 토큰 ===
|
||||
1406자 · kid iq4fSn_kovyqBsgaemqsVcsRJlWIYO5HTyiTO5WI9T4
|
||||
=== 7. 대조군 ===
|
||||
old 200
|
||||
=== 8. 더 높은 우선순위 공급자를 더한다 (기존이 200 이라 300 을 준다) ===
|
||||
Created new component with id '958e80bd-3b9f-4b05-9d9a-011b8e4ef54a'
|
||||
=== 9. JWKS 에 옛 키가 남아 있는가 ===
|
||||
{"keys":[{"kid":"mL3CkHOfWatmZa6b3c_aFUWrY35EI1WmjxTc1ydpqGc"
|
||||
{"kid":"iq4fSn_kovyqBsgaemqsVcsRJlWIYO5HTyiTO5WI9T4"
|
||||
{"kid":"5voCsAVhALEjGliTG9Z2bx6WSkHeAUFUXiYOYic-niI"
|
||||
RS256 키 수: 2
|
||||
=== 10. 새 토큰의 kid ===
|
||||
kid mL3CkHOfWatmZa6b3c_aFUWrY35EI1WmjxTc1ydpqGc
|
||||
=== 11. 둘 다 통하는가 ===
|
||||
old 200
|
||||
new 200
|
||||
@@ -0,0 +1,14 @@
|
||||
=== 12. 지울 대상 (rsa-rotated = 옛 키) ===
|
||||
a8b5aecc-ffb6-4b17-8d5b-3eef5ecb9b72
|
||||
=== 다시 옛 토큰을 받는다 (수명 안에 끝내려고) ===
|
||||
옛 kid mL3CkHOfWatmZa6b3c_aFUWrY35EI1WmjxTc1ydpqGc
|
||||
새 kid mL3CkHOfWatmZa6b3c_aFUWrY35EI1WmjxTc1ydpqGc
|
||||
※ 둘 다 지금은 새 키로 서명된다 — 옛 키 토큰은 위 8~11 에서 받은 것이 정본이다
|
||||
=== 13. 옛 공급자를 지운다 ===
|
||||
07:52:46 제거
|
||||
=== 14. JWKS 에서 사라졌는가 ===
|
||||
{"keys":[{"kid":"mL3CkHOfWatmZa6b3c_aFUWrY35EI1WmjxTc1ydpqGc"
|
||||
{"kid":"5voCsAVhALEjGliTG9Z2bx6WSkHeAUFUXiYOYic-niI"
|
||||
RS256 키 수: 1
|
||||
=== 15. 두 토큰을 다시 ===
|
||||
새키 토큰 200
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
=== 5. 옛 키로 서명된 토큰 (이 값을 끝까지 안 건드린다) ===
|
||||
1406자 · kid mL3CkHOfWatmZa6b3c_aFUWrY35EI1WmjxTc1ydpqGc
|
||||
=== 7. 대조군 ===
|
||||
old 200
|
||||
=== 8. priority 400 공급자를 더한다 ===
|
||||
Created new component with id '7aa3832c-787a-4e9b-9eda-2ec72c4c0b97'
|
||||
=== 9·10 ===
|
||||
RS256 키 수: 2
|
||||
새 토큰 kid AS65-ZKZDmxLFCfxk2agmmHQpM2jdT4xjP-To6r5SRM
|
||||
=== 11. 겹치는 구간 ===
|
||||
old 200
|
||||
new 200
|
||||
=== 13. 옛 공급자(priority 300) 제거 ===
|
||||
지울 id: 958e80bd-3b9f-4b05-9d9a-011b8e4ef54a
|
||||
=== 14·15 ===
|
||||
RS256 키 수: 1
|
||||
old 200
|
||||
new 200
|
||||
경과 6초 (토큰 수명 60초)
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
=== 지금 JWKS 에 있는 kid ===
|
||||
{"keys":[{"kid":"AS65-ZKZDmxLFCfxk2agmmHQpM2jdT4xjP-To6r5SRM"
|
||||
{"kid":"5voCsAVhALEjGliTG9Z2bx6WSkHeAUFUXiYOYic-niI"
|
||||
|
||||
=== 사라진 키로 서명된 토큰을 다시 만들 수는 없다 — 지금 받는 토큰은 살아 있는 키다 ===
|
||||
지금 토큰 kid AS65-ZKZDmxLFCfxk2agmmHQpM2jdT4xjP-To6r5SRM
|
||||
|
||||
=== 16. echo 를 다시 띄워 캐시를 비운다 ===
|
||||
deployment "echo" successfully rolled out
|
||||
재시작 34초
|
||||
|
||||
=== 재시작 뒤 현재 토큰 ===
|
||||
now 200
|
||||
fresh 200
|
||||
@@ -0,0 +1,16 @@
|
||||
5. 옛 토큰 kid AS65-ZKZDmxLFCfxk2agmmHQpM2jdT4xjP-To6r5SRM
|
||||
[+0초]
|
||||
7. 대조군 old 200
|
||||
8. Created new component with id '066d3957-9b0e-411f-a36c-87ed17a18815'
|
||||
10. 새 토큰 kid yHLkV7okKrLif-ndb01imOfaHze94lrllFgITCtoQmc
|
||||
11. old 200 new 200
|
||||
[+2초]
|
||||
13. 옛 공급자 제거 (7aa3832c-787a-4e9b-9eda-2ec72c4c0b97)
|
||||
[+5초]
|
||||
14. RS256 키 수: 1
|
||||
15. old 200 new 200
|
||||
[+6초]
|
||||
16. echo 재시작
|
||||
[+39초]
|
||||
16 뒤. old 401 new 504
|
||||
[+70초]
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
=== echo 가 준비됐는지 먼저 ===
|
||||
echo-85b6ffd88f-grm5g 1/1 Running 0 75s
|
||||
echo-85b6ffd88f-nnvpt 1/1 Running 0 59s
|
||||
옛 토큰 kid yHLkV7okKrLif-ndb01imOfaHze94lrllFgITCtoQmc
|
||||
Created new component with id '9af4a602-1e5c-47d7-8c52-6fd7667a5261'
|
||||
제거 완료 [+5초] · JWKS RS256 1개
|
||||
--- 제거 뒤 옛 토큰을 10초마다
|
||||
[+6초] old=401
|
||||
[+16초] old=200
|
||||
[+26초] old=401
|
||||
[+36초] old=200
|
||||
[+47초] old=401
|
||||
@@ -0,0 +1,9 @@
|
||||
=== 옛 키로 서명된 토큰을 하나 만들고 즉시 회전+제거, 그다음 파드별로 친다 ===
|
||||
옛 kid aJCNYKhd4LWm6fTcmllP3dbq_incT5Jww6CzNj92WmU
|
||||
Created new component with id '6689ab97-c4de-4b23-8ad7-c66ae4759113'
|
||||
제거 완료
|
||||
--- 파드마다 직접 (클러스터 안에서, 파드 IP 로)
|
||||
echo-85b6ffd88f-grm5g 10.42.1.76 up
|
||||
echo-85b6ffd88f-nnvpt 10.42.0.35 up
|
||||
--- 같은 토큰으로 8번 연속 (라운드로빈)
|
||||
401 200 401 200 401 200 401 200
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
=== B-7 1단계: Grafana Ingress 를 백업한다 ===
|
||||
30 /home/donghyeon/grafana-ingress-backup.yaml
|
||||
|
||||
=== B-7 2단계 ①② ===
|
||||
ingress.networking.k8s.io "grafana" deleted from observability namespace
|
||||
secret/oauth2-proxy-secrets configured
|
||||
deployment.apps/oauth2-proxy created
|
||||
service/oauth2-proxy created
|
||||
ingress.networking.k8s.io/oauth2-proxy created
|
||||
Waiting for deployment "oauth2-proxy" rollout to finish: 0 of 2 updated replicas are available...
|
||||
error: timed out waiting for the condition
|
||||
|
||||
=== 파드 상태와 실제 오류 ===
|
||||
oauth2-proxy-6c56c4c94f-vncmx 0/1 CrashLoopBackOff 4 (6s ago) 91s
|
||||
oauth2-proxy-6c56c4c94f-zxg52 0/1 CrashLoopBackOff 3 (48s ago) 91s
|
||||
---
|
||||
[2026/09/17 07:37:18] [provider.go:55] Performing OIDC Discovery...
|
||||
[2026/09/17 07:37:18] [main.go:59] ERROR: Failed to initialise OAuth2 Proxy: error initialising provider: could not create provider data: error building OIDC ProviderVerifier: could not get verifier builder: error while discovery OIDC configuration: failed to discover OIDC configuration: error performing request: Get "https://auth.hyeonworks.com/realms/keycloak-patterns/.well-known/openid-configuration": dial tcp 192.168.122.10:443: connect: connection refused
|
||||
[2026/09/17 07:36:36] [provider.go:55] Performing OIDC Discovery...
|
||||
[2026/09/17 07:36:36] [main.go:59] ERROR: Failed to initialise OAuth2 Proxy: error initialising provider: could not create provider data: error building OIDC ProviderVerifier: could not get verifier builder: error while discovery OIDC configuration: failed to discover OIDC configuration: error performing request: Get "https://auth.hyeonworks.com/realms/keycloak-patterns/.well-known/openid-configuration": dial tcp 192.168.122.10:443: connect: connection refused
|
||||
@@ -0,0 +1,15 @@
|
||||
=== B-7 되돌리기 ② 빌린 Ingress 를 걷고 Grafana 것을 올린다 ===
|
||||
ingress.networking.k8s.io "oauth2-proxy" deleted from keycloak-lab namespace
|
||||
ingress.networking.k8s.io/grafana created
|
||||
deployment.apps "oauth2-proxy" deleted from keycloak-lab namespace
|
||||
Error from server (NotFound): deployments.apps "svc" not found
|
||||
Error from server (NotFound): deployments.apps "oauth2-proxy" not found
|
||||
|
||||
=== 돌아왔는지 ===
|
||||
header-lab echo traefik app1.hyeonworks.com 192.168.122.11,192.168.122.12 80 61m
|
||||
keycloak-lab bff traefik app1.hyeonworks.com 192.168.122.11,192.168.122.12 80 73m
|
||||
keycloak-lab keycloak traefik auth.hyeonworks.com 192.168.122.11,192.168.122.12 80 3h3m
|
||||
observability grafana traefik app2.hyeonworks.com 192.168.122.11,192.168.122.12 80 1s
|
||||
---
|
||||
0
|
||||
oauth2-proxy 파드 0
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
=== 쌓인 RSA 공급자 정리 (가장 높은 것 하나만 남긴다) ===
|
||||
"id" : "6689ab97-c4de-4b23-8ad7-c66ae4759113", "name" : "rsa-rot-6",
|
||||
"id" : "d47b58ee-7c34-4be0-a3f3-30f49b4577c1", "name" : "rsa-enc-generated",
|
||||
|
||||
=== B-7 1단계: Grafana Ingress 백업 ===
|
||||
백업 30줄
|
||||
|
||||
=== B-7 2단계: Grafana 를 내리고 oauth2-proxy 배포 ===
|
||||
ingress.networking.k8s.io "grafana" deleted from observability namespace
|
||||
secret/oauth2-proxy-secrets configured
|
||||
deployment.apps/oauth2-proxy created
|
||||
service/oauth2-proxy created
|
||||
ingress.networking.k8s.io/oauth2-proxy created
|
||||
Waiting for deployment "oauth2-proxy" rollout to finish: 0 out of 2 new replicas have been updated...
|
||||
Waiting for deployment "oauth2-proxy" rollout to finish: 0 of 2 updated replicas are available...
|
||||
Waiting for deployment "oauth2-proxy" rollout to finish: 1 of 2 updated replicas are available...
|
||||
deployment "oauth2-proxy" successfully rolled out
|
||||
|
||||
=== 3단계: replica 와 배치 ===
|
||||
oauth2-proxy-6c56c4c94f-gq484 1/1 Running 0 12s 10.42.1.77 kc-lab-2 <none> <none>
|
||||
oauth2-proxy-6c56c4c94f-szr6j 1/1 Running 0 12s 10.42.0.36 kc-lab-1 <none> <none>
|
||||
@@ -0,0 +1,18 @@
|
||||
=== B-7 4단계: 진입점 두 곳이 갈라지나 ===
|
||||
https://app1.hyeonworks.com/ 200
|
||||
https://app2.hyeonworks.com/ 302
|
||||
|
||||
=== B-7 7단계: app2 로 로그인한다 ===
|
||||
도착: https://auth.hyeonworks.com/realms/keycloak-patterns/protocol/openid-connect/auth?app
|
||||
form:
|
||||
로그인 결과: 000
|
||||
head: cannot open '/tmp/p2b.html' for reading: No such file or directory
|
||||
본문 앞:
|
||||
|
||||
=== 쿠키 (값은 길이만) ===
|
||||
app2.hyeonworks.com _oauth2_proxy_csrf 176자
|
||||
|
||||
=== B-7 8단계: Redis 에 세션이 들어갔나 ===
|
||||
bff:session:sessions:b66634a2-1381-4071-8ceb-0a006fbe1327
|
||||
bff:session:sessions:c5f7b0c7-cd17-4749-bf3e-6d42c814bb1c
|
||||
dbsize: 2
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
=== realm 에 등록된 클라이언트 ===
|
||||
account
|
||||
account-console
|
||||
admin-cli
|
||||
bff-confidential
|
||||
broker
|
||||
realm-management
|
||||
security-admin-console
|
||||
|
||||
=== oauth2-proxy 가 쓰는 client_id ===
|
||||
|
||||
=== 이 클라이언트를 만드는 setup 문서가 있나 ===
|
||||
docs/keycloak-session-store/tech-log-studio/trust-handed-over-at-the-edge/setup/setup-reproduce-c2-backchannel-logout.md
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
=== 어느 문서에도 없는 한 단계: oauth2-proxy 클라이언트를 만든다 ===
|
||||
클라이언트 비밀 길이: 16자
|
||||
Created new client with id 'f7bed9b9-8fb5-4b3d-9253-c574c0b09739'
|
||||
|
||||
=== 만들어졌나 ===
|
||||
[ {
|
||||
"clientId" : "oauth2-proxy",
|
||||
"enabled" : true,
|
||||
"redirectUris" : [ "https://app2.hyeonworks.com/oauth2/callback" ],
|
||||
"publicClient" : false
|
||||
} ]
|
||||
@@ -0,0 +1,41 @@
|
||||
=== B-7 7단계: app2 로 로그인 ===
|
||||
로그인 폼: https://auth.hyeonworks.com/realms/keycloak-patterns/login-actions/authenticate?session_co
|
||||
로그인 결과: 401 · 본문 0바이트
|
||||
|
||||
=== 업스트림이 받은 헤더 (echo 가 그대로 돌려준다) ===
|
||||
{
|
||||
"headers" : {
|
||||
"host" : [ "app2.hyeonworks.com" ],
|
||||
"user-agent" : [ "curl/8.5.0" ],
|
||||
"accept" : [ "*/*" ],
|
||||
"accept-encoding" : [ "gzip" ],
|
||||
"cookie" : [ "_oauth2_proxy=djIuWDI5aGRYUm9NbDl3Y205NGVTMDFaR05rTURjNVpUQmlaVE5sWWpoaE9UVXdZelptWm1FMVpHTTVZamhpTVEuWDhMSFFnVnYtenRXV0hzTFMzVVN0QQ==|1789631924|yGT15uSP74BddTXAVgSvVGaz65hygKtaju9CDM3lHlc=" ],
|
||||
"x-forwarded-email" : [ "labuser@example.invalid" ],
|
||||
"x-forwarded-host" : [ "app2.hyeonworks.com" ],
|
||||
"x-forwarded-port" : [ "443" ],
|
||||
"x-forwarded-preferred-username" : [ "labuser" ],
|
||||
"x-forwarded-proto" : [ "https" ],
|
||||
"x-forwarded-server" : [ "traefik-5d6fcf895-xmqp6" ],
|
||||
"x-forwarded-user" : [ "07d3be2a-9f22-4779-a211-e530c8b7ff3b" ],
|
||||
"x-real-ip" : [ "192.168.122.1" ]
|
||||
},
|
||||
"remoteAddr" : "192.168.122.1",
|
||||
"localAddr" : "10.42.0.35",
|
||||
"scheme" : "https",
|
||||
"secure" : true,
|
||||
"serverName" : "app2.hyeonworks.com",
|
||||
"serverPort" : 443,
|
||||
"requestUrl" : "https://app2.hyeonworks.com/api/echo"
|
||||
}
|
||||
=== 쿠키 (값은 길이만) ===
|
||||
auth.hyeonworks.com KC_AUTH_SESSION_HASH 64자
|
||||
auth.hyeonworks.com AUTH_SESSION_ID 165자
|
||||
auth.hyeonworks.com KEYCLOAK_IDENTITY 594자
|
||||
auth.hyeonworks.com KEYCLOAK_SESSION 64자
|
||||
app2.hyeonworks.com _oauth2_proxy 176자
|
||||
|
||||
=== B-7 8단계: Redis ===
|
||||
_oauth2_proxy-5dcd079e0be3eb8a950c6ffa5dc9b8b1
|
||||
bff:session:sessions:b66634a2-1381-4071-8ceb-0a006fbe1327
|
||||
bff:session:sessions:c5f7b0c7-cd17-4749-bf3e-6d42c814bb1c
|
||||
dbsize=3
|
||||
@@ -0,0 +1,21 @@
|
||||
=== 주입 2 ① env 이름 순서 ===
|
||||
OAUTH2_PROXY_CLIENT_SECRET OAUTH2_PROXY_COOKIE_SECRET
|
||||
|
||||
=== 회전 전 대조군: 지금 쿠키가 통하는가 ===
|
||||
회전 전 200
|
||||
|
||||
=== 주입 2 ② A → B 로 바꾼다 ===
|
||||
07:58:58 UTC 회전
|
||||
deployment.apps/oauth2-proxy patched
|
||||
deployment "oauth2-proxy" successfully rolled out
|
||||
|
||||
=== 주입 검증 1·2·3 ===
|
||||
참조: COOKIE_SECRET_B
|
||||
Redis 세션: _oauth2_proxy-5dcd079e0be3eb8a950c6ffa5dc9b8b1
|
||||
파드:
|
||||
oauth2-proxy-d9b587458-7x9jt 1/1 Running 0 25s
|
||||
oauth2-proxy-d9b587458-njxdw 1/1 Running 0 12s
|
||||
|
||||
=== 관찰: 회전 전 쿠키가 아직 통하는가 ===
|
||||
회전 뒤 302
|
||||
(리다이렉트 목적지) https://auth.hyeonworks.com/realms/keycloak-patterns/protocol/openid-connect/auth?approval_prompt=force&client_id=oauth2-proxy&redirect_uri=https%3A%2F%2Fapp2.hyeonworks.com%2Foauth2%2Fcallback&response_type=code&scope=openid+email+profile&state=5V_qNK4dsuw6h4jJTooqFYlaVJ5WarqCuDpsGlpHgAw%3A%2Fapi%2Fecho
|
||||
@@ -0,0 +1,10 @@
|
||||
=== B-7a 6단계: R 함수와 스캔 루프 (오래 미검증이던 블록) ===
|
||||
_oauth2_proxy-5dcd079e0be3eb8a950c6ffa5dc9b8b1 type=string ttl=3551 len=3457
|
||||
|
||||
=== B-7a: TTL 이 줄어드는가 · 갱신되는가 (30초 간격 세 번) ===
|
||||
08:01:07
|
||||
_oauth2_proxy-5dcd079e0be3eb8a950c6ffa5dc9b8b1 ttl=3551
|
||||
08:01:37
|
||||
_oauth2_proxy-5dcd079e0be3eb8a950c6ffa5dc9b8b1 ttl=3521
|
||||
08:02:07
|
||||
_oauth2_proxy-5dcd079e0be3eb8a950c6ffa5dc9b8b1 ttl=3490
|
||||
@@ -0,0 +1,29 @@
|
||||
=== C-1 주입 1: app1 에 로그인한다 ===
|
||||
app1 로그인 200
|
||||
{"pattern":"AP3-backend-for-frontend","principal":"labuser","accessTokenStoredOnServer":true,"refreshTokenStoredOnServer
|
||||
|
||||
=== C-1 주입 3: 같은 창의 새 탭에서 app2 를 연다 (재인증이 뜨는가) ===
|
||||
도착: https://app2.hyeonworks.com/api/echo
|
||||
로그인 폼이 떴나: 0 (0 이면 재인증 없이 통과)
|
||||
본문 앞: { "headers" : { "host" : [ "app2.hyeonworks.com" ], "user-agent" : [ "curl/8.5.0
|
||||
|
||||
=== C-1 주입검증 2: 어느 클라이언트가 붙었나 ===
|
||||
[ {
|
||||
"offline" : "0",
|
||||
"clientId" : "bff-confidential",
|
||||
"active" : "15",
|
||||
"id" : "7ae3362a-2bed-4902-b6af-d7307ea4ad0b"
|
||||
}, {
|
||||
"offline" : "0",
|
||||
"clientId" : "oauth2-proxy",
|
||||
"active" : "2",
|
||||
"id" : "f7bed9b9-8fb5-4b3d-9253-c574c0b09739"
|
||||
} ]
|
||||
|
||||
=== C-1 주입검증 3: 저장소에 무엇이 늘었나 ===
|
||||
_oauth2_proxy-9aa2915c715c48b09a8916015a6f3801
|
||||
bff:session:sessions:0daf4915-a8a6-4b8e-bc97-5e58627eae23
|
||||
bff:session:sessions:b66634a2-1381-4071-8ceb-0a006fbe1327
|
||||
_oauth2_proxy-5dcd079e0be3eb8a950c6ffa5dc9b8b1
|
||||
bff:session:sessions:c5f7b0c7-cd17-4749-bf3e-6d42c814bb1c
|
||||
dbsize=5
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
=== C-1 주입검증 1: user session 과 client session 수 ===
|
||||
YwQBgnWh4dmkiknXlBVdbL6f | keycloak-patterns | 1
|
||||
1O7AtenktEMp_0MFgwFtev8o | keycloak-patterns | 1
|
||||
c4GCKTLjyfC52_JjLJuUf2GR | keycloak-patterns | 1
|
||||
Ur1NWoD6WiHMBX-oi1DvDrEe | keycloak-patterns | 1
|
||||
q2LCg3GRdG8acMlSYRXdJ-XF | keycloak-patterns | 1
|
||||
rjpU8hkBoDdgWG6duNzadrgn | keycloak-patterns | 1
|
||||
tIbyDHzlcDUxD6Ke65juXHlE | keycloak-patterns | 1
|
||||
zOVsxAt2PbCKF2fIOD8_YMNe | keycloak-patterns | 1
|
||||
4i6Q7qb3Y_7Ib4mQzzsmTkzQ | keycloak-patterns | 1
|
||||
V0mkutuu-0tNdmvHBfWucB9j | keycloak-patterns | 2
|
||||
(16 rows)
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
Server: 10.43.0.10
|
||||
Address: 10.43.0.10:53
|
||||
|
||||
|
||||
Name: app1.hyeonworks.com
|
||||
Address: 192.168.122.10
|
||||
|
||||
--- HTTPS ---
|
||||
All commands and output from this session will be recorded in container logs, including credentials and sensitive information passed through the command prompt.
|
||||
If you don't see a command prompt, try pressing enter.
|
||||
app1 200
|
||||
curl exit=0
|
||||
pod "c2probe" deleted from keycloak-lab namespace
|
||||
=== NetworkPolicy 가 있나 ===
|
||||
No resources found in keycloak-lab namespace.
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
-rw-r--r-- 1 root root 4882 Sep 4 08:22 fullchain2.pem
|
||||
-rw-r--r-- 1 root root 4882 Sep 4 12:29 fullchain3.pem
|
||||
-rw------- 1 root root 241 Sep 3 01:47 privkey1.pem
|
||||
-rw------- 1 root root 241 Sep 4 08:22 privkey2.pem
|
||||
-rw------- 1 root root 241 Sep 4 12:29 privkey3.pem
|
||||
--- nginx worker PID ---
|
||||
2629 4712
|
||||
--- 지금 서빙하는 인증서의 notBefore ---
|
||||
notBefore=Sep 4 11:29:18 2026 GMT
|
||||
notAfter=Dec 3 11:29:17 2026 GMT
|
||||
serial=06F3E0EF4D1BB03DE58130EAAD1176101373
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
=== D-4 5단계: 타이머 ===
|
||||
|
||||
0 timers listed.
|
||||
Pass --all to see loaded but inactive timers, too.
|
||||
--- 엣지 쪽
|
||||
Thu 2026-09-17 17:06:05 UTC 9h left - - certbot.timer certbot.service
|
||||
|
||||
=== D-4 6단계 ① ② ③ ===
|
||||
[Unit]
|
||||
Description=Certbot
|
||||
Documentation=file:///usr/share/doc/python-certbot-doc/html/index.html
|
||||
Documentation=https://certbot.eff.org/docs
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/certbot -q renew --no-random-sleep-on-renew
|
||||
PrivateTmp=true
|
||||
---
|
||||
[Unit]
|
||||
Description=Run certbot twice daily
|
||||
[Timer]
|
||||
OnCalendar=*-*-* 00,12:00:00
|
||||
RandomizedDelaySec=43200
|
||||
Persistent=true
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
---
|
||||
total 0
|
||||
|
||||
=== D-4 7단계를 문서 그대로: [test-server] 에서 ===
|
||||
(줄 수: 3)
|
||||
|
||||
=== 같은 것을 엣지에서 ===
|
||||
1065 1 11145 Thu Sep 17 04:27:39 2026 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
|
||||
1106 1065 11135 Thu Sep 17 04:27:49 2026 nginx: worker process
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
certbot exit=0
|
||||
Saving debug log to /var/log/letsencrypt/letsencrypt.log
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Processing /etc/letsencrypt/renewal/auth.hyeonworks.com.conf
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Renewing an existing certificate for auth.hyeonworks.com and 2 more domains
|
||||
Hook 'deploy-hook' ran with error output:
|
||||
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
|
||||
nginx: configuration file /etc/nginx/nginx.conf test is successful
|
||||
2026/09/17 10:36:31 [notice] 4744#4744: signal process started
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Congratulations, all renewals succeeded:
|
||||
/etc/letsencrypt/live/auth.hyeonworks.com/fullchain.pem (success)
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
=== 디스크의 새 파일 ===
|
||||
-rw------- 1 root root 241 Sep 4 08:22 privkey2.pem
|
||||
-rw------- 1 root root 241 Sep 4 12:29 privkey3.pem
|
||||
-rw------- 1 root root 241 Sep 17 10:36 privkey4.pem
|
||||
|
||||
=== 지금 서빙하는 인증서 ===
|
||||
notBefore=Sep 17 09:37:58 2026 GMT
|
||||
notAfter=Dec 16 09:37:57 2026 GMT
|
||||
serial=065547991777D11A408CEA90D945DDA03DF1
|
||||
|
||||
=== nginx worker PID (갱신 전 2629 4712) ===
|
||||
4745 4754
|
||||
auth 302 verify=0
|
||||
app1 200 verify=0
|
||||
app2 302 verify=0
|
||||
@@ -0,0 +1,26 @@
|
||||
=== 1단계 출발점 워커 PID (문서대로 test-server) ===
|
||||
(랩 호스트에서는 빈손이다)
|
||||
--- 엣지에서
|
||||
1065 1 11186 Thu Sep 17 04:27:39 2026 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
|
||||
1106 1065 11177 Thu Sep 17 04:27:49 2026 nginx: worker process
|
||||
|
||||
=== 5단계 훅 파일을 만든다 ===
|
||||
#!/bin/sh
|
||||
nginx -t && nginx -s reload
|
||||
|
||||
=== 6단계 설치 ===
|
||||
exit=0
|
||||
|
||||
=== 7단계 제자리에 있나 ===
|
||||
total 4
|
||||
-rwxr-xr-x 1 root root 38 Sep 17 07:34 reload-nginx.sh
|
||||
|
||||
=== 8단계 손으로 한 번 돌린다 ===
|
||||
exit=0
|
||||
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
|
||||
nginx: configuration file /etc/nginx/nginx.conf test is successful
|
||||
2026/09/17 07:34:08 [notice] 2361#2361: signal process started
|
||||
|
||||
=== 8단계 뒤 워커 PID 재측정 ===
|
||||
1065 1 11189 Thu Sep 17 04:27:39 2026 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
|
||||
2362 1065 0 Thu Sep 17 07:34:08 2026 nginx: worker process
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
=== 엣지에 인증서가 생긴 뒤 dry-run 이 무엇을 하나 ===
|
||||
Saving debug log to /var/log/letsencrypt/letsencrypt.log
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Processing /etc/letsencrypt/renewal/auth.hyeonworks.com.conf
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Failed to renew certificate auth.hyeonworks.com with error: You should register before running non-interactively, or provide --agree-tos and --email <email_address> flags.
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
All simulated renewals failed. The following certificates could not be renewed:
|
||||
/etc/letsencrypt/live/auth.hyeonworks.com/fullchain.pem (failure)
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
1 renew failure(s), 0 parse failure(s)
|
||||
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.
|
||||
exit=0
|
||||
|
||||
=== 엣지에 자격증명 파일이 있나 ===
|
||||
ls: cannot access '/etc/letsencrypt/cloudflare.ini': No such file or directory
|
||||
1
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
certbot exit=1
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Processing /etc/letsencrypt/renewal/auth.hyeonworks.com.conf
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Failed to renew certificate auth.hyeonworks.com with error: Missing command line flag or config entry for this setting:
|
||||
Please choose an account
|
||||
Choices: ['test-server@2026-09-03T01:50:44Z (66d5)', 'kc-lab-edge@2026-09-17T08:16:31Z (5df4)']
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
All simulated renewals failed. The following certificates could not be renewed:
|
||||
/etc/letsencrypt/live/auth.hyeonworks.com/fullchain.pem (failure)
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
1 renew failure(s), 0 parse failure(s)
|
||||
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
=== 엣지의 ACME 계정이 왜 둘인가 ===
|
||||
*
|
||||
stat: cannot statx '/etc/letsencrypt/accounts/acme-v02.api.letsencrypt.org/directory/*/': No such file or directory
|
||||
|
||||
=== renewal 설정이 계정을 지목하나 ===
|
||||
8:account = 8d53f9312e2a4c9cdd13620122cd8272
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
=== 운영 디렉터리의 계정들 ===
|
||||
stat: cannot statx '$d': No such file or directory
|
||||
/etc/letsencrypt/accounts/acme-v02.api.letsencrypt.org/directory/8d53f9312e2a4c9cdd13620122cd8272/
|
||||
|
||||
=== renewal 이 지목한 계정이 그중에 있나 ===
|
||||
/etc/letsencrypt/accounts/acme-v02.api.letsencrypt.org/directory/8d53f9312e2a4c9cdd13620122cd8272
|
||||
|
||||
=== 각 계정의 regr.json 이 누구인가 ===
|
||||
/etc/letsencrypt/accounts/acme-v02.api.letsencrypt.org/directory/8d53f9312e2a4c9cdd13620122cd8272/regr.json
|
||||
acct/3702274776
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
=== staging 디렉터리의 계정들 ===
|
||||
5df435a72a89118f1699212efd5fe2fe
|
||||
66d5d86599378a0b07936733587017a6
|
||||
|
||||
=== 운영 디렉터리의 계정 수 ===
|
||||
1
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
certbot exit=0
|
||||
Saving debug log to /var/log/letsencrypt/letsencrypt.log
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Processing /etc/letsencrypt/renewal/auth.hyeonworks.com.conf
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Simulating renewal of an existing certificate for auth.hyeonworks.com and 2 more domains
|
||||
Waiting 30 seconds for DNS changes to propagate
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Congratulations, all simulated renewals succeeded:
|
||||
/etc/letsencrypt/live/auth.hyeonworks.com/fullchain.pem (success)
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
BIN
Binary file not shown.
+13
@@ -0,0 +1,13 @@
|
||||
certbot exit=0
|
||||
Saving debug log to /var/log/letsencrypt/letsencrypt.log
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Processing /etc/letsencrypt/renewal/auth.hyeonworks.com.conf
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Simulating renewal of an existing certificate for auth.hyeonworks.com and 2 more domains
|
||||
Waiting 30 seconds for DNS changes to propagate
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Congratulations, all simulated renewals succeeded:
|
||||
/etc/letsencrypt/live/auth.hyeonworks.com/fullchain.pem (success)
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
Saving debug log to /var/log/letsencrypt/letsencrypt.log
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Processing /etc/letsencrypt/renewal/auth.hyeonworks.com.conf
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Simulating renewal of an existing certificate for auth.hyeonworks.com and 2 more domains
|
||||
Waiting 30 seconds for DNS changes to propagate
|
||||
|
||||
Certbot failed to authenticate some domains (authenticator: dns-cloudflare). The Certificate Authority reported these problems:
|
||||
Domain: auth.hyeonworks.com
|
||||
Type: dns
|
||||
Detail: During secondary validation: DNS problem: NXDOMAIN looking up TXT for _acme-challenge.auth.hyeonworks.com - check that a DNS record exists for this domain
|
||||
|
||||
Hint: The Certificate Authority failed to verify the DNS TXT records created by --dns-cloudflare. Ensure the above domains are hosted by this DNS provider, or try increasing --dns-cloudflare-propagation-seconds (currently 30 seconds).
|
||||
|
||||
Failed to renew certificate auth.hyeonworks.com with error: Some challenges have failed.
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
All simulated renewals failed. The following certificates could not be renewed:
|
||||
/etc/letsencrypt/live/auth.hyeonworks.com/fullchain.pem (failure)
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
1 renew failure(s), 0 parse failure(s)
|
||||
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
=== 훅 파일 ===
|
||||
total 4
|
||||
-rwxr-xr-x 1 root root 38 Sep 17 09:23 reload-nginx.sh
|
||||
=== 성공한 dry-run 출력에 deploy-hook 이 몇 번 ===
|
||||
0
|
||||
=== certbot 판 ===
|
||||
certbot 2.1.0
|
||||
=== --run-deploy-hooks 플래그가 있나 ===
|
||||
0
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
=== 밖에서 도메인으로 — 앞서 Host 헤더로 대신했던 것을 진짜 경로로 다시 잰다 ===
|
||||
--- B-4 주입 (문서의 명령에서 https 만 http 로) ---
|
||||
대조군 : (비면 정상)
|
||||
동명 헤더 둘 : "x-auth-request-roles" : [ "admin", "editor" ]
|
||||
값 안의 쉼표 : "x-auth-request-roles" : [ "role-with,comma" ]
|
||||
신원 위조 :
|
||||
"x-auth-request-email" : [ "attacker@evil.invalid" ]
|
||||
"x-auth-request-user" : [ "attacker" ]
|
||||
--- x-forwarded-* 가 밖에서 오면 무엇이 되나 ---
|
||||
"x-forwarded-host" : [ "app1.hyeonworks.com" ]
|
||||
"x-forwarded-port" : [ "80" ]
|
||||
"x-forwarded-proto" : [ "http" ]
|
||||
"x-forwarded-server" : [ "traefik-59b7647586-t8fc7" ]
|
||||
"x-real-ip" : [ "10.42.0.1" ]
|
||||
|
||||
--- C-2 후보 셋 (밖에서) ---
|
||||
/logout/connect/back-channel/keycloak 302
|
||||
/backchannel-logout 302
|
||||
/oauth2/sign_out 302
|
||||
--- app2 (Grafana) 도 닿나 ---
|
||||
app2 302
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
=== 엣지 nginx 는 무엇을 설정하나 ===
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Forwarded-Proto http;
|
||||
proxy_set_header X-Forwarded-Port 80;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
=== 그런데 앱에 도착하는 것 ===
|
||||
"x-forwarded-host" : [ "app1.hyeonworks.com" ]
|
||||
"x-forwarded-port" : [ "80" ]
|
||||
"x-forwarded-proto" : [ "http" ]
|
||||
"x-forwarded-server" : [ "traefik-59b7647586-t8fc7" ]
|
||||
"x-real-ip" : [ "10.42.1.0" ]
|
||||
|
||||
=== 내 주소는 무엇인가 ===
|
||||
inet 100.83.212.4/32 scope global tailscale0
|
||||
|
||||
=== Traefik 이 신뢰하는 출발지 설정이 있나 ===
|
||||
(위가 비면 기본값)
|
||||
|
||||
=== 저장소에 그 설정 파일이 있다 — 적용돼 있나 ===
|
||||
# Make Traefik trust the X-Forwarded-* headers that the host nginx sets.
|
||||
#
|
||||
# Without this, Traefik rewrites every forwarded header from its own connection,
|
||||
# which is plain HTTP on port 80. The application then sees scheme=http even
|
||||
# though the browser connected over TLS. See docs/two-hop-proxy-header-contract.md.
|
||||
#
|
||||
# k3s installs Traefik through its bundled HelmChart, so values are overridden
|
||||
# with a HelmChartConfig rather than by editing the deployment. k3s reconciles
|
||||
# the chart and recreates the Traefik pod.
|
||||
#
|
||||
# kubectl apply -f deploy/lab/k8s/traefik-forwarded-headers.yaml
|
||||
# kubectl -n kube-system rollout status deploy/traefik --timeout=180s
|
||||
apiVersion: helm.cattle.io/v1
|
||||
kind: HelmChartConfig
|
||||
metadata:
|
||||
name: traefik
|
||||
namespace: kube-system
|
||||
spec:
|
||||
valuesContent: |-
|
||||
ports:
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
=== 적용 전 — 앱이 보는 것 ===
|
||||
"x-forwarded-host" : [ "app1.hyeonworks.com" ]
|
||||
"x-forwarded-port" : [ "80" ]
|
||||
"x-forwarded-proto" : [ "http" ]
|
||||
"x-forwarded-server" : [ "traefik-59b7647586-t8fc7" ]
|
||||
"x-real-ip" : [ "10.42.0.1" ]
|
||||
(x-forwarded-for 가 없다. x-real-ip 는 flannel 게이트웨이다)
|
||||
|
||||
=== 저장소의 설정 전문 ===
|
||||
apiVersion: helm.cattle.io/v1
|
||||
kind: HelmChartConfig
|
||||
metadata:
|
||||
name: traefik
|
||||
namespace: kube-system
|
||||
spec:
|
||||
valuesContent: |-
|
||||
ports:
|
||||
web:
|
||||
forwardedHeaders:
|
||||
# Requests arriving from these sources keep their existing
|
||||
# X-Forwarded-* values instead of having them rewritten.
|
||||
#
|
||||
# 10.42.0.0/16 is the pod CIDR. It is required because the traefik
|
||||
# Service uses externalTrafficPolicy: Cluster, so svclb SNATs the
|
||||
# traffic and Traefik sees a pod-network address rather than the
|
||||
# host nginx address.
|
||||
#
|
||||
# The node/host range is deliberately absent. Because svclb SNATs,
|
||||
# the host nginx address never reaches Traefik — measured, not assumed.
|
||||
# Trusting a range that cannot appear only widens the surface.
|
||||
#
|
||||
# Trusting the whole pod CIDR still means any pod in the cluster could
|
||||
# forge these headers, which is why echo-network-policy.yaml restricts
|
||||
# who may reach the application at all.
|
||||
trustedIPs:
|
||||
- 10.42.0.0/16
|
||||
websecure:
|
||||
|
||||
=== 적용한다 (파일 주석이 적어 둔 두 줄) ===
|
||||
helmchartconfig.helm.cattle.io/traefik created
|
||||
Waiting for deployment "traefik" rollout to finish: 1 old replicas are pending termination...
|
||||
Waiting for deployment "traefik" rollout to finish: 1 old replicas are pending termination...
|
||||
deployment "traefik" successfully rolled out
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
=== 적용 뒤 — 앱이 보는 것 ===
|
||||
"x-forwarded-host" : [ "app1.hyeonworks.com" ]
|
||||
"x-forwarded-port" : [ "80" ]
|
||||
"x-forwarded-proto" : [ "http" ]
|
||||
"x-forwarded-server" : [ "traefik-5d6fcf895-n8p4k" ]
|
||||
"x-real-ip" : [ "192.168.122.1" ]
|
||||
|
||||
=== 내 tailnet 주소와 견준다 ===
|
||||
"remoteAddr" : "192.168.122.1"
|
||||
호스트의 tailscale0 = 100.83.212.4 / 엣지 게스트 = 192.168.122.10
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
=== 가설: Traefik 이 보는 출발지가 trustedIPs 밖이다 ===
|
||||
앱이 본 remoteAddr = 192.168.122.1 (호스트의 virbr0)
|
||||
설정의 trustedIPs = 10.42.0.0/16 (파드 대역)
|
||||
|
||||
=== 게스트 대역을 더해서 시험한다 (저장소 파일은 안 고친다) ===
|
||||
helmchartconfig.helm.cattle.io/traefik configured
|
||||
deployment "traefik" successfully rolled out
|
||||
|
||||
=== 다시 잰다 ===
|
||||
"x-forwarded-proto" : [ "http" ]
|
||||
"x-real-ip" : [ "192.168.122.1" ]
|
||||
"remoteAddr" : "192.168.122.1"
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
=== kc-lab-edge 의 인증서 ===
|
||||
Saving debug log to /var/log/letsencrypt/letsencrypt.log
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
No certificates found.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
---
|
||||
ls: cannot access '/etc/letsencrypt/live/': No such file or directory
|
||||
|
||||
=== 엣지 nginx 가 443 을 듣나 ===
|
||||
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1106,fd=5),("nginx",pid=1065,fd=5))
|
||||
---
|
||||
keycloak-lab
|
||||
|
||||
=== 밖에서 ===
|
||||
https://auth.hyeonworks.com/realms/master 000
|
||||
https://app1.hyeonworks.com/ 000
|
||||
http://auth.hyeonworks.com/realms/master 200
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
=== 04번 1단계: 플러그인이 깔렸나 ===
|
||||
* dns-cloudflare
|
||||
* standalone
|
||||
* webroot
|
||||
|
||||
=== 04번 3단계: 자격증명 파일이 있나 (값은 안 본다) ===
|
||||
ls: cannot access '/etc/letsencrypt/cloudflare.ini': No such file or directory
|
||||
wc: /etc/letsencrypt/cloudflare.ini: No such file or directory
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
=== 엣지 nginx 가 X-Forwarded-For 를 세우나 ===
|
||||
8: listen 80 default_server;
|
||||
9: server_name _;
|
||||
12: proxy_pass http://k3s_traefik;
|
||||
14: proxy_set_header Host $host;
|
||||
15: proxy_set_header X-Forwarded-Host $host;
|
||||
16: proxy_set_header X-Forwarded-Proto http;
|
||||
17: proxy_set_header X-Forwarded-Port 80;
|
||||
18: proxy_set_header X-Forwarded-For $remote_addr;
|
||||
19: proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
=== app1 은 엣지를 거치나 — 엣지 access log 마지막 3줄 ===
|
||||
192.168.122.1 - - [17/Sep/2026:07:10:45 +0000] "GET /api/echo HTTP/1.1" 200 617 "-" "curl/8.5.0"
|
||||
192.168.122.1 - - [17/Sep/2026:07:11:33 +0000] "GET /realms/master HTTP/1.1" 200 602 "-" "curl/8.5.0"
|
||||
192.168.122.1 - - [17/Sep/2026:07:12:01 +0000] "GET /api/echo HTTP/1.1" 200 617 "-" "curl/8.5.0"
|
||||
|
||||
=== http 로 토큰 엔드포인트가 도나 (이게 되면 b·c 편은 TLS 없이 돈다) ===
|
||||
well-known 200
|
||||
token 401
|
||||
@@ -0,0 +1,21 @@
|
||||
=== 앱이 실제로 받은 헤더 전부 (trustedIPs 에 게스트 대역을 더한 상태) ===
|
||||
{
|
||||
"headers" : {
|
||||
"host" : [ "app1.hyeonworks.com" ],
|
||||
"user-agent" : [ "curl/8.5.0" ],
|
||||
"accept" : [ "*/*" ],
|
||||
"x-forwarded-host" : [ "app1.hyeonworks.com" ],
|
||||
"x-forwarded-port" : [ "80" ],
|
||||
"x-forwarded-proto" : [ "http" ],
|
||||
"x-forwarded-server" : [ "traefik-697889c85-jqcjn" ],
|
||||
"x-real-ip" : [ "192.168.122.1" ],
|
||||
"accept-encoding" : [ "gzip" ]
|
||||
},
|
||||
"remoteAddr" : "192.168.122.1",
|
||||
"localAddr" : "10.42.0.27",
|
||||
"scheme" : "http",
|
||||
"secure" : false,
|
||||
"serverName" : "app1.hyeonworks.com",
|
||||
"serverPort" : 80,
|
||||
"requestUrl" : "http://app1.hyeonworks.com/api/echo"
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
=== 저장소 판으로 되돌린다 ===
|
||||
helmchartconfig.helm.cattle.io/traefik configured
|
||||
deployment "traefik" successfully rolled out
|
||||
|
||||
=== 호스트에서 출발지를 바꾸는 규칙이 있나 ===
|
||||
--- libvirt
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
=== 저장소 판만 적용한 상태에서 다시 잰다 ===
|
||||
ports:
|
||||
web:
|
||||
forwardedHeaders:
|
||||
# Requests arriving from these sources keep their existing
|
||||
# X-Forwarded-* values instead of having them rewritten.
|
||||
#
|
||||
# 10.42.0.0/16 is the pod CIDR. It is required because the traefik
|
||||
# Service uses externalTrafficPolicy: Cluster, so svclb SNATs the
|
||||
# traffic and Traefik sees a pod-network address rather than the
|
||||
# host nginx address.
|
||||
#
|
||||
# The node/host range is deliberately absent. Because svclb SNATs,
|
||||
# the host nginx address never reaches Traefik — measured, not assumed.
|
||||
# Trusting a range that cannot appear only widens the surface.
|
||||
#
|
||||
# Trusting the whole pod CIDR still means any pod in the cluster could
|
||||
# forge these headers, which is why echo-network-policy.yaml restricts
|
||||
# who may reach the application at all.
|
||||
trustedIPs:
|
||||
- 10.42.0.0/16
|
||||
websecure:
|
||||
forwardedHeaders:
|
||||
trustedIPs:
|
||||
- 10.42.0.0/16
|
||||
--- 앱이 받은 것
|
||||
{
|
||||
"headers" : {
|
||||
"host" : [ "app1.hyeonworks.com" ],
|
||||
"user-agent" : [ "curl/8.5.0" ],
|
||||
"accept" : [ "*/*" ],
|
||||
"x-forwarded-host" : [ "app1.hyeonworks.com" ],
|
||||
"x-forwarded-port" : [ "80" ],
|
||||
"x-forwarded-proto" : [ "http" ],
|
||||
"x-forwarded-server" : [ "traefik-5d6fcf895-xmqp6" ],
|
||||
"x-real-ip" : [ "192.168.122.1" ],
|
||||
"accept-encoding" : [ "gzip" ]
|
||||
},
|
||||
"remoteAddr" : "192.168.122.1",
|
||||
"localAddr" : "10.42.0.27",
|
||||
"scheme" : "http",
|
||||
"secure" : false,
|
||||
"serverName" : "app1.hyeonworks.com",
|
||||
"serverPort" : 80,
|
||||
"requestUrl" : "http://app1.hyeonworks.com/api/echo"
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
=== 이 curl 은 어디서 어디로 가나 ===
|
||||
100.83.212.4 app1.hyeonworks.com
|
||||
100.83.212.4 auth.hyeonworks.com
|
||||
|
||||
=== 호스트의 DNAT 파일 (sudo 없이 읽히나) ===
|
||||
#!/usr/sbin/nft -f
|
||||
table ip lab_edge
|
||||
delete table ip lab_edge
|
||||
|
||||
table ip lab_edge {
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority dstnat; policy accept;
|
||||
iifname "tailscale0" tcp dport {80, 443} dnat to 192.168.122.10
|
||||
}
|
||||
|
||||
chain forward {
|
||||
type filter hook forward priority filter - 10; policy accept;
|
||||
ip daddr 192.168.122.10 tcp dport {80, 443} ct state new accept
|
||||
}
|
||||
}
|
||||
|
||||
=== lab_edge 테이블 실물 ===
|
||||
sudo: a password is required
|
||||
exit=1
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
=== http 로 로그인 체인이 도나 ===
|
||||
oauth2 진입 302 -> https://auth.hyeonworks.com/realms/keycloak-patterns/protocol/openid-connect/auth?response_type=code&client_id=bff-confidential&scope=openid%20profile%20email&state=Vt28FHS-cuqr7NcdUaR6xjPOs2zreT0crThNPaGjDuQ%3D&redirect_uri=http://app1.hyeonworks.com/login/oauth2/code/keycloak&nonce=s14SFB1opH_jb0_IQKSx65X6FrtD4-8svAS8qfTQQwU&code_challenge=iv0wxqu3JsnSsT-f07hRh1UCwei4WHBZiDNGw-TATvA&code_challenge_method=S256
|
||||
|
||||
=== 그 리다이렉트를 따라가 본다 (3홉) ===
|
||||
final 302 https://auth.hyeonworks.com/realms/keycloak-patterns/protocol/openid-connect/auth?response_type=code&client_id=bff-confidential&scope=openid%20profile%20email&state=ATjUt4POkZvWTWfeYJHZxH4uYbJGdIcMDjw0yYmXTW8%3D&redirect_uri=http://app1.hyeonworks.com/login/oauth2/code/keycloak&nonce=R7GTKPxRn-hNvjvcsYTH_Zpw32wrlD7h376XQ1d5I2I&code_challenge=C9PP9r8Oze2mzwC6AusVE19CKx6-xHoQ1fxZwHO7PRM&code_challenge_method=S256
|
||||
|
||||
=== 등록된 redirectUris ===
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
=== 파드 안에서 공개 이름이 무엇으로 풀리나 ===
|
||||
100.83.212.4 auth.hyeonworks.com
|
||||
100.83.212.4 app1.hyeonworks.com
|
||||
|
||||
=== 파드에서 그 주소의 80·443 에 닿나 ===
|
||||
100.83.212.4:80 닫힘
|
||||
100.83.212.4:443 닫힘
|
||||
192.168.122.10(엣지):80 열림
|
||||
192.168.122.10(엣지):443 닫힘
|
||||
|
||||
=== CoreDNS 에 이 이름을 돌리는 설정이 있나 ===
|
||||
# File managed by k3s. DO NOT EDIT.
|
||||
# See: https://docs.k3s.io/advanced#coredns-custom-configuration-imports
|
||||
.:53 {
|
||||
errors
|
||||
health
|
||||
ready
|
||||
kubernetes cluster.local in-addr.arpa ip6.arpa {
|
||||
pods insecure
|
||||
fallthrough in-addr.arpa ip6.arpa
|
||||
}
|
||||
hosts /etc/coredns/NodeHosts {
|
||||
ttl 60
|
||||
reload 15s
|
||||
fallthrough
|
||||
}
|
||||
prometheus :9153
|
||||
cache 30
|
||||
loop
|
||||
reload
|
||||
loadbalance
|
||||
import /etc/coredns/custom/*.override
|
||||
forward . /etc/resolv.conf
|
||||
}
|
||||
import /etc/coredns/custom/*.server
|
||||
|
||||
--- NodeHosts
|
||||
192.168.122.11 kc-lab-1
|
||||
192.168.122.12 kc-lab-2
|
||||
|
||||
|
||||
=== 노드의 /etc/hosts 에 있나 ===
|
||||
(없음)
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
=== CoreDNS 에 엣지로 보내는 항목을 더한다 (k3s 의 custom override) ===
|
||||
configmap/coredns-custom created
|
||||
deployment.apps/coredns restarted
|
||||
Waiting for deployment "coredns" rollout to finish: 0 of 1 updated replicas are available...
|
||||
error: timed out waiting for the condition
|
||||
|
||||
=== 파드에서 다시 ===
|
||||
80 닫힘
|
||||
|
||||
=== echo 를 다시 띄워 JWKS 를 받게 해 본다 (여전히 https 라 실패해야 정상) ===
|
||||
deployment "echo" successfully rolled out
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
=== 실패 원인 ===
|
||||
plugin/hosts: this plugin can only be used once per Server Block
|
||||
k3s Corefile 이 이미 hosts /etc/coredns/NodeHosts 를 쓴다. override 는 같은 블록에 들어간다.
|
||||
|
||||
=== 별도 서버 블록(.server)으로 고쳐 넣는다 ===
|
||||
configmap/coredns-custom configured
|
||||
coredns-747f7ff557-c8f9q 1/1 Running 0 30s
|
||||
--- 로그
|
||||
.:53
|
||||
hyeonworks.com.:53
|
||||
[WARNING] No files matching import glob pattern: /etc/coredns/custom/*.override
|
||||
[INFO] plugin/reload: Running configuration SHA512 = bbef792a18068d14383e2aae31d25d75edca67dfea52ee28e28117264f318981634c941f3626af4eed0f5f0d9866ddac82f13668a8f19b5a353fae28e695f24d
|
||||
CoreDNS-1.14.6
|
||||
linux/amd64, go1.26.5, 424d125
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
=== 파드에서 다시 푼다 ===
|
||||
192.168.122.10 auth.hyeonworks.com
|
||||
192.168.122.10 app1.hyeonworks.com
|
||||
192.168.122.10:80 열림
|
||||
192.168.122.10:443 닫힘
|
||||
|
||||
=== 클러스터 안에서 realm 을 받아 본다 (http) ===
|
||||
sh: line 1: curl: command not found
|
||||
command terminated with exit code 127
|
||||
@@ -0,0 +1,14 @@
|
||||
=== B-7 6단계 ② 두 cookie secret 의 길이만 (값은 안 본다) ===
|
||||
32
|
||||
32
|
||||
|
||||
=== B-7a 6단계 R 함수와 스캔 루프 ===
|
||||
(위가 비면 세션 키가 없는 것이다) dbsize=3
|
||||
|
||||
=== D-4a 8단계 dry-run 으로 훅 호출만 본다 ===
|
||||
Saving debug log to /var/log/letsencrypt/letsencrypt.log
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
No simulated renewals were attempted.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
exit=0
|
||||
+9
-4
@@ -57,6 +57,8 @@ PostgreSQL 을 정상 종료시키고 refresh 와 새 로그인과 관리 API
|
||||
| 정지 구간 | 1분 남짓. 그동안 정문이 실제로 `503` 이 된다 |
|
||||
| 도구 | `jq` 가 이 실험대에 없다. Prometheus 출력은 `tr` 과 `grep` 으로 자른다 |
|
||||
|
||||
**공개 이름은 랩 안에서 안 풀린다.** `auth.hyeonworks.com` 같은 공개 이름이 랩 호스트에서도 게스트에서도 호스트 자신의 tailnet 주소 `100.83.212.4` 로 풀리는데 그 주소에는 443 을 듣는 것이 없다. 이름만 치면 `curl` 이 `000` 을 낸다(2026-09-17, 랩 호스트와 `kc-lab-1` 양쪽에서 쳐서 확인했다, observed). 그래서 랩 안에서 치는 `curl` 에는 `--resolve <이름>:443:192.168.122.10` 을 붙여 엣지 게스트를 짚었고, 그 형태로는 정문이 `200` 이다(observed). tailnet 에 붙은 다른 기계에서 치면 이름 그대로 닿으므로 `--resolve` 가 필요 없다.
|
||||
|
||||
## 이 실험이 가르는 것
|
||||
|
||||
A-1 에서 룩어사이드 캐시는 읽을 때 데이터베이스와 대조하지 않는다는 것을 확인했다. 로그아웃되어 DB 행이 사라진 세션에 대해서도 캐시를 가진 노드가 `200` 을 줬다. 그렇다면 캐시를 가진 노드는 DB 없이도 버틸지 모른다. 캐시가 DB 를 대신한다면 그 노드는 살아남아 부분 장애가 되고, 대신하지 못한다면 전면 장애가 된다.
|
||||
@@ -294,7 +296,8 @@ curl -s -o /dev/null -w 'well-known %{http_code}\n' \
|
||||
밖에서 정문도 재 둔다.
|
||||
|
||||
```bash label="[lab host] 밖에서 본 정문"
|
||||
curl -s -o /dev/null -w '%{http_code}\n' https://auth.hyeonworks.com/realms/master
|
||||
curl -s -o /dev/null -w '%{http_code}\n' --resolve auth.hyeonworks.com:443:192.168.122.10 \
|
||||
https://auth.hyeonworks.com/realms/master
|
||||
```
|
||||
|
||||
## 주입
|
||||
@@ -518,8 +521,9 @@ kubectl -n keycloak-lab describe svc keycloak | grep -i endpoints
|
||||
밖에서 본다. 한 번 눈으로 볼 때는 헤더까지 본다.
|
||||
|
||||
```bash label="[lab host] 정문을 코드로 한 번, 헤더로 한 번"
|
||||
curl -s -o /dev/null -w '%{http_code}\n' https://auth.hyeonworks.com/realms/master
|
||||
curl -I https://auth.hyeonworks.com/realms/master
|
||||
curl -s -o /dev/null -w '%{http_code}\n' --resolve auth.hyeonworks.com:443:192.168.122.10 \
|
||||
https://auth.hyeonworks.com/realms/master
|
||||
curl -I --resolve auth.hyeonworks.com:443:192.168.122.10 https://auth.hyeonworks.com/realms/master
|
||||
```
|
||||
|
||||
실측은 `https://auth.hyeonworks.com/realms/master HTTP 503` 이다(observed). 이 `503` 은 Keycloak 이 준 것이 아니다. Ready 인 백엔드가 하나도 없어서 그 앞의 프록시가 준 것이고, `200` 이던 JWKS 도 정문으로는 닿지 않는다.
|
||||
@@ -640,7 +644,8 @@ deployment "postgres" successfully rolled out
|
||||
```bash label="[lab host] ① Ready 와 정문을 함께 친다"
|
||||
kubectl -n keycloak-lab get pods -o "custom-columns=NAME:.metadata.name,READY:.status.containerStatuses[0].ready,RESTARTS:.status.containerStatuses[0].restartCount" \
|
||||
| grep keycloak
|
||||
curl -s -o /dev/null -w '%{http_code}\n' https://auth.hyeonworks.com/realms/master
|
||||
curl -s -o /dev/null -w '%{http_code}\n' --resolve auth.hyeonworks.com:443:192.168.122.10 \
|
||||
https://auth.hyeonworks.com/realms/master
|
||||
```
|
||||
|
||||
```bash label="[lab host] ② 재시작 횟수만 따로 센다"
|
||||
|
||||
+32
-6
@@ -56,6 +56,8 @@ sourceRevision: cdac9b8178391311d8eca1ebc6cac15bb62d79af
|
||||
| 걸리는 시간 | 전 구간 약 40분. 4a 의 축출을 보는 데만 7분 |
|
||||
| 되돌리기 | `virsh start`. `--grace-period=0 --force` 로 파드를 지우지 않는다 |
|
||||
|
||||
**공개 이름은 랩 안에서 안 풀린다.** `auth.hyeonworks.com` 같은 공개 이름이 랩 호스트에서도 게스트에서도 호스트 자신의 tailnet 주소 `100.83.212.4` 로 풀리는데 그 주소에는 443 을 듣는 것이 없다. 이름만 치면 `curl` 이 `000` 을 낸다(2026-09-17, 랩 호스트와 `kc-lab-1` 양쪽에서 쳐서 확인했다, observed). 그래서 랩 안에서 치는 `curl` 에는 `--resolve <이름>:443:192.168.122.10` 을 붙여 엣지 게스트를 짚었고, 그 형태로는 정문이 `200` 이다(observed). tailnet 에 붙은 다른 기계에서 치면 이름 그대로 닿으므로 `--resolve` 가 필요 없다.
|
||||
|
||||
## 이 실험이 가르는 것
|
||||
|
||||
A-1 과 A-5 는 네트워크만 끊는다. 파드는 살아 있고 쿠버네티스는 계속 정확한 상태를 안다. 여기서는 기계 자체를 없애므로 상태를 보고할 주체가 사라진다.
|
||||
@@ -197,11 +199,13 @@ kubectl get pv $(kubectl -n keycloak-lab get pvc postgres-data \
|
||||
**무엇을 확인하는가** — 정문이 지금 무엇을 답하는지, 그리고 Prometheus 와 Grafana 가 어느 노드에 있는지.
|
||||
|
||||
```bash label="[터미널 C] ① 응답을 통째로 읽는 형태"
|
||||
curl -I --max-time 8 https://auth.hyeonworks.com/realms/master
|
||||
curl -I --max-time 8 --resolve auth.hyeonworks.com:443:192.168.122.10 \
|
||||
https://auth.hyeonworks.com/realms/master
|
||||
```
|
||||
|
||||
```bash label="[터미널 C] ② 여러 번 비교할 것이므로 코드만 뽑는 형태"
|
||||
curl -s -o /dev/null -w '%{http_code}\n' --max-time 8 https://auth.hyeonworks.com/realms/master
|
||||
curl -s -o /dev/null -w '%{http_code}\n' --max-time 8 --resolve auth.hyeonworks.com:443:192.168.122.10 \
|
||||
https://auth.hyeonworks.com/realms/master
|
||||
```
|
||||
|
||||
```bash label="[터미널 B] ③ 관측 스택이 어느 노드에 있나"
|
||||
@@ -323,7 +327,8 @@ kubectl get node kc-lab-2
|
||||
```
|
||||
|
||||
```bash label="[터미널 C] ② 같은 간격으로 밖에서"
|
||||
curl -s -o /dev/null -w '%{http_code}\n' --max-time 8 https://auth.hyeonworks.com/realms/master
|
||||
curl -s -o /dev/null -w '%{http_code}\n' --max-time 8 --resolve auth.hyeonworks.com:443:192.168.122.10 \
|
||||
https://auth.hyeonworks.com/realms/master
|
||||
```
|
||||
|
||||
손이 아프면 한 줄로 묶는 형태가 있고, 그 루프는 미검증이다. `Ctrl-C` 로 멈춘다.
|
||||
@@ -333,7 +338,7 @@ while true; do
|
||||
printf '%s node=%s 외부=%s\n' "$(date +%H:%M:%S)" \
|
||||
"$(kubectl get node kc-lab-2 --no-headers | awk '{print $2}')" \
|
||||
"$(curl -s -o /dev/null -w '%{http_code}' --max-time 8 \
|
||||
https://auth.hyeonworks.com/realms/master)"
|
||||
--resolve auth.hyeonworks.com:443:192.168.122.10 https://auth.hyeonworks.com/realms/master)"
|
||||
sleep 15
|
||||
done
|
||||
```
|
||||
@@ -610,13 +615,33 @@ ssh kc-lab-2 'sudo crictl --runtime-endpoint unix:///run/k3s/containerd/containe
|
||||
### 9. 4b — 밖에서는 두 주소를 함께 본다
|
||||
|
||||
```bash label="[터미널 C] ① 20초 간격으로, 인증 서버"
|
||||
curl -s -o /dev/null -w 'auth=%{http_code}\n' --max-time 8 https://auth.hyeonworks.com/realms/master
|
||||
curl -s -o /dev/null -w 'auth=%{http_code}\n' --max-time 8 --resolve auth.hyeonworks.com:443:192.168.122.10 \
|
||||
https://auth.hyeonworks.com/realms/master
|
||||
```
|
||||
|
||||
```bash label="[터미널 C] ② 같은 간격으로, Grafana"
|
||||
curl -s -o /dev/null -w 'grafana=%{http_code}\n' --max-time 8 https://grafana.hyeonworks.com/
|
||||
```
|
||||
|
||||
**★ ② 는 이 배치에서 `000` 밖에 못 낸다 — 노드가 살아 있어도 그렇다**(2026-09-17, observed). 원래 실행은 여기서 `502` 와 `000` 이 갈렸는데 지금은 처음부터 `000` 이라 판정에 못 쓴다. 이유가 이름 해석이 아니라 **인증서**다.
|
||||
|
||||
```bash label="[lab host] 왜 000 인지 세 단계로 가른다"
|
||||
curl -s -o /dev/null --max-time 8 --resolve grafana.hyeonworks.com:443:192.168.122.10 https://grafana.hyeonworks.com/ ; echo "curl exit=$?"
|
||||
curl -sk -o /dev/null -w 'grafana=%{http_code}\n' --max-time 8 --resolve grafana.hyeonworks.com:443:192.168.122.10 https://grafana.hyeonworks.com/
|
||||
echo | openssl s_client -connect 192.168.122.10:443 -servername auth.hyeonworks.com 2>/dev/null | openssl x509 -noout -ext subjectAltName
|
||||
```
|
||||
|
||||
```text label="이 실험대의 값"
|
||||
curl exit=60
|
||||
grafana=404
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:app1.hyeonworks.com, DNS:app2.hyeonworks.com, DNS:auth.hyeonworks.com
|
||||
```
|
||||
|
||||
`curl exit=60` 은 인증서 검증 실패다. 엣지의 인증서가 덮는 이름은 셋뿐이라 `grafana.hyeonworks.com` 은 TLS 단계에서 끝나고 HTTP 는 시작도 안 한다. `-k` 로 검증을 끄면 그제서야 nginx 가 답하는데 `404` 다 — 그 이름으로 갈 곳이 없다. 가이드 06 도 **Grafana 는 밖에 열지 않고 `port-forward svc/grafana 3000:3000` 으로 본다**고 적어 둔다.
|
||||
|
||||
**그래서 ② 는 이 절의 신호가 못 된다.** 판정은 `auth` 쪽 ① 로 한다. 관측 스택이 살아 있는지를 밖에서 보려면 `port-forward` 를 띄운 터미널이 끊기는지로 보거나, 04 의 인증서에 이름을 더하고 엣지에 서버 블록을 올려야 한다(unknown — 이 실험대는 안 했다).
|
||||
|
||||
```text
|
||||
+20초 외부 auth=000 grafana=000 | kubectl: Unable to connect to the server: dial tcp
|
||||
+60초 외부 auth=000 grafana=000 | kubectl: Unable to connect to the server: dial tcp
|
||||
@@ -656,7 +681,8 @@ kubectl -n keycloak-lab get pods
|
||||
```
|
||||
|
||||
```bash label="[터미널 C] ⑤ 같은 간격으로 밖에서"
|
||||
curl -s -o /dev/null -w '%{http_code}\n' --max-time 8 https://auth.hyeonworks.com/realms/master
|
||||
curl -s -o /dev/null -w '%{http_code}\n' --max-time 8 --resolve auth.hyeonworks.com:443:192.168.122.10 \
|
||||
https://auth.hyeonworks.com/realms/master
|
||||
```
|
||||
|
||||
**예상 결과**
|
||||
|
||||
+10
-4
@@ -59,6 +59,8 @@ sourceRevision: cdac9b8178391311d8eca1ebc6cac15bb62d79af
|
||||
| 걸리는 시간 | 전 구간 약 30분 |
|
||||
| 도구 | `jq` 가 이 실험대에 없다. Prometheus 출력은 `tr` 과 `grep` 으로 자른다 |
|
||||
|
||||
**공개 이름은 랩 안에서 안 풀린다.** `auth.hyeonworks.com` 같은 공개 이름이 랩 호스트에서도 게스트에서도 호스트 자신의 tailnet 주소 `100.83.212.4` 로 풀리는데 그 주소에는 443 을 듣는 것이 없다. 이름만 치면 `curl` 이 `000` 을 낸다(2026-09-17, 랩 호스트와 `kc-lab-1` 양쪽에서 쳐서 확인했다, observed). 그래서 랩 안에서 치는 `curl` 에는 `--resolve <이름>:443:192.168.122.10` 을 붙여 엣지 게스트를 짚었고, 그 형태로는 정문이 `200` 이다(observed). tailnet 에 붙은 다른 기계에서 치면 이름 그대로 닿으므로 `--resolve` 가 필요 없다.
|
||||
|
||||
## 이 실험이 가르는 것
|
||||
|
||||
A-1 이 답하지 못하고 넘긴 물음에서 출발한다. 가이드는 그 물음을 그대로 인용한다.
|
||||
@@ -276,11 +278,13 @@ ESTABLISHED src=10.42.1.77 dst=10.42.0.42 sport=60485 dport=7800
|
||||
**무엇을 확인하는가** — 정문이 지금 무엇을 답하는지.
|
||||
|
||||
```bash label="[lab host] ① 응답을 통째로 읽는 형태"
|
||||
curl -I --max-time 8 https://auth.hyeonworks.com/realms/master
|
||||
curl -I --max-time 8 --resolve auth.hyeonworks.com:443:192.168.122.10 \
|
||||
https://auth.hyeonworks.com/realms/master
|
||||
```
|
||||
|
||||
```bash label="[lab host] ② 여러 번 비교할 것이므로 코드만 뽑는 형태"
|
||||
curl -s -o /dev/null -w '%{http_code}\n' --max-time 8 https://auth.hyeonworks.com/realms/master
|
||||
curl -s -o /dev/null -w '%{http_code}\n' --max-time 8 --resolve auth.hyeonworks.com:443:192.168.122.10 \
|
||||
https://auth.hyeonworks.com/realms/master
|
||||
```
|
||||
|
||||
**출력에서 답이 되는 것** — `200` 이어야 한다.
|
||||
@@ -584,7 +588,8 @@ kubectl -n keycloak-lab get pods | grep keycloak
|
||||
```
|
||||
|
||||
```bash label="[lab host] ② 같은 간격으로 밖에서"
|
||||
curl -s -o /dev/null -w '%{http_code}\n' --max-time 8 https://auth.hyeonworks.com/realms/master
|
||||
curl -s -o /dev/null -w '%{http_code}\n' --max-time 8 --resolve auth.hyeonworks.com:443:192.168.122.10 \
|
||||
https://auth.hyeonworks.com/realms/master
|
||||
```
|
||||
|
||||
```text
|
||||
@@ -690,7 +695,8 @@ kubectl -n keycloak-lab get endpointslice -l kubernetes.io/service-name=keycloak
|
||||
```
|
||||
|
||||
```bash label="[lab host] ③ 같은 간격으로 밖에서"
|
||||
curl -s -o /dev/null -w '%{http_code}\n' --max-time 8 https://auth.hyeonworks.com/realms/master
|
||||
curl -s -o /dev/null -w '%{http_code}\n' --max-time 8 --resolve auth.hyeonworks.com:443:192.168.122.10 \
|
||||
https://auth.hyeonworks.com/realms/master
|
||||
```
|
||||
|
||||
```text
|
||||
|
||||
+70
-2
@@ -263,6 +263,30 @@ agroal_creation_time_total_milliseconds
|
||||
agroal_destroy_count_total
|
||||
```
|
||||
|
||||
**★ 같은 줄을 2026-09-17 에 쳤더니 모양이 달랐다**(observed). `grep` 은 이름만 남기지 않는다. 지표 한 줄을 통째로 내보내므로 레이블과 값이 함께 나오고, 순서도 알파벳순이 아니다. 열일곱 줄이 나왔고 그 안에 `agroal_max_used_count` 가 이미 있었다.
|
||||
|
||||
```text
|
||||
agroal_invalid_count_total{datasource="default"} 0.0
|
||||
agroal_flush_count_total{datasource="default"} 0.0
|
||||
agroal_leak_detection_count_total{datasource="default"} 0.0
|
||||
agroal_reap_count_total{datasource="default"} 3.0
|
||||
agroal_blocking_time_max_milliseconds{datasource="default"} 112.0
|
||||
agroal_max_used_count{datasource="default"} 3.0
|
||||
agroal_acquire_count_total{datasource="default"} 1908.0
|
||||
agroal_active_count{datasource="default"} 0.0
|
||||
agroal_awaiting_count{datasource="default"} 0.0
|
||||
agroal_blocking_time_average_milliseconds{datasource="default"} 0.0
|
||||
agroal_creation_time_total_milliseconds{datasource="default"} 160.0
|
||||
agroal_creation_time_average_milliseconds{datasource="default"} 32.0
|
||||
agroal_destroy_count_total{datasource="default"} 3.0
|
||||
agroal_available_count{datasource="default"} 2.0
|
||||
agroal_creation_count_total{datasource="default"} 5.0
|
||||
agroal_creation_time_max_milliseconds{datasource="default"} 105.0
|
||||
agroal_blocking_time_total_milliseconds{datasource="default"} 285.0
|
||||
```
|
||||
|
||||
이름만 늘어놓고 보려면 `| awk '{print $1}' | sort` 를 붙인다. 위의 열두 줄이 이름뿐인 것은 원 실행이 그렇게 다듬어 남겼기 때문이다(inferred).
|
||||
|
||||
**출력에서 답이 되는 것** — 열두 줄 가운데 뒤에서 쓰는 넷이다.
|
||||
|
||||
| 지표 | 무엇을 말하는가 |
|
||||
@@ -663,6 +687,21 @@ kubectl -n keycloak-lab exec a6-probe -- sh -c \
|
||||
agroal_available_count 19.0
|
||||
```
|
||||
|
||||
**★ 이 정규식은 `blocking_time_total` 도 함께 잡는다**(2026-09-17, observed). 같은 줄을 쳤더니 여덟 줄이 나왔다. 위 일곱 줄에 `agroal_blocking_time_total_milliseconds` 가 하나 더 붙고, 지표마다 `{datasource="default"}` 가 달려 있다.
|
||||
|
||||
```text
|
||||
agroal_blocking_time_max_milliseconds{datasource="default"} 20000.0
|
||||
agroal_max_used_count{datasource="default"} 18.0
|
||||
agroal_acquire_count_total{datasource="default"} 2020.0
|
||||
agroal_active_count{datasource="default"} 0.0
|
||||
agroal_awaiting_count{datasource="default"} 0.0
|
||||
agroal_blocking_time_average_milliseconds{datasource="default"} 114.0
|
||||
agroal_available_count{datasource="default"} 18.0
|
||||
agroal_blocking_time_total_milliseconds{datasource="default"} 230680.0
|
||||
```
|
||||
|
||||
`blocking_time_max` 는 여기서도 `20000.0` 이었다.
|
||||
|
||||
| 값 | 읽는 법 |
|
||||
|---|---|
|
||||
| `blocking_time_max 20000.0` | 커넥션을 받으려고 20초를 기다린 요청이 있었다 |
|
||||
@@ -751,6 +790,8 @@ kubectl -n keycloak-lab logs keycloak-1 --since=20m \
|
||||
관련 로그 줄수: 0
|
||||
```
|
||||
|
||||
**★ 그 줄을 2026-09-17 에 쳤다**(observed). 출력은 `0` 이고 종료 코드는 `1` 이다 — `grep -c` 는 센 값이 0 이면 1 로 끝난다. 뒤에 `&&` 로 다른 명령을 이어 붙이면 그 명령이 안 돈다.
|
||||
|
||||
하나도 없었고 까닭이 명확하다.
|
||||
|
||||
```text
|
||||
@@ -827,7 +868,33 @@ kubectl -n keycloak-lab delete pod a6-probe --ignore-not-found
|
||||
| Service | `kubectl -n keycloak-lab get endpointslice -l kubernetes.io/service-name=keycloak` | ready 주소 둘 |
|
||||
| 풀 | `agroal_awaiting_count` · `agroal_active_count` | `0` |
|
||||
| 탐침 파드 | `kubectl -n keycloak-lab get pod a6-probe` | 지웠으면 `NotFound` |
|
||||
| 밖 | `curl -s -o /dev/null -w '%{http_code}\n' https://auth.hyeonworks.com/realms/master` | `200` |
|
||||
| 밖 | `curl -s -o /dev/null -w '%{http_code}\n' --resolve auth.hyeonworks.com:443:192.168.122.10 https://auth.hyeonworks.com/realms/master` | `200` |
|
||||
|
||||
**★ 이 표의 두 줄은 이 실험대에서 답이 달랐다**(2026-09-17, observed).
|
||||
|
||||
`enp1s0` 쪽은 비어 있지 않다. 이 게스트의 기본 qdisc 가 `fq_codel` 이라 아무것도 안 걸었을 때도 한 줄이 나온다. 잔재가 없다는 것은 그 줄에 `netem` 이나 `prio` 가 안 보인다는 뜻이다.
|
||||
|
||||
```text
|
||||
qdisc fq_codel 0: root refcnt 2 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64
|
||||
```
|
||||
|
||||
마지막 줄에 `--resolve` 가 붙어 있는 까닭이다. 원 가이드는 이름만 쳤는데 `auth.hyeonworks.com` 이 lab host 에서 `100.83.212.4` 로 풀리고 그 주소의 443 이 닫혀 있어, 그 형태는 `000` 을 찍고 `curl` 은 `7` 로 끝난다. `kc-lab-edge` 에서 쳐도 같은 값이다.
|
||||
|
||||
```bash label="[lab host] 원 가이드가 적은 형태 — 이 실험대에서는 000 이다"
|
||||
curl -s -o /dev/null -w '%{http_code}\n' https://auth.hyeonworks.com/realms/master
|
||||
```
|
||||
|
||||
```text
|
||||
curl: (7) Failed to connect to auth.hyeonworks.com:443 after 3 ms: Could not connect to server
|
||||
000
|
||||
```
|
||||
|
||||
엣지 주소를 짚어 주면 `200` 이 온다. 이름만 친 `000` 은 Keycloak 이 아니라 이름이 가리키는 곳의 문제라 원상복구 판정에는 쓸 수 없다. 지연 주입을 되돌리는 절이라 응답이 늦을 수 있어 시간을 넉넉히 준 형태로 친다.
|
||||
|
||||
```bash label="[lab host] 표의 마지막 줄 — 시간을 넉넉히 준 형태"
|
||||
curl -s -o /dev/null -w '%{http_code}\n' --max-time 20 \
|
||||
--resolve auth.hyeonworks.com:443:192.168.122.10 https://auth.hyeonworks.com/realms/master
|
||||
```
|
||||
|
||||
## 막히면
|
||||
|
||||
@@ -854,7 +921,8 @@ kubectl -n keycloak-lab delete pod a6-probe --ignore-not-found
|
||||
## 무엇이 관측이고 무엇이 아닌가
|
||||
|
||||
- (observed) 파드와 postgres 의 노드 배치, 주입 전 평균 `70 ms` 와 `66 ms`, `Cannot find device "eth0"` 네 줄 사이에 낀 `적용완료` 와 주입 시각 `13:14:55`, 그 상태의 「검증」 값 `43 ms` 와 `47 ms`, `ip -brief link` 의 `flannel.1` 과 `cni0`, 넣은 직후의 `Sent 0 bytes 0 pkt` 와 부하 뒤의 `Sent 18388 bytes 150 pkt`, 주입 뒤 `41 ms` 와 `1872 ms`, 동시 20건의 스무 줄 전부와 `22.230871` 까지의 계단, `blocking_time_max 20000.0` 과 `max_used_count 19.0` 과 `acquire_count_total 672.0` 과 `blocking_time_average 281.0`, 이벤트 세 줄과 `89s`·`32m`·`52m`, 낙관적 락 로그 `0`, 해제 뒤 `noqueue` 와 `43 ms` 와 `51 ms`, `agroal_*` 지표 이름 열두 개.
|
||||
- (unknown) `enp1s0` 과 `flannel.1` 에 각각 거는 `tcpdump` 두 줄, `tc filter show`, 낙관적 락 로그를 세는 `grep -icE` 줄. 가이드가 셋 다 미검증으로 표시했다. `ssh kc-lab-2` 로 들어가 원격 셸에서 `tc` 를 치는 두 단계 형태도 이 실험대에서 치지 않았다.
|
||||
- (unknown) `ssh kc-lab-2` 로 들어가 원격 셸에서 `tc` 를 치는 두 단계 형태. 이 실험대에서 치지 않았다. 가이드가 미검증으로 표시한 넷 — `tcpdump` 두 줄과 `tc filter show` 와 낙관적 락 로그를 세는 `grep -icE` — 은 2026-09-17 에 전부 쳤다.
|
||||
- (observed, 2026-09-17) 관찰 다섯 절과 복구를 다시 밟은 값 — 주입 전 `44 ms` 와 `40 ms`, 주입 뒤 `1865 ms` 와 `40 ms`, `connect 0.000552 ttfb 1.864861`, 동시 20건이 `1.871238` 에서 `22.245645` 까지 스무 줄 전부 `200`, `blocking_time_max 20000.0` 과 `max_used_count 18.0`, readiness 프로브가 `context deadline exceeded` 로 한 줄, 낙관적 락 로그 `0`, 해제 뒤 `noqueue` 와 `42 ms` 와 `39 ms`, 엔드포인트 주소 둘.
|
||||
- 구조에서 나온 결론이고 출력이 없는 것 — 「`enp1s0` 에 걸면 0 패킷」. 원 실행은 `eth0` 실패 뒤 곧바로 `flannel.1` 로 갔다.
|
||||
- 센 것이고 잰 것이 아닌 것 — 왕복 `9` 는 A-0 이 잡은 SQL 목록을 센 값이고 패킷을 추적한 값이 아니다. `200 ms × 9 ≈ 1,800 ms` 와 실측 `1,872 ms` 의 자릿수가 맞는다는 것까지가 이 계산의 범위다.
|
||||
- 증거 파일이 잘려 있는 것 — `agroal_*` 목록이 알파벳순으로 `destroy_count_total` 에서 끊겨 있다. 뒤에 쓰는 `agroal_max_used_count` 는 그 목록에 안 보이지만 부하 뒤 출력에는 있다.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user