Skip to content

VaultEntry

One secret in the tenant's vault: an AI provider key, an environment variable for Pix sandboxes and Belai hosts, or a provider management key. Fields, YAML, HCL and CLI samples, and how apply treats it.

Checked against config-schemas@v1.15.0, terraform-provider-resolve@82cb23c, cli@v4.9.1

One secret in the tenant’s vault: an AI provider key, an environment variable for Pix sandboxes and Belai hosts, or a provider management key, with the grants that say where it may be used. The value is encrypted with KMS before it is stored, is sent once by the client, and is never exported, shown in a plan or returned by any endpoint. No grant means no access, and inside one entry a deny beats an allow. Two active entries that fill the same slot (a provider for provider keys, a variable name for environment variables) may not cover the same subject: a plan that would create such an overlap is refused. Deleting the document revokes the entry: its value is destroyed and it covers nothing, and the vault keeps a stub with its history. Connector secrets (forge tokens, the Wiz client secret) are not VaultEntry documents: they are created through their integration kinds. Automatic rotation is set up in the console and an apply leaves it as it is.

apiVersion vulnetix.com/v1
kind VaultEntry
Group Vault
Status Served. The config engine plans and applies it.
Objects per tenant many, keyed by metadata.name
Token and role An owner or admin session, or a vmt_ config management token that lists VaultEntry in its kinds and has the owner role. An admin or member token cannot carry this kind.
Secret fields spec.value: read on the client from valueFrom, sent once, never exported or shown in a plan
Terraform resource vulnetix_vault_entry, imported by name (see Terraform and OpenTofu)
CLI vulnetix config apply, CLI v3.168.0 and later.
Pinned schema v1.15.0/VaultEntry.schema.json
Newest schema latest/VaultEntry.schema.json
First released in v1.5.0
Print the built-in copy vulnetix config schema VaultEntry

Minimal

Only the fields the kind requires. From examples/VaultEntry/minimal.yaml.

YAML

# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/VaultEntry.schema.json
apiVersion: vulnetix.com/v1
kind: VaultEntry
metadata:
  name: npm-token
spec:
  type: env
  name: NPM_TOKEN

HCL (resource vulnetix_vault_entry)

# Only the arguments the kind requires. From config-schemas examples/VaultEntry/minimal.yaml.

resource "vulnetix_vault_entry" "npm_token" {
  name       = "npm-token"
  entry_name = "NPM_TOKEN"
  type       = "env"
}

CLI (applies it)

export VULNETIX_CONFIG_TOKEN=vmt_...   # a config management token
vulnetix config apply -f - --manager gitops:acme/platform --auto-approve <<'EOF'
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/VaultEntry.schema.json
apiVersion: vulnetix.com/v1
kind: VaultEntry
metadata:
  name: npm-token
spec:
  type: env
  name: NPM_TOKEN
EOF

Advanced

Every field the kind supports, with a when expression where it takes one. From examples/VaultEntry/advanced.yaml.

YAML

# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/VaultEntry.schema.json
# An Anthropic key for the AI Firewall and two sandboxes, an environment
# variable for every Belai host but one, and the OpenAI admin key the vault
# rotates provider keys with.
apiVersion: vulnetix.com/v1
kind: VaultEntry
metadata:
  name: anthropic-production
  labels:
    team: platform
  annotations:
    ticket: https://tracker.example.com/SEC-218
spec:
  type: provider_key
  provider: anthropic
  name: Anthropic production
  value: { env: VULNETIX_ANTHROPIC_KEY }
  grants:
    - surface: ai_firewall
      effect: allow
      all: true
    - surface: pix_sandbox
      effect: allow
      ids:
        - 3f1c2a9e-8b4d-4c7a-9e21-5d6f7a8b9c01
        - 7a2e4b6c-1d3f-4e5a-8b7c-9d0e1f2a3b4c
  expiresAt: 2027-06-30T00:00:00Z
---
apiVersion: vulnetix.com/v1
kind: VaultEntry
metadata:
  name: npm-token
