RKE2 CySec latest provisioning¶
이 문서는 bloodbag-cysec-latest GitOps 24-Secret 공급 lane이다. signed 기준 환경 bloodbag-cysec(22-Secret)와 bloodbag-dev 계약은 변경하지 않는다.
latest는 항상 TEMPORARY NON-CLINICAL이며 regulatoryEvidenceEligible=false다. 이 lane은 규제 PASS/E2 증적을 만들지 않는다.
권위는 GitOps origin/main PR #151 계약 문서다.
- 경로:
clusters/tirosh-home/rke2-gpu/apps/bloodbag/cysec-latest/infra-readiness-contract.json - GitOps-facing
contractDigest:sha256:dcb89695c9ce0d9378e5c4509637a238e7695f56aac08b74cd2f12d8b56011e6 secretNameSetHash:sha256:e939ca14ba777daf315e49b4208c24e5dd68c06a52f96c582de47729b38382c0secretKeySetHash:sha256:5276cf9cf2b2687479d6f7574460d5f9fb396d0aef87f394932322fcc0712687
stale digest d0e4874, f4893ed, 7-Secret 5b7008는 권위가 아니다. Infra 내부 mapping digest는 GitOps digest와 분리해 pin한다.
정정 기록:
관련 GitOps 이슈: tirosh-gitops#150. Namespace bloodbag-cysec-latest는 GitOps bootstrap이 이미 소유하고 sync한다. Infra는 이 Namespace를 생성·변경·adopt하지 않으며 app.kubernetes.io/managed-by=infra-tools를 요구하지 않는다. 없으면 preflight/apply/verify는 fail-closed다.
계약 요약¶
- namespace:
bloodbag-cysec-latest(GitOps bootstrap 소유) - workload Secret 24개, 모두 이 namespace. GitOps 이름을 쓰며
-latestsuffix를 붙이지 않는다. bloodbag-secret, Product API route TLS, writeback은 workload24 밖이다. Product API route TLS는 runtime green 전까지 deferred.- registry:
bloodbag-cysec-registry(kubernetes.io/dockerconfigjson,ghcr.io) - TLS leaf 3개 / SAN 3개: postgres, signal-ingress Redis, internal-processing Redis. 전용 latest ECDSA P-256 CA.
- StorageClass:
bloodbag-cysec-latest-local-retain(cluster-scoped). PVC는 만들지 않는다. - writeback: 향후 K3s lifecycle (
tirosh-home/k3s의argocd/argocd-image-updater-gitops-writeback-cysec-latest). GPU RKE2에 적용하지 않는다. - 전용 계약:
sites/tirosh-home/rke2/bloodbag-cysec-latest-provisioning.toml.sites/tirosh-home/secrets.toml에는 latest runtime material을 추가하지 않는다.
exact latest24 names/key sets는 GitOps JSON 순서를 유지한다.
bloodbag-cysec-registry{.dockerconfigjson}bloodbag-postgres-bootstrap{admin-password}bloodbag-postgres-tls{ca.crt,tls.crt,tls.key}bloodbag-database-migration{database-user,database-password}bloodbag-product-api-database{password}bloodbag-product-api-key-material{session-key,csrf-key,patient-key}bloodbag-super-admin-bootstrap-database{password}bloodbag-super-admin-bootstrap-account{username,display-name,password}bloodbag-result-writer-database{database-url}bloodbag-signal-relay-source{password}—source-url없음bloodbag-signal-relay-source-tls{ca.crt}bloodbag-signal-ingress-redis-tls{ca.crt,tls.crt,tls.key}bloodbag-signal-ingress-redis-signal-ingress-publisher{password}bloodbag-signal-ingress-redis-signal-decoder{password}bloodbag-signal-ingress-redis-health{password}bloodbag-signal-ingress-redis-acl-audit{password}bloodbag-internal-processing-redis-tls{ca.crt,tls.crt,tls.key}bloodbag-internal-processing-redis-signal-decoder-internal{password}bloodbag-internal-processing-redis-inference-orchestrator{password}bloodbag-internal-processing-redis-result-writer-lifecycle{password}bloodbag-internal-processing-redis-result-writer-worker{password}bloodbag-internal-processing-redis-product-api{password}bloodbag-internal-processing-redis-health{password}bloodbag-internal-processing-redis-acl-audit{password}
이전 7-Secret 초안과의 관계¶
초기 Infra 초안은 application dotenv 하나(bloodbag-secret), -latest suffix Secret 이름, Product API TLS, GPU 클러스터 writeback, Infra 소유 Namespace를 가정했다. 그 모델은 GitOps PR #151 24-Secret 권위와 충돌하므로 폐기한다. 유용한 잔여 규칙은 유지한다.
- dotenv는 shell
source하지 않는다. 값은 출력하지 않는다. - create-only material bootstrap, mode 0600/0700/0400, staging 후 atomic rename.
- signed
bloodbag-cysec22-Secret lease와bloodbag-devregistry는 건드리지 않는다. - ImageUpdater per-image writeback을 이 Secret에 연결하지 않는다.
Material bootstrap¶
운영자 승인 임시 예외: registry dockerconfig만 기존 GHCR_USERNAME/GHCR_PULL_TOKEN byte를 재사용한다. Kubernetes Secret 이름은 bloodbag-cysec-registry다. 이 예외는 identity 분리 완료가 아니며 dedicated credential 발급 후 rotation이 필요하다. signed-lane PKI/password byte는 복사하지 않는다.
전제:
- credential dotenv (
GHCR_USERNAME,GHCR_PULL_TOKEN,BLOODBAG_CYSEC_LATEST_CA_PASSPHRASE) - 필수 operator dotenv (아래 2개
BLOODBAG_CYSEC_LATEST_*키, 값 문법 포함) - 출력 latest24 dotenv, source-redis adjunct dotenv, issuer 디렉터리는 아직 없어야 한다 (create-only)
- 입력 파일은 현재 사용자 소유, mode 0600, symlink/hardlink 금지
operator dotenv가 없거나 키가 비어 있으면 bootstrap은 생성/커밋 전에 fail-closed다. create-only이므로 부분 출력은 남기지 않는다. 예전 6키 operator 파일이 남아 있으면 unexpected operator keys로 실패한다.
bootstrap이 생성하는 값:
- 전용 latest ECDSA P-256 CA와 leaf 3개 (위 SAN 3개)
- Opaque password 16개 (
token_urlsafe(32)): postgres admin, migration password, product-api DB, super-admin DB, relay-source, signal Redis 4, internal Redis 7 - SuperAdmin username/display 리터럴
tirosh database-user리터럴bloodbag_migration- product-api key material 3개 (
token_urlsafe(32)): session-key, csrf-key, patient-key - registry dockerconfig (위 재사용 예외)
- 별도 source-redis CA와 Opaque server TLS/health Secret 재료 (문서 14)
bootstrap이 발명하지 않는 운영자 키 (latest prefix, 이름만 보고 값은 출력하지 않음):
BLOODBAG_CYSEC_LATEST_SUPER_ADMIN_BOOTSTRAP_ACCOUNT_PASSWORD(non-promotable test material)BLOODBAG_CYSEC_LATEST_RESULT_WRITER_DATABASE_URL(consumer username unresolved; Secret apply ≠ DB provisioned)
make rke2/cysec-latest/material/bootstrap SITE=tirosh-home \
RKE2_BLOODBAG_CYSEC_LATEST_CREDENTIAL_ENV_FILE=/absolute/path/to/credentials.env \
RKE2_BLOODBAG_CYSEC_LATEST_OPERATOR_ENV_FILE=/absolute/path/to/operator.env \
RKE2_BLOODBAG_CYSEC_LATEST_OUTPUT_ENV_FILE=/absolute/path/to/bloodbag-cysec-latest.env \
RKE2_BLOODBAG_CYSEC_LATEST_SOURCE_REDIS_OUTPUT_ENV_FILE=/absolute/path/to/bloodbag-cysec-latest-source-redis.env \
RKE2_BLOODBAG_CYSEC_LATEST_ISSUER_DIR=/absolute/path/to/cysec-latest-issuer
[CHANGES]: 로컬 secret 파일을 만든다. 클러스터 명령을 실행하지 않는다. 터미널 JSON은 경로와 키 이름/개수만 출력하고 값은 출력하지 않는다.
출력 안전:
- 출력 dotenv는 O_EXCL/create-only, mode 0600. overwrite, symlink, source alias, issuer 내부 경로를 거부한다.
- issuer 디렉터리는 mode 0700,
ca.key/ca.crt/ca-metadata.json은 mode 0400.ca.key만BestAvailableEncryption과BLOODBAG_CYSEC_LATEST_CA_PASSPHRASE로 암호화한다. leaf TLS key는 Kubernetes TLS Secret 요구로 비암호화다. passphrase는 출력 dotenv와 metadata에 복사하지 않는다. - staging 후 atomic rename. 실패 시 최종 부분 출력을 남기지 않는다.
- metadata receipt는 이름·SAN·시각만 담고 값이나 private-key digest를 담지 않는다.
운영자 값 검사 (값을 출력하지 않음):
- super-admin username/display는 생성된 리터럴
tirosh - super-admin password: GitOps 12–256 byte single-line, non-promotable test material. 값은 문서/로그/JSON에 쓰지 않는다
- result-writer
database-url:postgresql+psycopg://<user>:<password>@bloodbag-postgres.bloodbag-cysec-latest.svc:5432/bloodbag?sslmode=verify-full&sslrootcert=/run/database-trust/ca.crt, fragment 금지. URL 적용은 PostgreSQL 프로비저닝이 아니다 - relay-source password와 client-trust CA는 bootstrap이 생성한다. source-redis adjunct는 문서 14
MacBook 실행 절차¶
기존 BLOODBAG .env를 저장소로 복사하거나 shell source하지 않는다. bootstrap이 만든 출력 dotenv 경로를 --env-file / Make 변수로만 넘긴다.
make rke2/cysec-latest/preflight SITE=tirosh-home \
RKE2_BLOODBAG_CYSEC_LATEST_ENV_FILE=/absolute/path/to/bloodbag-cysec-latest.env
make rke2/cysec-latest/plan SITE=tirosh-home \
RKE2_BLOODBAG_CYSEC_LATEST_ENV_FILE=/absolute/path/to/bloodbag-cysec-latest.env
make rke2/cysec-latest/storage-class/plan SITE=tirosh-home
make rke2/cysec-latest/storage-class/apply SITE=tirosh-home
make rke2/cysec-latest/storage-class/verify SITE=tirosh-home
make rke2/cysec-latest/apply SITE=tirosh-home \
RKE2_BLOODBAG_CYSEC_LATEST_ENV_FILE=/absolute/path/to/bloodbag-cysec-latest.env
make rke2/cysec-latest/verify SITE=tirosh-home
Secret-only 실행에서는 네 lifecycle 모두
RKE2_BLOODBAG_CYSEC_LATEST_STORAGE_CLASS_MANIFEST=를 명시한다. 이때 plan은
StorageClass를 렌더링하지 않고 apply/verify는 StorageClass API를 조회하거나 변경하지
않는다. StorageClass가 필요한 경우 위 storage-class/* lifecycle을 별도로 사용한다.
preflight[SAFE]: 계약 closed schema, GitOps hash pin, dotenv 문법/파일 경계, 36개BLOODBAG_CYSEC_LATEST_*키 존재. 값은 출력하지 않는다. 빠진 키는 이름만 보고 nonzero. kubeconfig가 있으면 GitOps Namespace 존재를 확인하고 없으면 fail-closed. Secret get은 Namespace가 있을 때만.plan[SAFE]: 선택된 StorageClass와 Secret을REDACTED로만 렌더링한다. Namespace 매니페스트를 만들지 않는다. 운영자 키가 없어도 blocked/redacted plan을 낼 수 있다.kubectl diff를 쓰지 않는다.apply[CHANGES]: apply-readiness가 빠진 키 이름만 보고 실패할 수 있다. 그 다음 Namespace를 조회하고 없으면 중단한다. 없는 namespace에서kubectl get secret이나 namespaced Secret server-dry-run을 하지 않는다. StorageClass 계약을 넘긴 경우에만 cluster-scoped 객체를 조회·적용한다. Secret-bearing 임시 파일과kubectl diff를 쓰지 않는다.verify[SAFE]: GitOps Namespace canonical label/annotation, 선택된 StorageClass, Secret type/key names, andtirosh.ai/material-digestlowercase 64-hex shape만 확인한다. 값을 읽거나 digest byte를 비교하지 않는다. extra Argo CD tracking label은 selfHeal과 싸우지 않기 위해 허용한다.storage-class/*: cluster-scoped Retain 클래스만. PVC를 만들지 않는다. 기존 객체가 있으면app.kubernetes.io/managed-by=infra-tools가 없으면 dry-run/apply 전에 fail-closed.
GitOps ownership 경계¶
- Namespace 생성·label·Pod Security·
tirosh.ai/ownership=bootstrap·argocd.argoproj.io/sync-options=Prune=false,Delete=false는 GitOps bootstrap 소유다. - Infra는 이 Namespace를 create/apply/adopt하지 않는다. 없으면 fail-closed.
- signed
bloodbag-cysecApplication, 22-Secret lease, signed StorageClassbloodbag-cysec-local-retain,bloodbag-devregistry 계약은 이 lane의 대상이 아니다. - ImageUpdater per-image writeback을 이 Secret에 연결하지 않는다. 이미지 8개는 GitOps 단일 커밋 경로(#150)가 담당한다.
canonical GitOps Namespace metadata (origin/main):
- labels:
app.kubernetes.io/name=bloodbag,app.kubernetes.io/part-of=bloodbag,tirosh.ai/environment=cysec-latest,tirosh.ai/ownership=bootstrap,tirosh.ai/regulatory-evidence-eligible=false,tirosh.ai/clinical-use=false, Pod Securityrestrictedenforce/audit/warn - annotations:
argocd.argoproj.io/sync-options=Prune=false,Delete=false,tirosh.ai/temporary-non-clinical=true
RKE2 / K3s split¶
RKE2 GPU (tirosh-home/rke2/gpu)가 소유하는 것:
- latest24 Secret (namespace
bloodbag-cysec-latest) - StorageClass
bloodbag-cysec-latest-local-retain
K3s (tirosh-home/k3s)가 향후 소유하는 것 (Phase 1 비범위, GPU에 적용 금지):
argocd/argocd-image-updater-gitops-writeback-cysec-latest- GitOps readiness status=ready/signing/dispatch
StorageClass¶
signed analog bloodbag-cysec-local-retain과 같은 형태이며 이름은 latest 전용이다.
- provisioner
rancher.io/local-path reclaimPolicy: RetainvolumeBindingMode: WaitForFirstConsumerallowVolumeExpansion: false- non-default (
storageclass.kubernetes.io/is-default-class=false) - cluster-scoped, PVC 생성 없음
no-apply / 비범위 (Phase 1)¶
이 문서는 클러스터 apply를 강제하지 않는다. GitOps overlay는 blocked-awaiting-external-provisioning 상태다. 구현은 존재하지만 운영 apply는 GitOps Namespace가 있고 운영자 dotenv가 완전할 때만 수행한다.
명시적 비범위:
- GitOps workload 합성 또는 GitOps 저장소 수정
- CySec 개발 URL 전환
- signed
bloodbag-cysec22-Secret 자동 갱신 - Product API route TLS
- K3s writeback 적용
- readiness status=ready/signing/dispatch
- 규제 증거 또는 PASS/E2 주장
.env를 git/CI artifact로 저장
실제 apply는 운영자가 MacBook에서 kubeconfig와 bootstrap 출력 dotenv를 준비한 뒤에만 수행한다.
rollback / recovery¶
prior Secret byte backup은 제공하지 않는다. 잘못된 적용을 되돌리려면:
make rke2/cysec-latest/verify SITE=tirosh-home으로 metadata drift를 확인한다.- 승인된 latest dotenv(
BLOODBAG_CYSEC_LATEST_*)를 다시 준비한다. make rke2/cysec-latest/apply ...를 재실행한다. 동일 material이면 skip이고, 변경된 Secret만 replace한다.
signed bloodbag-cysec rollback lane과 섞지 않는다.
검증¶
make interface/check SITE=tirosh-home
UV_CACHE_DIR=.uv-cache uv run ruff check packages/infra-tools/src packages/infra-tools/tests
UV_CACHE_DIR=.uv-cache uv run pytest packages/infra-tools/tests
make docs/build