Skip to content

[CWL security migration] Independent Keyverse KMS and secret authority; retire dotenv and static credential files #2063

Description

@seonghobae

Owner requirement — corrected 2026-09-10

CWL must stop depending on .env, and Keyverse must itself provide the independent KMS/cryptographic trust and secret-lifecycle service. External KMS/HSM is OPTIONAL, not a production prerequisite. The previous preference for external custody did not meet the owner's standalone requirement.

POSTGRES_PASSWORD_FILE, a different plaintext config file, or a Kubernetes Secret is not proof of migration. These may change transport but do not establish Keyverse issuance, access policy, rotation, revocation or audit. A static host file cannot be relabeled as an independent trust authority merely by moving it outside the repository.

This issue is the cross-repository migration register, NOT evidence that rollout is complete. The original request was recorded on 2026-09-09; the clarification above supersedes the previous external-provider/static-bootstrap interpretation without discarding useful hardening or predecessor delta.

Canonical responsibility

Keyverse owns root custody, initialization/seal/unseal/recovery, cryptographic key lifecycle and operations, secret versions/leases, governed credential issuance/revocation and access audit. Identity/federation, authorization and custody remain distinct bounded contexts. New custody/cryptographic runtime is Rust with reviewed primitives, not a new custom cipher or another Python vault engine.

.github owns reusable verification/inventory; AppGuardrail owns source detection. enterprise-architecture-core records the context map and adoption decision; context-graph-contracts publishes only value-free interoperability contracts. Consumers retain domain truth and use immutable released APIs, never Keyverse DBs, source copies or open-PR runtime dependencies.

Independent startup and key usage

The Keyverse custody core must initialize and unseal without a live dependent Keycloak, credentials issued by its own locked data plane, another Keyverse deployment, or an external KMS/vault. Minimal durable bootstrap state may contain encrypted key material and public/authenticated metadata, not its complete plaintext unlock factor.

A standalone quorum-unseal profile with separately protected custodians is a valid direction; optional local hardware or external-provider profiles can support automatic unseal under their declared trust assumptions. Quorum unseal is not threshold signing. Do not promise both unattended full-cluster cold recovery and protection from possession of all host state without any separate unlocking factor. Protect initial enrollment and instance identity; never replace that with an unverified token, shared admin password or unauthenticated first network request.

Keyverse must offer opaque key handles and authorized encrypt/decrypt, wrap/unwrap, sign/verify and MAC operations. Root/wrapping/signing private keys are non-exportable via normal APIs. Secret-string retrieval and any plaintext data-key export are separately scoped capabilities; not every consumer should receive an encryption key as a string.

Software-only custody, hardware-backed custody and validated hardware modules have different assurance. A PKCS#11-compatible service is not automatically a physical HSM or FIPS-validated product. Record the exact module/version/configuration evidence for any such claim.