spec:
  type: env
  name: NPM_TOKEN
  value: { env: VULNETIX_NPM_TOKEN }
  grants:
    - surface: belai_host
      all: true
    - surface: belai_host
      effect: deny
      ids:
        - 0b1c2d3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e
---
apiVersion: vulnetix.com/v1
kind: VaultEntry
metadata:
  name: openai-admin
spec:
  type: management
  provider: openai
  name: OpenAI admin
  value: { env: VULNETIX_OPENAI_ADMIN_KEY }

HCL (resource vulnetix_vault_entry)

# Every argument the kind supports. From config-schemas examples/VaultEntry/advanced.yaml.

variable "anthropic_production_value" {
  type      = string
  sensitive = true
  ephemeral = true
}
variable "npm_token_value" {
  type      = string
  sensitive = true
  ephemeral = true
}
variable "openai_admin_value" {
  type      = string
  sensitive = true
  ephemeral = true
}

resource "vulnetix_vault_entry" "anthropic_production" {
  name       = "anthropic-production"
  entry_name = "Anthropic production"
  expires_at = "2027-06-30T00:00:00Z"
  grants = [
    {
      all     = true
      effect  = "allow"
      surface = "ai_firewall"
    },
    {
      effect  = "allow"
      ids     = ["3f1c2a9e-8b4d-4c7a-9e21-5d6f7a8b9c01", "7a2e4b6c-1d3f-4e5a-8b7c-9d0e1f2a3b4c"]
      surface = "pix_sandbox"
    },
  ]
  provider_slug    = "anthropic"
  type             = "provider_key"
  value_wo         = var.anthropic_production_value
  value_wo_version = 1
  labels = {
    team = "platform"
  }
  annotations = {
    ticket = "https://tracker.example.com/SEC-218"
  }
}

resource "vulnetix_vault_entry" "npm_token" {
  name       = "npm-token"
  entry_name = "NPM_TOKEN"
  grants = [
    {
      all     = true
      surface = "belai_host"
    },
    {
      effect  = "deny"
      ids     = ["0b1c2d3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e"]
      surface = "belai_host"
    },
  ]
  type             = "env"
  value_wo         = var.npm_token_value
  value_wo_version = 1
}

resource "vulnetix_vault_entry" "openai_admin" {
  name             = "openai-admin"
  entry_name       = "OpenAI admin"
  provider_slug    = "openai"
  type             = "management"
  value_wo         = var.openai_admin_value
  value_wo_version = 1
}

CLI (applies it)

export VULNETIX_CONFIG_TOKEN=vmt_...   # a config management token
export VULNETIX_ANTHROPIC_KEY=...   # read on this machine by valueFrom, never written to the document
export VULNETIX_NPM_TOKEN=...   # read on this machine by valueFrom, never written to the document
export VULNETIX_OPENAI_ADMIN_KEY=...   # read on this machine by valueFrom, never written to the document
vulnetix config apply -f - --manager gitops:acme/platform --auto-approve <<'EOF'
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/VaultEntry.schema.json
# An Anthropic key for the AI Firewall and two sandboxes, an environment
# variable for every Belai host but one, and the OpenAI admin key the vault
# rotates provider keys with.
apiVersion: vulnetix.com/v1
kind: VaultEntry
metadata:
  name: anthropic-production
  labels:
    team: platform
  annotations:
    ticket: https://tracker.example.com/SEC-218
spec:
  type: provider_key
  provider: anthropic
  name: Anthropic production
  value: { env: VULNETIX_ANTHROPIC_KEY }
  grants:
    - surface: ai_firewall
      effect: allow
      all: true
    - surface: pix_sandbox
      effect: allow
      ids:
        - 3f1c2a9e-8b4d-4c7a-9e21-5d6f7a8b9c01
        - 7a2e4b6c-1d3f-4e5a-8b7c-9d0e1f2a3b4c
  expiresAt: 2027-06-30T00:00:00Z
---
apiVersion: vulnetix.com/v1
kind: VaultEntry
metadata:
  name: npm-token
