Plan File Format Reference¶
A MigrationPlan is a YAML file that describes which workloads to migrate from Kubernetes Secrets to an EU-hosted vault. It is generated by cloudtaser target discover -o and consumed by source apply-plan, source verify-plan, and target protect --plan.
The plan file serves as a reviewable compliance artifact. Security teams can audit it before any changes are made to the cluster or vault.
Schema¶
apiVersion: cloudtaser.io/v1 # Required. Must be exactly "cloudtaser.io/v1"
kind: MigrationPlan # Required. Must be exactly "MigrationPlan"
metadata:
name: <string> # Required. Plan name for identification
cluster: <string> # Optional. Cluster API endpoint (auto-populated by discover)
createdAt: <timestamp> # Optional. ISO 8601 timestamp (auto-populated by discover)
createdBy: <string> # Optional. Username (auto-populated from OS user)
tenants: # Required. List of tenants (grouped by namespace)
- name: <string> # Required. Tenant name (typically matches namespace)
namespace: <string> # Required. Kubernetes namespace
workloads: # Required. List of workloads in this tenant
- kind: <string> # Required. Deployment, StatefulSet, or DaemonSet
name: <string> # Required. Workload name
replicas: <int> # Optional. Current replica count (informational)
status: <string> # Optional. pending, migrated, or skipped
secrets: # Required. Secret mappings for this workload
- source: <string> # Required. Original secret reference
vaultPath: <string> # Required. Target vault KV v2 path
fields: # Optional. Field-to-environment-variable mapping
<field>: <ENV_VAR>
Fields¶
Top-level¶
| Field | Type | Required | Description |
|---|---|---|---|
apiVersion |
string | Yes | Must be cloudtaser.io/v1. The CLI rejects plans with a different version. |
kind |
string | Yes | Must be MigrationPlan. The CLI rejects plans with a different kind. |
metadata |
object | Yes | Plan-level identification and audit fields. |
tenants |
list | Yes | List of tenants. May be empty ([]). |
metadata¶
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Human-readable plan name. Used in CLI output and reports. |
cluster |
string | No | Kubernetes API endpoint of the target cluster. Auto-populated by discover from the kubeconfig. |
createdAt |
timestamp | No | When the plan was generated. ISO 8601 format. |
createdBy |
string | No | Who generated the plan. Auto-populated from the OS user. |
tenants[]¶
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Tenant name. Used to derive vault policy and role names (<name>-read, <name>-role). |
namespace |
string | Yes | Kubernetes namespace containing the workloads. |
workloads |
list | Yes | List of workloads in this tenant. |
tenants[].workloads[]¶
| Field | Type | Required | Description |
|---|---|---|---|
kind |
string | Yes | Workload kind: Deployment, StatefulSet, or DaemonSet. |
name |
string | Yes | Workload name (as shown by kubectl get). |
replicas |
int | No | Current replica count. Informational only -- used in interactive mode output. |
status |
string | No | Migration status: pending (default), migrated, or skipped. Updated by target protect --plan. |
secrets |
list | Yes | Secret mappings for this workload. |
tenants[].workloads[].secrets[]¶
| Field | Type | Required | Description |
|---|---|---|---|
source |
string | Yes | Original secret reference. Format depends on the source type (see below). |
vaultPath |
string | Yes | Target vault KV v2 path. Used by apply-plan for policy creation and by verify-plan for secret existence checks. |
fields |
map[string]string | No | Maps vault secret fields to environment variable names. If omitted, all fields in the vault secret are injected with their original key names. |
Source reference format¶
The source field uses a prefix to indicate the origin:
| Prefix | Example | Meaning |
|---|---|---|
k8s-secret/ |
k8s-secret/db-credentials |
Kubernetes Secret named db-credentials |
vault-injector/ |
vault-injector/secret/data/app/config |
Existing Vault Agent Injector annotation path |
Status values¶
The status field on each workload tracks migration progress:
| Value | Meaning |
|---|---|
pending |
Not yet migrated. Will be processed by target protect --plan. |
migrated |
Successfully migrated. CloudTaser annotations applied and rolling restart triggered. |
skipped |
Explicitly skipped during interactive migration. Will not be reprocessed. |
When target protect --plan runs, it skips workloads with migrated or skipped status. This makes the migration resumable -- if interrupted, re-run the same command and only pending workloads are processed.
How each command uses the plan¶
| Command | Reads | Writes | Uses |
|---|---|---|---|
target discover -o |
-- | Creates the plan | Scans cluster, generates tenant/workload/secret structure |
source apply-plan |
Plan file | -- | Creates vault policies and K8s auth roles per tenant |
source verify-plan |
Plan file | -- | Checks each vaultPath exists and has expected fields |
target protect --plan |
Plan file | Updates status fields |
Patches workloads with CloudTaser annotations |
Vault naming conventions¶
The discover command generates vault paths using the pattern:
For Kubernetes Secret references:
- Secret
db-credentialsin namespacepaymentsbecomessecret/data/payments/db-credentials
For existing Vault Agent Injector annotations:
- The existing vault path is preserved as-is
The apply-plan command uses the vaultPath values to construct policies:
- Policy name:
<tenant-name>-read - Policy rules:
readonsecret/data/<path>andread, listonsecret/metadata/<path> - K8s auth role:
<tenant-name>-rolebound to the tenant's namespace
Examples¶
Single-namespace deployment¶
apiVersion: cloudtaser.io/v1
kind: MigrationPlan
metadata:
name: staging-migration
cluster: https://staging.k8s.example.com
createdAt: "2026-04-01T10:00:00Z"
createdBy: platform-team
tenants:
- name: default
namespace: default
workloads:
- kind: Deployment
name: web-app
replicas: 2
status: pending
secrets:
- source: k8s-secret/app-config
vaultPath: secret/data/default/app-config
fields:
database_url: DATABASE_URL
redis_url: REDIS_URL
Multi-namespace enterprise deployment¶
apiVersion: cloudtaser.io/v1
kind: MigrationPlan
metadata:
name: production-migration
cluster: https://prod.k8s.example.com
createdAt: "2026-04-01T10:00:00Z"
createdBy: platform-team
tenants:
- name: payments
namespace: payments
workloads:
- kind: Deployment
name: payment-api
replicas: 3
status: pending
secrets:
- source: k8s-secret/db-credentials
vaultPath: secret/data/payments/db-credentials
fields:
username: DB_USER
password: DB_PASS
- source: k8s-secret/stripe-key
vaultPath: secret/data/payments/stripe-key
fields:
secret_key: STRIPE_SECRET_KEY
- kind: Deployment
name: payment-worker
replicas: 2
status: pending
secrets:
- source: k8s-secret/db-credentials
vaultPath: secret/data/payments/db-credentials
fields:
username: DB_USER
password: DB_PASS
- name: trading
namespace: trading
workloads:
- kind: StatefulSet
name: trading-engine
replicas: 1
status: pending
secrets:
- source: k8s-secret/api-key
vaultPath: secret/data/trading/api-key
fields:
key: API_KEY
- kind: DaemonSet
name: market-data-collector
status: pending
secrets:
- source: k8s-secret/feed-credentials
vaultPath: secret/data/trading/feed-credentials
Partially completed migration¶
After running target protect --plan interactively and approving only the first workload:
apiVersion: cloudtaser.io/v1
kind: MigrationPlan
metadata:
name: production-migration
tenants:
- name: payments
namespace: payments
workloads:
- kind: Deployment
name: payment-api
replicas: 3
status: migrated # Already done
secrets:
- source: k8s-secret/db-credentials
vaultPath: secret/data/payments/db-credentials
fields:
username: DB_USER
password: DB_PASS
- kind: Deployment
name: payment-worker
replicas: 2
status: pending # Will be processed on next run
secrets:
- source: k8s-secret/db-credentials
vaultPath: secret/data/payments/db-credentials
fields:
username: DB_USER
password: DB_PASS
Workload with no field mappings¶
When fields is omitted, all fields in the vault secret are injected using their original key names as environment variable names:
workloads:
- kind: Deployment
name: simple-app
status: pending
secrets:
- source: k8s-secret/app-secrets
vaultPath: secret/data/default/app-secrets
# No fields mapping -- all vault fields injected as-is
Editing plans¶
Plans are standard YAML files. You can edit them with any text editor to:
- Remove workloads that should not be migrated
- Adjust vault paths to match your naming convention
- Fix field mappings if the auto-detected env var names are wrong
- Change tenant names (this affects the generated policy and role names)
- Reset status from
skippedtopendingto re-include a previously skipped workload
The only fields that must not be changed are apiVersion and kind -- the CLI validates these on load.
Related¶
- Migration Plan Workflow -- step-by-step guide
- Enterprise Deployment Architecture -- CLI-as-orchestrator model
- CLI Reference -- full command documentation