@agenticprimitives/ap-kms
v0.0.0-alpha.4
Published
Manifest-driven managed-KMS orchestrator: provision per-identity Cloud-KMS HSM signing keys + per-key IAM, resolve each agent's Smart Agent (agent-naming), derive + verify the EVM delegate address, and push the minimal runtime secrets to deploy targets wi
Maintainers
Readme
@agenticprimitives/ap-kms
Manifest-driven managed-KMS orchestrator. One declarative kms.manifest.json is the single source of
truth for an app's signing identities; ap-kms apply then does every step to get Cloud-KMS signing working:
- Provision the keyring + a per-identity HSM secp256k1 signing key + per-key IAM (gcloud-free REST, via
@agenticprimitives/key-custody/provision-gcp). Idempotent. - Derive + report each key's EVM address (verify it before wiring).
- Resolve each agent-naming name → its Smart Agent address (
@agenticprimitives/agent-naming). - Wire the minimal runtime secrets to each deploy target via an app-supplied secret writer with no
terminal echo —
--write. The orchestrator is provider-agnostic; concrete deploy-platform code (Cloudflare/Vercel/…) lives in the app and is injected aswriteSecret(ADR-0020).
The one human step it never does is the owner-signed delegation leaf (Smart Agent → KMS key), produced
by the content-signer ceremony. ap-kms apply reports per-identity whether it's bound; ap-kms verify
confirms each agent's live KMS delegate (derived from the key) still equals the owner-authorized delegate
stored in the deployment's bindings, and that the stored SA matches the name's on-chain resolution.
Design
The core (@agenticprimitives/ap-kms) is pure — the provisioner, name resolver, address derivation,
stored-bindings reader, and secret writer are all injected (KmsOrchestratorDeps). This keeps
key-custody a leaf and the orchestration testable. The node wiring (@agenticprimitives/ap-kms/node)
assembles the provider-agnostic implementations (provisioner / derivation / resolver / bindings reader) and
the fs manifest loader; the deploy-platform secret writer stays in the app and is injected:
import { applyKmsManifest } from '@agenticprimitives/ap-kms';
import { loadManifest, makeNodeDeps } from '@agenticprimitives/ap-kms/node';
import { writeSecret } from './my-app-secret-writers.js'; // app-owned: switches on deployment.platform
const manifest = loadManifest('kms.manifest.json');
await applyKmsManifest(manifest, makeNodeDeps(manifest, { writeSecret }), { write: true });deployment.platform is an opaque tag; the app's writeSecret(deployment, name, value) decides how to
push the secret (e.g. a worker secret CLI, a hosting-provider REST API). No provider hostnames or
provider-specific code live in this package.
CLI
ap-kms apply # provision + IAM + derive + resolve SA + REPORT (no secret writes)
ap-kms apply --write --writers ./w.js # also push runtime secrets via the app-supplied writer module
ap-kms apply --dry-run # print the plan only (no GCP mutations)
ap-kms verify # read-only drift check vs. stored owner-authorized delegations
ap-kms <cmd> --manifest path/to/kms.manifest.json--writers <module> is dynamically imported and must export writeSecret(deployment, name, value) (or
default-export it). The naming RPC URL comes from the env var named by manifest.naming.rpcUrlEnv (kept out
of the manifest because it carries an API key).
