Bundle Reference
Complete annotated YAML schema for the keyzero bundle configuration
A bundle is a single YAML file that defines the complete keyzero server configuration. Pass it to kz server start with --bundle <path>, or validate it with kz server check --bundle <path>.
Top-Level Structure
version: "1" # Required. Bundle schema version.
issuers: [...] # Required. JWT issuer configurations with type and profiles.
policies: [...] # Required. CEL authorization rules.
resources: [...] # Required. Secret refs with glob patterns.
backends: { ... } # Required. Secret storage backend definitions.
issuers
Each issuer defines a trusted JWT source. At least one of jwks_url or static_keys must be provided.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Unique issuer name |
issuer_url | string | yes | Expected iss claim value |
jwks_url | string | no | URL to fetch JSON Web Key Set |
audience | string | no | Expected aud claim value. If omitted, audience is not validated |
type | string | yes | Issuer type: github-actions, kubernetes, gcp, aws, or custom |
map | map | no | Override or extend the built-in claim mappings for this issuer type |
static_keys | list | no | Inline public keys for verification |
Issuer types and built-in profiles
Each issuer type has a built-in profile that maps JWT claims to standard variables automatically. You can override any mapping with the map field.
| Type | org | service | env | action | branch | actor |
|---|---|---|---|---|---|---|
github-actions | repository_owner | repository | environment | workflow | ref | actor |
kubernetes | namespace | serviceaccount | -- | -- | -- | -- |
gcp | project_id | email | -- | -- | -- | -- |
aws | account_id | arn | -- | -- | -- | -- |
custom | -- | -- | -- | -- | -- | -- |
The custom type has no default mappings. You must provide an explicit map for any variables you want populated.
static_keys entry
| Field | Type | Required | Description |
|---|---|---|---|
kid | string | yes | Key ID, matched against token header kid |
alg | string | yes | Algorithm: RS256, ES256, HS256, etc. |
pem | string | yes | PEM-encoded key material |
issuers:
- name: github-actions
issuer_url: "https://token.actions.githubusercontent.com"
jwks_url: "https://token.actions.githubusercontent.com/.well-known/jwks"
audience: "keyzero"
type: github-actions
- name: k8s
issuer_url: "https://kubernetes.default.svc"
jwks_url: "https://kubernetes.default.svc/openid/v1/jwks"
type: kubernetes
- name: local
issuer_url: "https://local.dev"
audience: "keyzero"
type: custom
map:
org: team
service: sub
static_keys:
- kid: "dev-key-01"
alg: RS256
pem: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBg...
-----END PUBLIC KEY-----
policies
CEL-based authorization rules. Evaluated top-down, first-match-wins. If no policy matches, an implicit deny applies.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Unique policy name (returned in responses) |
description | string | no | Human-readable description |
rule | string | yes | CEL expression. Must return a boolean |
effect | string | yes | allow or deny |
CEL context variables:
| Variable | Type | Trust | Description |
|---|---|---|---|
issuer | string | Verified | Matched issuer name |
org | string | Verified | Organizational boundary (mapped from JWT) |
service | string | Verified | Workload identity |
env | string | Verified | Environment |
action | string | Verified | What the workload is doing |
branch | string | Verified | Code version/ref |
actor | string | Verified | Human who triggered |
groups | list | Verified | Group membership |
claims.* | map | Verified | Raw JWT claims (e.g. claims.repository) |
ref | string | Request | Requested secret path |
context.* | map | Untrusted | Caller-declared fields |
Use ref.matches() with glob patterns to scope policies to specific secret paths instead of tag-based pre-filters:
policies:
- name: allow-backend-prod
description: "Backend team can access prod secrets"
rule: "org == 'myorg' && service == 'myorg/backend' && ref.matches('secret/data/prod/**')"
effect: allow
- name: allow-dev
description: "Any authenticated caller can access dev secrets"
rule: "ref.matches('secret/data/dev/**')"
effect: allow
- name: default-deny
rule: "true"
effect: deny
resources
Secret references with glob patterns and a single resolver per resource.
| Field | Type | Required | Description |
|---|---|---|---|
ref | string | yes | Path or glob pattern (e.g. secret/data/prod/**) |
resolver | string | yes | References a key in backends |
mode | string | no | direct (default) or short_lived |
credential_location | string | no | Where to place the credential in proxied requests (default: header:Authorization:Bearer) |
ttl | integer | no | Time-to-live in seconds for short_lived mode (default: 300) |
path | string | no | Backend-specific path |
field | string | no | Field to extract from the secret |
role_arn | string | no | AWS STS role ARN for AssumeRole |
duration_seconds | integer | no | STS session duration (default: 900) |
secret_id | string | no | AWS Secrets Manager secret ID |
Match priority
When a request matches multiple resource entries, the most specific match wins:
- Exact match -- literal path with no globs
- Narrower glob -- more specific pattern (e.g.
secret/data/prod/db/*) - Broader glob -- wider pattern (e.g.
secret/data/prod/**) - First defined -- declaration order as tiebreaker
resources:
- ref: "secret/data/prod/db/password"
resolver: vault-prod
mode: direct
path: secret/data/db/prod
field: password
credential_location: "header:Authorization:Bearer"
- ref: "secret/data/prod/**"
resolver: vault-prod
mode: direct
- ref: "secret/data/dev/**"
resolver: local
mode: direct
backends
Named backend configurations. Each key is referenced by resource resolver fields.
| Field | Type | Required | Description |
|---|---|---|---|
type | string | yes | Backend type (see table below) |
address | string | depends | Server address (Vault) |
auth.method | string | no | Auth method (Vault) |
auth.role | string | no | Auth role (Vault) |
region | string | no | AWS region |
path | string | depends | File path (env_file) |
vault | string | no | 1Password vault name |
Backend types
| Type | Description | Required backend fields |
|---|---|---|
env_file | Read from a KEY=VALUE file | path |
hashicorp_vault | HashiCorp Vault KV v2 | address |
aws_secrets_manager | AWS Secrets Manager | region (optional) |
aws_sts | AWS STS AssumeRole | region (optional) |
onepassword_cli | 1Password CLI (op) | vault (optional) |
backends:
local:
type: env_file
path: ./secrets.env
vault-prod:
type: hashicorp_vault
address: https://vault.example.com
aws:
type: aws_secrets_manager
region: us-east-1
Complete Example
version: "1"
issuers:
- name: github-actions
issuer_url: "https://token.actions.githubusercontent.com"
jwks_url: "https://token.actions.githubusercontent.com/.well-known/jwks"
audience: "keyzero"
type: github-actions
- name: local
issuer_url: "https://local.dev"
audience: "keyzero"
type: custom
map:
org: team
service: sub
static_keys:
- kid: "dev-key-01"
alg: RS256
pem: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...
-----END PUBLIC KEY-----
policies:
- name: allow-backend-prod
description: "Backend team can access prod secrets"
rule: "org == 'myorg' && service == 'myorg/backend' && ref.matches('secret/data/prod/**')"
effect: allow
- name: allow-dev
description: "Any authenticated caller can access dev secrets"
rule: "ref.matches('secret/data/dev/**')"
effect: allow
- name: block-compromised
description: "Block known-compromised service"
rule: "service == 'compromised-service'"
effect: deny
- name: default-deny
rule: "true"
effect: deny
resources:
- ref: "secret/data/prod/db/password"
resolver: vault-prod
mode: direct
path: secret/data/db/prod
field: password
credential_location: "header:Authorization:Bearer"
- ref: "secret/data/dev/**"
resolver: local
mode: direct
field: DB_PASSWORD
- ref: "secret/data/dev/api-key"
resolver: local
mode: direct
field: API_KEY
credential_location: "header:X-API-Key:"
backends:
local:
type: env_file
path: ./playground/secrets.env
vault-prod:
type: hashicorp_vault
address: https://vault.example.com