13 KiB
플랫폼 인프라
단일 노드 k3s에서 사용하는 공통 플랫폼 인프라의 선언형 구성을 관리하는 저장소입니다. 상세 아키텍처, 운영 절차, 의사결정 기록은 중앙 Platform 문서에서 관리합니다.
현재 상태
Phase 1과 Phase 2의 선언 및 수동 초기 구축 진입점이 구현되어 있습니다. Phase 1에는 namespace, SSD Local PV, CloudNativePG, 공용 PostgreSQL, Gitea, Traefik Ingress와 NetworkPolicy가 포함됩니다. Phase 2 선언에는 Keycloak, 공용 PostgreSQL의 Keycloak DB·Role, AIStor Operator, 단일 MinIO AIStor ObjectStore, namespace와 Local PV가 포함됩니다.
Phase 1은 실제 클러스터에 적용했습니다. CloudNativePG·PostgreSQL·Gitea, PV/PVC와 내부 Traefik health가 정상이며 Gitea 네 컨테이너의 restricted securityContext도 검증했습니다. Host Nginx의 Gitea proxy 전환과 로컬·public HTTP/HTTPS 검증도 통과했습니다.
Phase 2는 전체를 한 번에 적용하지 않았습니다. Keycloak-only 범위인 전용 DB와
Role, NetworkPolicy, 공식 Operator, 단일 Keycloak 인스턴스, hyeonworks realm,
confidential gitea client와 gitea/gitea-keycloak-oidc Secret까지 실제 적용을
완료했습니다. Traefik web entrypoint에는 실제 관측한 Host Nginx source
10.42.0.1/32만 forwarded-header trusted IP로 적용했습니다.
id.learn.hyeonworks.com의 Host Nginx static hold를 Keycloak proxy로 바꾸는
전환과 Gitea OIDC·브랜딩 rollout도 완료했습니다. Host Nginx 후보 SHA-256은
5c5cd74b4992f537fd27c50cf2209573a80a9904e0b19b58c3154717be6ff4a5, 백업은
/etc/nginx/sites-available/learn-services.before-keycloak-20260723160519이며,
적용한 Gitea manifest SHA-256은 d25a757...a157입니다. 활성 OAuth source,
외부 인증 전용 가입 정책, authorization-code redirect와 브랜딩 자동 검증을 모두
통과했습니다. 실제 realm 사용자의 브라우저 login/callback/logout와 비상 관리자
로그인은 별도 수용 시험으로 남아 있습니다.
AIStor는 Keycloak 경로와 분리해 실제 적용했습니다. aistor와 object-storage
namespace, 900Gi Retain Local PV, 공식 Operator와 단일 ObjectStore, 기본 차단
NetworkPolicy가 동작 중입니다. ObjectStore는 Initialized/green, PVC는
aistor-data-local-pv에 Bound이며 S3와 Console은 ClusterIP로만 노출됩니다.
고정 다이제스트의 공식 AIStor Client로 버킷 생성, 객체 쓰기·읽기 checksum,
객체·버킷 삭제까지 인증된 스모크 테스트를 통과했습니다.
| 구성요소 | 고정 버전 | 상태 |
|---|---|---|
| CloudNativePG | Operator 1.30.0, Chart 0.29.0 |
Phase 1 적용, Ready/Available 1/1 |
| PostgreSQL | 17.9-standard-trixie |
Phase 1 적용, healthy 1/1, PVC Bound |
| Gitea | 애플리케이션 1.27.0, Chart 12.7.0 |
OIDC·브랜딩 rollout 완료; OAuth source·정책·redirect·자산 자동 검증 통과 |
| Keycloak | Operator·애플리케이션 26.7.0 |
Ready 1/1; realm·client·OIDC Secret·Host Nginx 공개 전환 완료 |
| Traefik | Chart 40.1.3+up40.1.0, 이미지 3.7.4 |
NodePort 30080/30443, web trust 10.42.0.1/32 적용 |
| AIStor Operator | Chart 5.10.0 |
적용, Operator·AdminJob·Webhook Ready 1/1 |
| AIStor ObjectStore | Chart 1.0.16 |
적용, Initialized/green, 900Gi PVC Bound, 인증 S3 스모크 통과 |
| 렌더 도구 | Kustomize 5.8.1, Helm 3.19.4 |
정확히 일치해야 함 |
Argo CD와 Istio는 현재 단계에서 구현하거나 배포하지 않습니다.
실제 Kustomize 빌드 루트
Phase 1 최초 적용은 다음 경로만 빌드 루트로 사용합니다.
| 순서 | 빌드 루트 | 렌더 방식 |
|---|---|---|
| 1 | infrastructure/namespaces/overlays/home |
Kustomize |
| 2 | infrastructure/storage/ssd-local-pv |
Kustomize |
| 3 | infrastructure/controllers/cloudnative-pg |
Kustomize + Helm |
| 4 | services/platform-postgres |
Kustomize |
| 5 | services/gitea |
Kustomize + Helm |
services/gitea는 신규 설치용 baseline 빌드 루트이며 렌더 결과는
gitea.yaml입니다. Keycloak OIDC와 브랜딩은 최초 Phase 1 적용 대상이 아니며,
Host Nginx ID 전환 뒤 전용 빌드 루트 services/gitea/profiles/oidc에서
gitea-oidc.yaml로 렌더링하고 수명주기 스크립트로만 적용합니다.
Phase 2는 Phase 1 전체를 먼저 검증한 뒤 다음 빌드 루트를 추가로 렌더합니다.
| 순서 | 빌드 루트 | 렌더 방식 |
|---|---|---|
| 1 | infrastructure/namespaces/phase2 |
Kustomize |
| 2 | infrastructure/storage/aistor-local-pv |
Kustomize |
| 3 | infrastructure/controllers/keycloak-operator |
Kustomize 원격 리소스 |
| 4 | services/platform-postgres-keycloak |
Kustomize |
| 5 | services/keycloak |
Kustomize |
| 6 | infrastructure/controllers/aistor-operator |
Kustomize + Helm |
| 7 | services/minio-aistor |
Kustomize + Helm |
하위 base와 overlays/home는 직접 적용 대상이 아닐 수 있습니다. Helm values와
환경 patch가 형제 디렉터리에 있는 구성은 Kustomize 기본 RootOnly 제한을
유지하기 위해 서비스 또는 컨트롤러 루트에서 렌더합니다.
Secret 원칙
평문 Secret, 비밀번호, 라이선스, 개인 키와 소스 관리되는 kind: Secret YAML을
저장소에 두지 않습니다. 각 단계의 초기 구축 스크립트가 계약 전체의
존재·타입·키·교차 namespace 동일성을 검증하고, 전체가 없을 때만 명시 확인 후
생성합니다. 일부만 존재하면 중단하며 자동 회전하지 않습니다.
최초 생성은 여러 Kubernetes API 요청으로 수행되므로 중간 실패 시 일부 객체가 남을 수 있습니다. 후속 실행은 이를 삭제하거나 덮어쓰지 않고 부분 상태로 감지해 중단합니다.
Phase 1 계약:
platform-data/gitea-db-credentialsgitea/gitea-db-credentialsgitea/gitea-admin
Phase 2 계약:
platform-data/keycloak-db-credentialskeycloak/keycloak-db-credentialsgitea/gitea-keycloak-oidcaistor/minio-licenseobject-storage/aistor-root-configuration
gitea/gitea-keycloak-oidc는 Opaque 유형이며 정확히 key, secret 두 key만
갖습니다. 현재 Keycloak-only 작업으로 생성됐지만 payload는 문서, values와 렌더
결과에 기록하지 않습니다.
자세한 계약은 Secret 문서를 따릅니다. Helm 차트가 렌더하는 초기화 스크립트·비민감 설정용 내부 Secret은 애플리케이션 자격 증명 계약과 구분합니다.
k3s Secret 저장 암호화와 복구 증거
k3s Secret encryption at rest의 상태 확인과 fail-stop 활성화 절차는 암호화 수동 운영 절차를 따릅니다. datastore나 snapshot 단독 탈취를 완화하지만 같은 host의 root 침해나 full-disk 탈취를 해결하지는 않습니다. server token과 backup을 함께 얻으면 복구·복호화할 수 있으므로 recovery bundle 전체를 Secret으로 취급합니다.
2026-08-09 live 실행에서 수동 LUKS header 복구 proof, recovery close·잔류 없음 검사,
closed validator, Secret encryption Enabled/reencrypt_finished, hash·integrity·API·node
검사와 post bundle 기록을 모두 통과했고 최신 bundle marker도 검증했습니다. 다만 일반
lifecycle 자동화, 격리 restore drill, off-host 복제와 암호화 escrow 검증은 아직
완료되지 않았으므로 관측성 Phase 4 gate는 열리지 않았습니다.
Phase 4 Secret 생성 전에는 live --expect-reencrypted와 restore evidence --check를 매번
독립 호출합니다. backend별 수동 복구, 일회용 격리 환경, 세 mode 결과 생성·등록·검사와
파기 기준은 k3s Secret 복구 drill,
중앙 보호 경계는
보안과 Secret 관리와
백업과 복구 설계를
따릅니다. 완료된 live hardening의 비민감 정정은
2026-08-08 복구 명령 원장의
2026-08-09 addendum과
2026-08-09 로컬 정책 기록에
남긴다. 별도의 Task 6 실행 runbook은 만들지 않았으며, 이를 암시하지 않는다.
검증과 수동 적용
아무 리소스도 적용하지 않는 렌더 검증 명령은 다음과 같습니다.
cd /home/donghyeon/workspace/platform
bash scripts/validate/render-phase1.sh
bash scripts/validate/render-phase2.sh
Phase 1 검증은 baseline과 OIDC profile을 포함한 manifest 여섯 개를 생성합니다.
최초 구축 스크립트는 그중 gitea.yaml baseline만, OIDC 수명주기 스크립트는
gitea-oidc.yaml 하나만 각각 적용합니다.
Helm이 시스템 PATH에 없다면 검증된 3.19.4 실행 파일의 절대 경로를
PLATFORM_HELM_BIN으로 지정합니다. Phase 2 검증은 Phase 1을 먼저 검증한 뒤
공식 AIStor Chart 패키지 다이제스트, Keycloak 단일 인스턴스·HTTP hostname/Ingress,
AIStor 1x1·900Gi·PVC 보호·ClusterIP, RootOnly 유지와 Secret 소스·렌더링 부재를
확인합니다. 실제 클러스터의 ObjectStore CRD는 로컬 렌더에 필요하지 않습니다.
Phase 1 상세 절차는 중앙 Phase 1 런북과 짧은 실행 진입점을 따릅니다.
Keycloak에서 Gitea OIDC까지의 실제 실행 순서와 현재 완료·대기 경계는 중앙 Keycloak-Gitea OIDC 전환 런북에 기록합니다. 실행 진입점은 다음 네 개입니다.
cd /home/donghyeon/workspace/platform
# 완료: Keycloak DB·Operator·인스턴스
bash scripts/bootstrap/apply-keycloak.sh --execute
# 완료: realm·confidential Gitea client·OIDC Secret
bash scripts/bootstrap/configure-keycloak-gitea-oidc.sh --execute
# 완료: id.learn.hyeonworks.com Host Nginx 전환
sudo bash scripts/bootstrap/apply-host-nginx-keycloak.sh --execute
# 완료: 고정 SHA 렌더 결과의 gitea-oidc.yaml만 적용하고 OIDC·브랜딩 검증
PLATFORM_HELM_BIN=/home/donghyeon/.local/bin/helm \
bash scripts/bootstrap/apply-gitea-oidc.sh --execute
Traefik 신뢰 경계의 적용 값과 첫 실패·복구 내용은 중앙 Traefik trust 런북에 기록합니다. AIStor의 실제 배포 명령·결과·실패와 복구 과정은 중앙 AIStor 배포 기록과 Phase 2 수동 진입점에 기록합니다.
AIStor 재검증 진입점은 다음과 같습니다.
cd /home/donghyeon/workspace/platform
PLATFORM_HELM_BIN=/home/donghyeon/.local/bin/helm \
bash scripts/bootstrap/apply-aistor.sh \
--license-file /home/donghyeon/.secrets/aistor/minio.license \
--root-config-file /home/donghyeon/.secrets/aistor/root.env \
--execute
bash scripts/validate/aistor-s3-smoke.sh --execute
첫 명령은 기존 Secret과 Retain PV를 회전·삭제하지 않고 계약과 readiness를 재검증한다. 두 번째 명령은 임시 버킷과 객체를 만들었다가 삭제하며, 자격 증명 payload는 출력하지 않는다.
호스트 Nginx
Gitea Nginx 설정을
기반으로 한 Gitea proxy는 현재 Host Nginx에 적용되어 있고 로컬·public HTTPS
health를 통과했습니다. id.learn.hyeonworks.com도
Keycloak 포함 설정으로
전환되어 공개 discovery issuer 검사를 통과했습니다.
ID 전환은 scripts/bootstrap/apply-host-nginx-keycloak.sh --execute가 공개
discovery 사전 검사, 기존 설정 백업, nginx -t, 다시 불러오기와 HTTPS 사후
검사를 수행하도록 합니다. 실패 시 후보를 방치하지 않고 백업 설정을 복원합니다.
실제 전환 성공 뒤 scripts/bootstrap/apply-gitea-oidc.sh --execute로 Gitea
OIDC source와 브랜딩도 live Deployment에 적용했습니다. 세부 경계는
Nginx 수동 전환 절차를 따릅니다.
저장소 규칙
- Kubernetes 리소스는 Kustomize
base와 환경별overlays로 구분합니다. - 공식 Helm 차트 원본은 수정하지 않고 고정 버전, SHA-256, 저장소 관리 values·patch로 설정합니다.
- 클러스터 진입점과 향후 GitOps 애플리케이션 선언은
clusters/home에서 관리합니다. - 공통 컨트롤러와 기반 리소스는
infrastructure, 플랫폼 서비스는services에서 관리합니다. - 반복 정책과 향후 서비스 메시 확장 지점은
components에서 관리합니다. - 자동화는
scripts, 사람이 검토하는 최초 적용 절차는bootstrap/manual, 상세 운영 기록은 중앙 문서에 둡니다. - 생성된 Helm 캐시와 렌더 산출물 대신 재현 가능한 선언만 버전 관리합니다.