Files

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 경로와 분리해 실제 적용했습니다. aistorobject-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

하위 baseoverlays/home는 직접 적용 대상이 아닐 수 있습니다. Helm values와 환경 patch가 형제 디렉터리에 있는 구성은 Kustomize 기본 RootOnly 제한을 유지하기 위해 서비스 또는 컨트롤러 루트에서 렌더합니다.

Secret 원칙

평문 Secret, 비밀번호, 라이선스, 개인 키와 소스 관리되는 kind: Secret YAML을 저장소에 두지 않습니다. 각 단계의 초기 구축 스크립트가 계약 전체의 존재·타입·키·교차 namespace 동일성을 검증하고, 전체가 없을 때만 명시 확인 후 생성합니다. 일부만 존재하면 중단하며 자동 회전하지 않습니다.

최초 생성은 여러 Kubernetes API 요청으로 수행되므로 중간 실패 시 일부 객체가 남을 수 있습니다. 후속 실행은 이를 삭제하거나 덮어쓰지 않고 부분 상태로 감지해 중단합니다.

Phase 1 계약:

  • platform-data/gitea-db-credentials
  • gitea/gitea-db-credentials
  • gitea/gitea-admin

Phase 2 계약:

  • platform-data/keycloak-db-credentials
  • keycloak/keycloak-db-credentials
  • gitea/gitea-keycloak-oidc
  • aistor/minio-license
  • object-storage/aistor-root-configuration

gitea/gitea-keycloak-oidcOpaque 유형이며 정확히 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.comKeycloak 포함 설정으로 전환되어 공개 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 캐시와 렌더 산출물 대신 재현 가능한 선언만 버전 관리합니다.