spec:
  type: env
  name: NPM_TOKEN
  value: { env: VULNETIX_NPM_TOKEN }
  grants:
    - surface: belai_host
      all: true
    - surface: belai_host
      effect: deny
      ids:
        - 0b1c2d3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e
---
apiVersion: vulnetix.com/v1
kind: VaultEntry
metadata:
  name: openai-admin
spec:
  type: management
  provider: openai
  name: OpenAI admin
  value: { env: VULNETIX_OPENAI_ADMIN_KEY }
EOF

Fields

Paths use dots for nesting and [] for the items of a list. Required means required whenever the parent object is present. A default is what the server uses when the field is left out.

Field Type Required Default Allowed values Secret Description
apiVersion string yes exactly vulnetix.com/v1 The document format version. Every kind in this release is vulnetix.com/v1.
kind string yes exactly VaultEntry Always VaultEntry.
metadata object yes no other keys
metadata.name string yes pattern ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$ The object’s name, unique per kind within a tenant. It is the natural key: plan, apply, export and the Terraform provider all address an object by kind and name.
metadata.org string no format uuid The tenant (organization UUID) the document belongs to. When set, plan and apply refuse to run against any other tenant.
metadata.labels object no map of string to string (length 0 to 256); keys match ^[a-z0-9]([a-z0-9._/-]{0,61}[a-z0-9])?$ Free key/value labels. Stored with the object, never interpreted by the server.
metadata.annotations object no map of string to string (length 0 to 4096) Free key/value notes for people and tools, such as a ticket link.
spec object yes no other keys
spec.type string yes provider_key, env, management provider_key: an AI provider’s API key, handed to the AI Firewall gateway, Pix sandboxes and Belai hosts that hold a grant. env: an environment variable set in Pix sandboxes and on Belai hosts that hold a grant. management: a provider admin key that the vault uses to rotate provider keys; it is never granted to a surface. The type cannot change: declare a new entry instead.
spec.provider string no pattern ^[a-z0-9][a-z0-9._-]{0,63}$ The AI Firewall provider slug the key is for, a built-in provider or one of the tenant’s AiProvider objects. Required for provider_key and management, and not allowed for env. The provider must exist and be enabled when the plan runs. It cannot change: declare a new entry instead.
spec.name string yes length 1 to 64 For env, the variable name: upper case letters, digits and underscore, starting with a letter or underscore. Names such as PATH, HOME and LD_PRELOAD, and names starting LD_, BELAI_, VULNETIX_, VX_, BASH_ or SSH_, are reserved and refused at plan. A variable’s name cannot change: declare a new entry instead. For provider_key and management, the label the console shows: 1 to 64 letters, digits, spaces or . _ : / @ + -.
spec.value object no 1 to 1 keys; no other keys yes Where the client reads the secret value. Required when the entry is created; left out, the stored value is kept. Supplying the value the entry already holds is no change; a different value makes a new version and keeps the old one’s fingerprint in the entry’s history. An env value is at least 8 characters, so that it can be scrubbed from output reliably, and at most 4096; a key has no line breaks.
spec.value.env string no pattern ^[A-Za-z_][A-Za-z0-9_]*$ Name of an environment variable.
spec.value.file string no length 1 to any Path to a file holding the value. Trailing newlines are trimmed.
spec.grants array of object no 0 to 12 items Where the value may be used. Each grant names a surface and either every subject on it or a list of subject ids. Left out or empty, the entry is stored but nothing may use it. At most 12 grants.
spec.grants[].surface string yes pix_sandbox, belai_host, ai_firewall pix_sandbox: Pix sandboxes, by their canonical sandbox id, which survives relaunches. belai_host: self-hosted Belai hosts, by host id. ai_firewall: AI Firewall callers, by the id of the principal that owns the Vulnetix API key making the request.
spec.grants[].effect string no allow allow, deny allow lets the subjects use the value; deny takes subjects away from an allow, and wins over it.
spec.grants[].all boolean no true covers every subject on the surface, now and later. A grant is all or a list of ids, not both.
spec.grants[].ids array of string no 1 to 100 items; each item: format uuid The subjects covered, as UUIDs. 1 to 100 ids; duplicates are dropped and the list is kept sorted.
spec.expiresAt string no format date-time, or format date When the value stops being handed out. Left out, it never expires. A new expiry must be at least a minute and at most 10 years away; an expired entry is refused with vault_key_expired rather than decrypted.

