Evaluate migration permissions (source + target)
Audience: operators of the published obs-migrate CLI (PyPI/uvx), using public docs and their real source + Elastic/Kibana — not a repo lab harness.
Goal: give the user confidence their credentials can perform every step before they invest in a migration. Separate non-mutating probes from checks that change target state, and be honest about what each proves.
Prerequisites (install)
These skills help operators of the published CLI (not a repo checkout).
If obs-migrate is missing or doctor is not Ready, follow
install-obs-migrate first — that skill owns PyPI/uvx/pip, extras, and
Python/uv gotchas. Do not invent alternate install commands here.
uvx --from 'elastic-observability-migration[all]' obs-migrate doctor
# After a persistent install, the same check is: obs-migrate doctor
Source/Elastic credentials: connect-to-o11y-source (and your env exports).
Mental model (state this to the user)
- The source (Grafana/Datadog) is read-only. The tool never writes back to the source. So the only source permission that matters is read/search/export of dashboards (and, for Datadog, monitors). If
connect-to-o11y-sourcesucceeded, source read is already proven. - The target (Elastic/Kibana) is where write permission matters. The migration needs an API key that can:
- create/update dashboards via the typed Dashboards API —
PUT /api/dashboards/{id}(defaultobs-migrate upload/migrate --uploadpath) - read saved objects / list dashboards —
obs-migrate cluster list-dashboards(Serverless uses_export) - manage data views —
GET/POST/DELETE /api/data_views/... - create alert rules (only if migrating alerts) —
POST /api/alerting/ruleandGET /api/alerting/rules/_find(creation fails closed unless it can inventory existing migrated rules) - read target indices for field validation — ES
_field_caps - delete migrated alert rules —
obs-migrate delete-rules(dry-run by default;--confirmto delete)
- create/update dashboards via the typed Dashboards API —
Source permission check (non-mutating)
Reading dashboards is the proof. (See the connect-to-o11y-source skill for full setup.)
export GRAFANA_URL="https://grafana.example.com" GRAFANA_USER="..." GRAFANA_PASS="..."
KIBANA_URL= obs-migrate migrate \
--source grafana --input-mode api \
--output-dir /tmp/perm-src --assets dashboards
- Pulled dashboards: source read permission is sufficient.
- 401/403: the source user/token lacks read access (or is wrong).
Note on Grafana alerts: Grafana alert artifacts are derived from dashboard JSON during migration, not fetched as a separate API asset. Do not treat --assets alerts as a distinct source permission probe for Grafana. For Datadog, monitor read is a real separate scope — --assets alerts with --source datadog exercises the Monitors API.
--assets takes exactly one value: dashboards, alerts, or all. It is not a comma list — to exercise both dashboard and monitor reads in one Datadog run use --assets all, not --assets dashboards,alerts.
Target permission checks — non-mutating first
These do not create or modify dashboards/rules. Run these to validate the Kibana API key safely:
Export your target endpoints/key first (any names work; this skill uses KIBANA_ENDPOINT, ELASTICSEARCH_ENDPOINT, KEY):
export KIBANA_ENDPOINT="https://...kb..." ELASTICSEARCH_ENDPOINT="https://...es..." KEY="<api-key>"
# 1. API key auth + serverless detection (also reveals the delete limitation below)
obs-migrate cluster detect-serverless --kibana-url "$KIBANA_ENDPOINT" --kibana-api-key "$KEY"
# 2. Saved-object READ (via _export on Serverless)
obs-migrate cluster list-dashboards --kibana-url "$KIBANA_ENDPOINT" --kibana-api-key "$KEY"
# 3. ES read for field validation
curl -sf -H "Authorization: ApiKey $KEY" "$ELASTICSEARCH_ENDPOINT/metrics-*/_field_caps?fields=*" >/dev/null && echo "ES read OK"
# 4. Alerting read (only if migrating alerts) — package-native, read-only:
# lists migrated rules (tagged obs-migration) and proves alerting-read access.
obs-migrate audit-rules --kibana-url "$KIBANA_ENDPOINT" --kibana-api-key "$KEY"
audit-rules is read-only by default (it only lists migrated rules; it disables nothing unless you pass --disable-enabled). On a target with no migrated rules yet it simply reports zero — that still proves the key can reach and read the Alerting API. (Raw equivalent if you prefer: curl -s -H "Authorization: ApiKey $KEY" "$KIBANA_ENDPOINT/api/alerting/_health".)
Custom-CA / self-signed targets: every obs-migrate command above (cluster ..., audit-rules, upload, verify-alert-rules) accepts the global TLS flags --ca-cert <bundle> (env OBS_MIGRATE_CA_CERT) and --insecure (env OBS_MIGRATE_INSECURE). If a probe fails with a TLS/CERTIFICATE_VERIFY_FAILED error rather than a 401/403, that's a trust problem, not a permission gap — add --ca-cert (keeps verification on; preferred) or, only with explicit user consent, --insecure. For the raw curl field-caps check, the analogous escapes are curl --cacert <bundle> or curl -k.
ensure-data-views creates/updates data views, so treat it as a mutating check:
# Data-view CREATE/UPDATE (changes target state — only run if you intend to create them)
obs-migrate cluster ensure-data-views \
--kibana-url "$KIBANA_ENDPOINT" --kibana-api-key "$KEY" \
--data-view-patterns "metrics-*,logs-*"
Target write proof — these CHANGE target state
Only run these when the user accepts that they create objects. State this explicitly before running.
# Dashboard write proof (creates/updates a dashboard via typed Dashboards API; does not self-clean).
# Prefer reviewing <their-output-dir>/dashboards/native/*.native.json, then:
obs-migrate upload \
--artifact-dir <their-output-dir>/dashboards \
--kibana-url "$KIBANA_ENDPOINT" --kibana-api-key "$KEY"
# Alert-rule write proof — SELF-CLEANING round trip (package-native).
# Creates the emitted rules DISABLED, confirms none came back enabled, then
# DELETES them (unless --keep-rules). Needs a comparison report from a prior
# alert-capable migration (e.g. <their-output-dir>/alerts/alert_comparison_results.json
# for Grafana, or <their-output-dir>/alerts/monitor_comparison_results.json for Datadog). --limit caps it.
obs-migrate verify-alert-rules \
--comparison <their-output-dir>/alerts/alert_comparison_results.json \
--kibana-url "$KIBANA_ENDPOINT" --kibana-api-key "$KEY" \
--limit 1
verify-alert-rules is the preferred alert write check because it cleans up after itself. If the user has no comparison report yet (no alert migration run), the alternative is obs-migrate migrate --source grafana --input-mode api --output-dir /tmp/perm-alerts --assets alerts --kibana-url "$KIBANA_ENDPOINT" --kibana-api-key "$KEY" --create-alert-rules, which creates rules disabled and tagged obs-migration but does not self-clean — afterward: obs-migrate audit-rules ... --disable-enabled to disable, then obs-migrate delete-rules --kibana-url ... --kibana-api-key ... (dry-run) and ... --confirm to delete. The dashboard upload proof also leaves a dashboard behind — delete it with obs-migrate cluster delete-dashboards if it was only a test.
Serverless caveats (call these out)
- Saved-object
GET/_find/directDELETEare blocked on Serverless. Listing uses_export; "delete" rewrites objects to[DELETED]placeholders via re-import. So a user can lack nothing and still be unable to hard-delete — that is the platform, not a permission gap. - Migration-created rules are disabled by default and tagged
obs-migration.
Do NOT
- Do not present a state-changing command (
upload,ensure-data-views, rule creation) as a "safe permission check" without saying it mutates the target. - Do not invent flags, endpoints, or privilege names.
obs-migrate doctorchecks local tool resolution, not credentials/permissions. - Do not claim Grafana
--assets alertsproves a separate source alert-read permission. - Do not point package users at
scripts/...files orexamples/...YAML for the alert checks — useobs-migrate verify-alert-rules/obs-migrate audit-rules(shipped) and the user's own migrated output instead. - Do not describe
audit-rules(without--disable-enabled) as mutating — it only reads.
See also
install-obs-migrate— install/doctor when the CLI is missing or not Ready.connect-to-o11y-sourceskill — source setup and reachability.obs-migrate verify-alert-rules --helpandobs-migrate audit-rules --help— the self-cleaning alert write proof and the read-only rule audit (shipped in the package).obs-migrate cluster --helpandobs-migrate migrate --help— authoritative target/alerting flags for the installed version.https://github.com/elastic/observability-migration-platform/blob/main/docs/command-contract.md—clusteractions and the alert upload flow (online docs / repo).