Migrates Kuma and Kong Mesh policy manifests across the API changes in the 2.x line and into 3.0 — rewrites what can be rewritten safely, and reports what cannot, with the reason.
The policy API changed substantially across 2.0–2.14, and some of the 3.0 removals are silent.
The Kuma and Kong Mesh policy API changed substantially across 2.0–2.14, and 3.0 removes a number of fields that 2.14 still accepts. Some of those removals are silent: the manifest applies cleanly and simply stops doing what it used to.
kuma-migrator automates the mechanical parts, flags the parts that need a
human, and writes a Markdown report of every change it made or would make.
Two commands, plus a manual apply step. Extract from a live control plane, migrate (preview first with --dry-run), apply.
# 1a. Pull resources via kumactl (self-hosted OR Konnect-hosted, zonal or Global CP)
kuma-migrator extract --kumactl-context konnect-global-prod --output-dir ./raw-policies
# 1b. ...or via kubectl (self-hosted, Kubernetes-backed CP)
kuma-migrator extract --kube-context zone-eu-west1-prod --output-dir ./raw-policies
# 2. Write the migrated manifests + migration-report.md
# (add --dry-run to preview first — writes migration-plan.md, no YAML)
kuma-migrator migrate --input-dir ./raw-policies --output-dir ./migrated
# Now read migration-report.md — it gives the exact apply order for your
# setup (Mesh resources go last: they switch on meshServices.mode: Exclusive)
# 3a. Apply them yourself if you used --kumactl-context (self-hosted or
# Konnect) — kumactl rejects a directory, so apply one file at a time
kumactl config use-context konnect-global-prod
kumactl apply -f ./migrated/konnect-global-prod-global-ctx/mesh-default/resiliency/MeshTimeout-my-timeout.yaml
# 3b. ...or via kubectl if you extracted via --kube-context — this step
# is manual; kuma-migrator never touches your control plane's state
kubectl apply -f ./migrated/zone-eu-west1-prod-zone-ctx/mesh-default/resiliency/
Applied to every legacy policy the tool touches.
targetRef, a legacy policy kind
rewritten to its Mesh* successor, and a tag/label selector expanded into a
typed reference — the same mechanism behind every conversion below.
Alongside these, every output document is scanned for deprecated and removed fields across the 2.x line and 3.0.
| Scenario | Migration |
|---|---|
| Legacy | sources/destinations/selectors policies → targetRef/to/from/rules, with the conf body rewritten to the successor's schema — except TrafficRoute (ambiguous HTTP vs TCP) and VirtualOutbound (no single successor), reported for manual migration |
| Subset | MeshSubset with service tags → Dataplane/MeshService |
| Rules | Deprecated from[] → rules[], for MeshTimeout/MeshCircuitBreaker/MeshRateLimit/MeshAccessLog/MeshTLS only (Kuma 2.10+) — MeshTrafficPermission/MeshFaultInjection use a different, SPIFFE-based rules[] shape and are not auto-converted |
| Mesh | Mesh CRD observability → standalone MeshMetric/MeshTrace/MeshAccessLog |
| ExternalService | ExternalService → MeshExternalService |
| GW | MeshGateway and MeshGatewayRoute → Gateway API. Kuma 3.0 deletes the built-in gateway API outright, so under v3 MeshGatewayInstance is reported rather than converted, and the source objects must be deleted before upgrading. MeshHTTPRoute/MeshTCPRoute are current policies on both lines and pass through unchanged |
| OPAPolicy | Kong Mesh OPAPolicy → MeshOPA |
Why MTP/MFI's from[] is never auto-converted:
MeshTrafficPermission modes.
Full list: migration paths and deprecation warnings.
--to-latest v2|v3One output cannot serve both lines.
migrate (including its --dry-run mode) takes --to-latest v2
(default, latest 2.x) or v3. 3.0 removes fields 2.14 still requires, and some 3.0 replacements
(MeshOpenTelemetryBackend, SecureDataSource) do not exist before
2.14.
v2 keeps the output applicable to a 2.x control plane and
reports 3.0 removals as forward-looking advisories.
v3 rewrites what it safely can and flags the rest — a v3
report carries a banner warning that the output must not be applied to a 2.x CP.
Every release archive carries a build provenance attestation.
You do not have to trust that a downloaded archive matches this repository — you can check. Each release binds its archives to the exact commit and GitHub Actions run that built them, cryptographically, via GitHub build provenance attestation.
VERSION=$(gh release view --repo Kong/kuma-migrator --json tagName --jq '.tagName' | tr -d 'v')
curl -LO "https://github.com/Kong/kuma-migrator/releases/latest/download/kuma-migrator_${VERSION}_linux_amd64.tar.gz"
gh attestation verify "kuma-migrator_${VERSION}_linux_amd64.tar.gz" --repo Kong/kuma-migrator
The same digests appear in the release's checksums.txt, in the attestation,
and in the Homebrew cask's sha256 fields — nothing is rebuilt in between.
brew install --cask bcollard/kuma-migrator/kuma-migrator
Download the binary for your platform from the
GitHub Releases page —
Linux and macOS (amd64/arm64), Windows (amd64).
git clone https://github.com/Kong/kuma-migrator.git && cd kuma-migrator
make build
# binary at ./dist/kuma-migrator
Full options: installation guide.
Everything above is the short version. Each page below goes deeper on one part of it.
| Page | What it covers |
|---|---|
| Installation | Homebrew, binaries, from source |
| CLI reference | Every command, flag, and the config file |
| Extracting from a control plane | CP-mode rules, output layout, Konnect, Universal vs Kubernetes format |
| Plan and migrate | Dry run, output layout, Gateway API placement |
| Choosing a target version | --to-latest and the checks that change with it |
| Applying the migrated manifests | Apply order, and cleaning up changed kinds |
| Migration paths and deprecations | Everything detected, fixed or flagged |
| MeshTrafficPermission modes | from[] vs rules[], and why it is not mechanical |
| MeshHTTPRoute and 3.0 routing | The 404 change, and the targetRef matrix for every policy |
| Transformation examples | Before-and-after YAML per scenario |
| Console output and reports | What you see, and what the report contains |
| Notes and caveats | Behaviour worth knowing before relying on the output |
Index: docs/.
19 releases since April 2026. Full history: Releases · compare view.
MeshHTTPRoute/MeshTCPRoute are no longer converted to Gateway API. Both are current policies on 2.x and 3.0 — Kuma compiles HTTPRoute/GRPCRoute into a MeshHTTPRoute — and Kuma has never reconciled Gateway API TCPRoute at all, so that output was dead on every version. They now pass through unchanged, and the 3.0 404 catch-all advisory fires on the MeshHTTPRoute itself.--to-latest v3 delegated-gateway guidance: Kuma 3.0 removes the kuma.io/gateway marking rather than renaming it, so the tool now points at traffic.kuma.io/exclude-inbound-ports and kuma.io/ignore. Top-level targetRef checks apply 3.0's uniform Mesh/Dataplane-only rule to every policy, and converted MeshGateway/MeshGatewayRoute objects now carry a delete-before-upgrading advisory.plan command — use migrate --dry-run instead, same flags and output. Also redesigned the pipeline diagram to mark apply as a manual step, not a command.HostnameGenerator being misclassified as "Skipped".gh attestation verify.--to-latest v3 gaps found auditing upstream kuma/kong-mesh: Dataplane BUILTIN gateway type, MeshOPA targetRef/DataSource fixes, MeshLoadBalancingStrategy crossZone, MeshHTTPRoute catch-all.Gateway.spec.gatewayClassName to resolve a real GatewayClass instead of a dead controllerName string; stopped emitting a dead built-in-gateway pair under v3.conf bodies are converted to the successor's schema instead of copied verbatim.--to-latest v2|v3 targeting, closed 2.13/2.14 deprecation gaps, fixed OPAPolicy handling and an extract data-loss bug.MeshIdentity/MeshTrust mtls advisory.migrate/plan output shows mesh name and file paths.MeshService names.--output-format flag, context-first output directory layout, per-environment skip lists.-k/--tls-skip-verify; stopped trusting readOnly from /_resources.