Rules

Conditions the schema enforces beyond each field’s own type. vulnetix config validate and the engine’s plan report a document that breaks one.

On Rule
spec When type is env: name must be pattern ^[A-Z_][A-Z0-9_]{0,63}$. Otherwise: provider is required and name must be pattern ^[A-Za-z0-9][A-Za-z0-9 ._:/@+-]{0,63}$.
spec When type is management: grants must be 0 to 0 items.
spec.grants[] Exactly one of these holds: (1) all is required and all must be true; (2) ids is required.

Applying this kind

  • Command. vulnetix config apply -f <file>; the CLI line above says from which release. Plan first with vulnetix config plan: it shows each object as create, update, delete or no change, with a planHash that apply then holds to. Apply writes in one transaction, except for the second phase below.
  • Manager. Each object records the manager that applied it (terraform, console or gitops:<repo>). --prune deletes only objects its own manager owns. See The manager and the config engine.
  • Second phase. This kind is not written inside the apply transaction. The other kinds apply and commit first, then each VaultEntry is written on its own, in the tenant vault. One that fails reports status.phase: Failed and a message, and nothing is recorded for it. The others stay applied and the apply answers 207. Plan again to see what is left. A single PUT from the Terraform provider answers 502 external_failed instead.
  • Status. A failed second-phase write reports phase Failed and the entry owns nothing. The phases the engine reports are explained under status phases.

How apply treats it

  • The vault lives wholly outside Postgres, so this kind is written in the second phase. After the Postgres transaction commits, each entry is a compare-and-swap of the record inside a small transaction that records its ownership. Its undo puts the entry back (also a compare-and-swap, refused if someone changed it since) when that cannot be recorded.
  • A failed entry is reported with phase Failed and owns nothing.
  • The value is a valueFrom secret, required to create, never read back, exported or shown in a plan. The same value again is no change.
  • The vault service checks the document, so it is refused for the reasons the vault page refuses it.
  • The entry keeps the metadata.name it was applied under. An undeclared entry is listed under a name derived from its id, type and provider or variable. The type cannot change.
  • Delete revokes the entry, keeping the stub and history. AI firewall and sandbox derives run after the write, in the background, one at a time per tenant.
  • Owner only: a token for this kind needs the owner role.

Terraform and OpenTofu

The resource is vulnetix_vault_entry in the vulnetix/resolve provider. Its arguments are the spec in snake case, beside name, labels and annotations from metadata. The Minimal and Advanced HCL are above. The provider’s own reference is vulnetix_vault_entry.

Import an object that already exists by its name:

# Import an existing VaultEntry by its name (metadata.name).
terraform import vulnetix_vault_entry.npm_token npm-token

A secret is two arguments, never stored in the plan or the state: value_wo (write-only) and value_wo_version. Change the version number to send a new value. See Secrets.

Install, authentication and how state is read: Terraform and OpenTofu.

Check a file with vulnetix config validate -f <file>. See Validate documents. In an editor, start the file with the schema comment.

Edit this pageSources: config-schemas/schemas/VaultEntry.schema.json, config-schemas/schemas/common.schema.json, config-schemas/examples/VaultEntry/minimal.yaml, config-schemas/examples/VaultEntry/advanced.yaml, terraform-provider-resolve/examples/resources/vulnetix_vault_entry/minimal.tf, terraform-provider-resolve/examples/resources/vulnetix_vault_entry/advanced.tf, vdb-site/docs/platform-iac-engine.md, vdb-site/api/internal/handler/config_engine_kinds.go, vdb-site/api/internal/config/vaultentry.go
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.