Policy to enforce

  1. Runtime application/provider secrets resolve through released Keyverse contracts. .env, home-directory dotenv discovery, plaintext config DBs, static secret mounts and environment-variable fallback are not alternative credential authorities.
  2. Non-secret endpoints, log levels, bootstrap locators and deployment settings stay typed configuration. Do not misclassify safe dotenv-disabling code, examples or transitive dependencies as proven secret exposure.
  3. Cryptographically verify short-lived workload identity and bind issuer, audience, subject, tenant/environment, key/version, purpose, operation and lifetime. GitHub OIDC also binds repository/owner IDs and trusted immutable workflow identity. Decoded claims alone are not authentication; PR/fork code never receives general privileged secrets.
  4. Prefer direct client integration or authenticated local IPC. A driver-required ephemeral file is only a separately reviewed compatibility sink AFTER Keyverse-issued, scoped, short-lived authorization, with replacement/cleanup and no fallback. The current static /run/keyverse-bootstrap/* producer lacks this lifecycle and remains a gap, not a default standalone architecture.
  5. Consumers fail closed on invalid/revoked/expired authorization. Any still-valid lease cache follows its explicit revocation policy. Revocation cannot retroactively erase plaintext already returned to a compromised consumer; revoke/expire the upstream credential too. Do not hide failure with expired caches, operator tokens, paid-provider fallback or another secret store.
  6. Model-provider secret use stays in contextual-orchestrator's authorized execution boundary; model-backed Actions continue using orchestrator/free and gateway-scoped identity. No hardcoded provider/model/group or key fan-out to siblings.
  7. Secret values do not enter PRs, logs, artifacts, metrics, browser bundles, events, screenshots or LLM context. Evidence contains only necessary value-free locations/references, with appropriate access control for sensitive metadata.

PostgreSQL acceptance

Database-image administrative initialization is separate from consumer authentication. _FILE initializes a static password; it is not a workload lease.

Use Keyverse-issued short-lived client certificates with explicit database-role mapping where the actual driver/TLS integration supports them, or an explicitly selected Keyverse-owned dynamic-role adapter with least-privilege credentials. No shared long-lived superuser password is distributed to applications. The database adapter is a deliberate privileged provider integration, not permission for arbitrary cross-service SQL.

Prove real issuance, login, scope denial, renewal, rotation and revocation. Define revocation for both new connections and existing sessions/pools; expiration alone is not evidence that an authenticated session ended. Provisioning authority and initial DB connection must not create another startup dependency cycle. A static certificate/private-key file is not an acceptable substitute for a static password file.

Existing source lines and correction

Historical initial inventory — not an exhaustive organization census

Refresh each path from its live protected/default ref before editing. These are the original indexed observations, not current deployment findings:

Repository Observed revision Entry points Owner action
keyverse 0f10ac556a318c3c3f5ce7eab0802573ecce0c4c (open #129) config/bootstrap/vault administrator API Independent Rust custody, key operations and credential lifecycle before release
contextual-orchestrator 414f22973658c4ddc3d4320fcf7acd9b4e8ba991 credentials.py, provider_bootstrap.py, scripts/ci/serve_seeded_gateway.py Released Keyverse port; staged removal of environment seeding
naruon 042b0c70531b229af3acbd0421a2f23098d848b3 backend/core/env_paths.py, backend/core/config.py, scripts/naruon_compose.sh Remove home/parent/project dotenv discovery; preserve session/data recovery; distinguish key operations from secret retrieval
LineageWeave 83eba56149eb802cd63642c507c324c9976ec78e Makefile and Compose Retire home dotenv transport; consume CO/Keyverse contracts
xtrmLLMBatchPython 80096c8b8e21f288992b00d2db873d81208eba10 xtrmllmbatch/cli.py and scripts/tests Retire loaders/backup discovery; provider calls through CO
four-pillars 8c6a2fa76af1cb7f6bb7f56ceb4e7ce92d2f7897 src/four_pillars/settings.py Separate typed settings from credential authority
linux-cluster-ops 7d6c0e6f488dffb609eded3f8980ded570b54362 backup/restore scripts Remove static credential files without losing restoration
pg-erd-cloud existing issue #946 settings, APP_SECRET_FILE, encrypted DSNs Continue existing issue; versioned DSN recovery and key rewrap

Enumerate all accessible non-archived CWL repositories, retaining inaccessible/unscanned/failed entries in the denominator. Zero lexical findings or absence of .env is not migration completion.

Work packages and completion gates

  • Native Keyverse init/seal/unseal/recovery succeeds without any external KMS/vault and without dependent identity/database startup credentials.
  • Context-bound encryption, non-exportable key operations, versioned/3NF durable state, audit failure behavior, concurrency, rotation, rewrap and restore are implemented and tested.
  • Verified workload identity, narrow authorization, secret/key-operation distinction and credential lease/revocation contracts are released immutably.
  • PostgreSQL real-driver issuance/authentication/expiry/rotation/revocation and active-session behavior are proven; static _FILE wiring is not counted.
  • Run scheduler when base branches advance #151/Handle unknown stale auto-merge branches #153 compatibility hardening is integrated only with corrected default-profile/custody boundaries and current full checks.
  • AppGuardrail detection and central .github immutable invocation produce value-free exact-head inventories and reject new regressions without hiding legacy gaps.
  • EA/contracts owners reconcile the context map, API ownership, PRD/TRD/UML and product gap baseline; no domain truth/secret copying.
  • Consumer owner stacks demonstrate clean .env-free startup, authority outages, rotation/revocation and rollback without static fallback, then retire old paths.
  • Publish owner artifacts before adoption; record owner version + consumer SHA + deployment/recovery evidence.

PR check concurrency remains {workflow name}-{repository}-{PR number}; missing indirect PR identity fails closed. Cancel only obsolete same-group verification runs. Merge/release/deploy/migrations stay serialized, idempotent and non-cancelling. No force pushes, synthetic checks, gate weakening or unverified Close.

No real credentials, deployment or repository protections are changed by this issue revision. The corrected acceptance requirements remain unfulfilled until executable evidence exists.

Primary references (APA 7)

HashiCorp. (n.d.). Seal stanza. https://developer.hashicorp.com/vault/docs/configuration/seal

HashiCorp. (n.d.). Seal/Unseal. https://developer.hashicorp.com/vault/docs/concepts/seal

HashiCorp. (n.d.). Transit secrets engine. https://developer.hashicorp.com/vault/docs/secrets/transit

HashiCorp. (n.d.). PostgreSQL database secrets engine. https://developer.hashicorp.com/vault/docs/secrets/databases/postgresql

PostgreSQL Global Development Group. (n.d.). Certificate authentication (PostgreSQL 17). https://www.postgresql.org/docs/17/auth-cert.html

National Institute of Standards and Technology. (n.d.). FIPS 140-3 standards. https://csrc.nist.gov/projects/cryptographic-module-validation-program/fips-140-3-standards

GitHub. (n.d.). OpenID Connect reference. https://docs.github.com/en/actions/reference/security/oidc

OWASP Foundation. (n.d.). Secrets management cheat sheet. https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html

Keycloak. (n.d.). Using a vault. https://www.keycloak.org/server/vault

Vendor documents are architectural precedents, not adopted runtime dependencies or proof of Keyverse implementation. Keycloak's internal vault adapter is not the CWL-wide KMS/secret-service API.

Activity

  1. seonghobae commented on Sep 9, 2026

    @seonghobae
    ContributorAuthor

    2026-09-10 execution checkpoint

    This migration is now active in owner code; it is still not an organization-wide cutover.

    Keyverse owner stack

    • 🧪 테스트 개선: parse_conflict_reason 함수 단위 테스트 추가 #129 current exact head e4e4076bdf9efba9d7af29adb6716b3df1b3cb13: main was integrated by ordinary merge. Fixed the review findings rather than closing/replacing the PR: per-vault random KDF salt/version/iteration metadata is durable; normal startup refuses legacy ciphertext without KDF metadata; explicit one-shot legacy rewrap authenticates every row before transactional rewrite; privileged Key Vault GET responses use Cache-Control: no-store; ADR-0015 pins the Keycloak reference; ADR-0016 no longer claims zero consumer-side or Keyverse-side work. Hosted CI run 34417088027 is GREEN including locked install, Ruff, 100% docstrings, full tests with enforced 100% production statement/branch coverage, distribution build, realm validation and Compose validation. Security Scan/SAST/CodeQL are still queued; no merge-ready claim.
    • Run scheduler when base branches advance #151 remains the protected vault-root bootstrap child. CodeRabbit found a real parent-directory replacement risk; the child now validates every traversed directory descriptor, rejects group/world-writable untrusted parents, and allows only the deliberate root-owned sticky-directory profile. It must non-force integrate the stabilized 🧪 테스트 개선: parse_conflict_reason 함수 단위 테스트 추가 #129 head and rerun exact-head gates before promotion.
    • Handle unknown stale auto-merge branches #153 is a new independent root-process bootstrap slice against protected main. It removes .env.example, replaces Compose secret interpolation with /run/keyverse-bootstrap/* supervisor/KMS materialized files, uses POSTGRES_PASSWORD_FILE, and adds a bounded Keycloak file→native-process-environment entrypoint. ADR-0017 records that this is a Keyverse self-bootstrap exception only, not a consumer secret-file fallback. Current head cf8498dd33b7d64363a8359d76cab4cb47577ba9; hosted CI/security is running.
    • ⚡ Bolt: iter_json_objects O(N) 공백 탐색 최적화 #103 remains the canonical authorization/PDP line. It is intentionally not duplicated by the vault work and is still Draft/non-mergeable; workload secret reads must eventually consume its released verified-principal/authorization contract rather than mutable source.

    Detection owner

    • AppGuardrail fix(autofix): publish protected branch repairs through stacked PRs #1199 current head 021a1f4c226e6d1bcb7575fe1d37a7140823611c adds bounded executable dotenv dependency rules. Tests, Security Scan, SAST Semgrep, OpenSSF Evidence, Retention Audit, Pinned HTTPS, scan-path and Security Process were GREEN at the last exact-head read. Its CodeQL compatibility job is waiting for the central dispatched verdict; the gate has not been weakened.

    Consumer evidence

    • Naruon protected develop 042b0c70531b229af3acbd0421a2f23098d848b3 still explicitly loads ~/.env, ../.env, .env through SettingsConfigDict, operator_env_file_paths() and start_backend.py, and its tests intentionally assert that behavior. The migration branch exists but no runtime cutover is being fabricated before the Keyverse workload API is released. Correct sequence: Keyverse release → Naruon credential-resolution port/ACL/test double → shadow/denial/outage/rotation tests → replace startup contract → remove dotenv paths.
    • Organization code search also found 38 env_file matches; this is an inventory signal, not a 38-vulnerability claim. AppGuardrail remains the canonical classifier once released.

    No live secret was read, copied, rotated, deleted or placed in an issue/PR. No force push, bypass merge, direct sibling DB read, mutable PR-head runtime dependency or fallback vault was introduced.

  2. seonghobae commented on Sep 9, 2026

    @seonghobae
    ContributorAuthor

    2026-09-10 consumer preparation update — Naruon

    Opened ContextualWisdomLab/naruon#1630 from protected develop@042b0c70531b229af3acbd0421a2f23098d848b3.

    The stack deliberately does not consume an unreleased Keyverse endpoint and does not remove current bootstrap settings yet. It adds only the consumer-owned application seam:

    • value-free CredentialReference binding authority, tenant, environment, namespace, key, version, and purpose;
    • CredentialResolver protocol;
    • ResolvedCredential repr redaction;
    • UnavailableCredentialResolver that fails closed and has no env/dotenv/plaintext-DB/local-vault fallback;
    • Proposed Naruon ADR-0018 recording that production cutover remains BLOCKED-UPSTREAM until an immutable Keyverse workload credential release exists.

    TDD lineage: test-only RED commit 348f96c1b1eefda2b3d9e3b932a6457acd9209e7 referenced the intentionally absent core.credential_resolution; minimum implementation followed at df2b094791a8393528eaa2e1901195369317a809; current documentation/test head is 81954c0d226ef0b5f4eec72f9bd72ea82a0bf1e0.

    Current exact-head hosted Application CI, Security Scan, Bandit, Semgrep, CodeQL and Docker runs have been created and are queued/pending. No GREEN, merge, Keyverse API adoption, or dotenv-removal claim is made. The successor after immutable owner release must add the actual Keyverse adapter, shadow/rotation/revocation/outage evidence, and only then remove the corresponding Naruon legacy dotenv/environment paths.

  3. changed the title [-][CWL security migration] Make Keyverse the credential authority and retire dotenv runtime dependencies[/-] [+][CWL security migration] Independent Keyverse KMS and secret authority; retire dotenv and static credential files[/+] on Sep 10, 2026
  4. seonghobae commented on Sep 10, 2026

    @seonghobae
    ContributorAuthor

    Native Keyverse source increment — 2026-09-10

    Existing owner PR ContextualWisdomLab/keyverse#153 now contains the internal Rust custody component at exact head 8418d8bde90ad65a3c4b98aeccee830426f34f14, tree 47b47ce6f0641116cdf8463ed646424729d33cc9. It is a normal descendant preserving the transport hardening and independent-custody correction; no new vault owner or consumer implementation was created.

    services/key_custody adds OS-random root/recovery initialization, separate bounded quorum shares, sealed-by-default reconstruction, authenticated unseal, reseal, no root export API, and context-bound internal record protection. It has no environment/file/network/DB credential reader or external KMS startup dependency. Context association is not workload authorization.

    18 Rust test functions are authored, including a ciphertext fixture generated and checked independently with the local libsodium C API. Actual local C checks passed (root/data roundtrip, 52 data ciphertext/tag mutations rejected, changed AAD rejected), but Rust compilation/execution/coverage are NOT verified. The initial test-first job stayed queued; no observed RED→GREEN cycle is claimed. Fresh exact-head CI 34426740038 is queued at the latest read.

    The missing committed Cargo.lock remains a real gate. Temporary candidate generation cannot result in acceptance: the final job requires a tracked, unchanged lock. Capture Cargo's actual output, commit the lock, remove generation and rerun locked checks before promotion.

    This is not a released KMS or CWL migration completion. Workload/custodian authentication, authorization, durable audit/atomic persistence, monotonic rollback protection, key/credential lifecycle, PostgreSQL session/driver acceptance and immutable release remain open. Static #153 deployment transport is still not accepted as the final standalone profile. The #154/#143 cleanup ancestry and #128/#153 ADR-0017 collision are documented repair findings, not grounds to discard predecessor delta.

    The implementation plan, component README/AGENTS/CHANGELOG, doctoring and docs/product-technical-gap-baseline.md record these boundaries. No credentials, production deployments, protections, consumer runtime dependencies, merges or releases were changed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions