Skip to content

OpenBao 요구사항

헌법 조항: OpenBao is the secret source of truth. 모든 런타임 시크릿의 단일 저장/회전 지점이다.

  • FractalOps 및 연동 스택 시크릿의 단일 저장/회전 지점.

토폴로지 런타임 의존성(runtime_dependencies.openbao):

openbao:
ct_id: 125
host: 10.10.10.125
port: 8200
verify_tls: false

OpenBao 값은 두 경로로 워크로드에 전달된다(secret_delivery):

flowchart LR
  OB["OpenBao<br/>(10.10.10.125:8200)<br/>fractalops/default/*"]
  ES["External Secrets<br/>(ns external-secrets)"]
  VA["Vault Agent<br/>(ns vault-agent)"]
  K["k8s Secret / 파일"]
  W["워크로드<br/>(reload_strategy)"]

  OB -- "delivery_mode: external_secret" --> ES
  OB -- "delivery_mode: vault_agent" --> VA
  ES --> K
  VA --> K
  K --> W
  • secret_delivery.mediation: fractalops, openbao_path_prefix: fractalops/default.
  • External Secrets: secret_store_name: fractalops-openbao, auth_mount: kubernetes, refresh_interval: 15m, token_ttl: 1h, token_max_ttl: 24h.
  • reload 전략은 contract별로 다르다: rollout_restart, staged_restart, hot_resolve.
  • OpenBao는 secret value의 SSOT다. SPIRE는 secret store가 아니라 workload identity issuer다.
  • FractalOps core workload는 전용 Kubernetes ServiceAccount를 사용하고 SPIRE 기본 identifier 규칙인 spiffe://<trust-domain>/ns/<namespace>/sa/<service-account>를 OpenBao JWT auth subject로 제출한다.
  • fractalops-runtime OpenBao JWT role은 SPIRE JWT-SVID를 검증한 workload에 read-only secret 조회권만 준다.
  • stack 간 통신용 bootstrap material은 정적 초기값으로 두지 않는다. fractalops-stack-seed-issuer role을 쓰는 seed issuer가 SPIRE JWT-SVID로 OpenBao에 로그인한 뒤 runtime/* 또는 evidence/* scope에 생성/갱신한다.
  • ESO는 OpenBao 값을 Kubernetes Secret으로 투영한다. ESO가 seed 값을 생성하지 않는다.
  • scope 기반 저장(plugins, connectors/<id>, runtime).
  • env -> openbao sync operation 제공.
  • 참조 포맷 ref:<scope>:<key> 해석.
    • identity-contract catalog의 ${FRACTALOPS_*} 플레이스홀더도 같은 해석기로 OpenBao/env에서 채워진다(stack_identity_contract_catalog.py).
  • 회전 대상 키마다 <KEY>__ROTATION_ENVELOPE 메타데이터 저장.
  • 회전 envelope에는 발급 주체, 담당 agent, subject, active/next/previous generation, 소비자 목록, 재주입 방식, 검증 상태, 폐기 단계가 포함되어야 함.
flowchart LR
  A["write_next_generation"] --> B["refresh_consumers"]
  B --> C["verify_consumers"]
  C --> D["promote_active_generation"]
  D --> E["revoke_previous_generation"]
  • OpenBao의 secret value는 현재 active generation의 material일 뿐이다.
  • EOS/agent 회전은 raw value를 직접 소유하지 않고 rotation envelope를 소유한다.
  • envelope의 fingerprint만 active secret과 맞춰 검증하고, raw secret은 envelope에 기록하지 않는다.
  • staged dual key 회전은 위 5단계로 닫힌 루프를 가져야 한다.
  • secret_delivery.contracts[].requires_rotation_envelope: true인 connector는 audit에서 envelope 누락, fingerprint mismatch, owner/consumer 누락을 실패로 처리한다.

requires_rotation_envelope: true를 강제하는 대표 contract는 connectors/daytona-studio다.

- scope: connectors/daytona-studio
rotation_strategy: provider_issued_token
rotation_lifecycle: eos
rotation_controller: eos
requires_rotation_envelope: true
secret_classes: [provider_api_token, jwt_bootstrap_token]
rotation_envelope_keys: [FRACTALOPS_DAYTONA_API_TOKEN]
rotation_consumers: [fractalops-studio-execution-workspace-registry]

connectors/daytona는 EOS controller로 rotation_consumersdaytona-connector, fractalops-studio-execution-workspace-registry를 둔다. connectors/dokployFRACTALOPS_DOKPLOY_API_KEYdokploy-connector, project-preview-reconciler가 소비한다.

  • root token 직접 사용 금지(운영 계정/정책 분리).
  • 운영 workload의 OpenBao 로그인은 정적 root/app token이 아니라 SPIRE JWT-SVID를 우선한다.
  • unseal 절차는 운영 런북으로 관리한다.
  • 소비자는 ref:<scope>:<key> 또는 broker lease로만 접근하고, envelope를 통해 reload와 검증 상태를 보고해야 한다.
  • OpenBao에서 키 갱신 후 connector 동작 재검증.
  • 평문 env에만 있는 민감값 제거(make infra-ssot-scan-strict).
  • 회전 audit에서 raw secret 단독 저장이 없는지 확인.
  • envelope가 raw secret을 포함하지 않는지 확인.
  • previous generation 폐기와 소비자 재검증 상태가 남는지 확인.