Re-home agents to a new API base URL through the agent/config response (backend move or per-tenant EU->US region move) - the lesson from the 2026-07-18 WEU->GWC cutover, where the compiled-in API hostname hard-cut every in-flight agent (no DNS indirection possible: mTLS breaks behind a proxy, Flex custom-domain TLS is broken). Backend (ConfigVersion 33): - AdminConfiguration.AgentMigrateApiBaseUrl (global) + AgentMigrateTenantOverridesJson (tenantId->URL; empty value pins a tenant against the global target; override wins) - GetAgentConfigFunction.ResolveMigrateTarget serves the validated target; AgentMigrateServed / AgentMigrateRejected warnings as delivery evidence - TableConfigRepository Store+Map; admin portal Global Settings round-trip Agent (kill-switch-mirrored hardening): - Shared AgentEndpointMigrationRules: https-only, *.azurewebsites.net on a label boundary, no path/port/userinfo - enforced on BOTH sides - Live fetch only: RemoteConfigService cache strips the field on write AND read; EndpointMigration.ResolveTarget re-checks the fetch outcome - AgentRuntimeConfig.Resolve returns before merge/integrity/bootstrap cleanup on a pending migration (no spurious IntegrityCheckFailed against a stale migration stub), Program.RunAgent rebuilds Phase 3+4 against the new URL - single hop, kill signal wins before and after the hop Tests: AgentEndpointMigrationTests (backend rules + resolution), EndpointMigrationTests + cache-hardening strip (agent). Full suites green (Functions 2992, Agent Core 1822, vitest 557, tsc silent). Doc: docs/agent/endpoint-migration.md Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4.9 KiB
type, title, description, resource, tags, timestamp
| type | title | description | resource | tags | timestamp | |||||
|---|---|---|---|---|---|---|---|---|---|---|
| Concept | Agent Endpoint Migration — Config-Channel Re-Home | How the backend re-homes agents to a new API base URL (backend move or per-tenant region move) via MigrateToApiBaseUrl on the agent config response, and why HTTP redirects were rejected. | /src/Agent/AutopilotMonitor.Agent.V2.Core/Configuration/EndpointMigration.cs |
|
2026-07-18T00:00:00+02:00 |
Problem
The agent's API base URL is compiled into the binary (Constants.ApiBaseUrl). No DNS/domain
indirection is possible in front of the API: mTLS client-cert auth does not survive a reverse
proxy (Front Door), and Flex Consumption custom-domain TLS is broken. A backend move (like the
2026-07-18 WEU→GWC subscription migration) therefore hard-cuts every deployed agent still
pointing at the old hostname. In-flight agents self-terminate safely (local MaxLifetime watchdog
- CleanupService), but their sessions are lost and a per-tenant region move (EU→US) has no mechanism at all.
Mechanism
AgentConfigResponse.MigrateToApiBaseUrl — served on GET /api/agent/config (incl. the
bootstrap wrapper), the same control channel as the kill switch, fetched at every agent
process start.
Agent flow (Program.RunAgent, Phase 4):
- Config fetched from the compiled-in (old) base URL.
- Kill-switch check runs FIRST — kill wins over migrate.
AgentRuntimeConfig.Resolvedetects the migration signal directly after the fetch and returns early, BEFORE merge / binary-integrity / bootstrap-cleanup — none of those side effects may run against a config from the backend being abandoned (a migration stub may advertise stale agent hashes; a spuriousIntegrityCheckFailed+ force-update would be harmful).Program.RunAgentswapsAgentConfiguration.ApiBaseUrl, disposes the old client stack, rebuilds Phase 3 (auth clients) and re-runs Phase 4 against the new URL —allowEndpointMigration: false, so the new backend's config cannot chain a second hop.- Kill-switch check runs again on the NEW backend's config; startup continues normally (Phase 5+ builds mTLS/telemetry clients from the updated base URL).
Hardening (mirrors the kill switch)
- Live fetch only — the on-disk config cache strips
MigrateToApiBaseUrlon write AND read (RemoteConfigService.CacheConfig/LoadCachedConfig);EndpointMigration.ResolveTargetre-checksLastFetchOutcome == Succeededas defence-in-depth. A planted cache file can never re-home an agent. - Allowlist validated on BOTH sides —
AgentEndpointMigrationRules(Shared, single source): https only, host must end in.azurewebsites.neton a label boundary, no path/query/userinfo/port. The backend refuses to serve an invalid admin value (AgentMigrateRejectedwarning); the agent refuses to honour one even if the backend was compromised. - One hop, no loops — second Resolve pass never migrates; a target equal to the current base URL is a no-op (steady state during the migration window).
Operation
Global admin settings (AdminConfiguration, admin portal → Global Settings):
AgentMigrateApiBaseUrl— global target, set on the backend being abandoned; clear it after the migration window.AgentMigrateTenantOverridesJson— JSON objecttenantId → URLfor per-tenant moves. An entry with an empty string pins that tenant against the global target (staged rollout). Overrides win over the global value.
Delivery evidence: every served target logs AgentMigrateServed (Warning — reaches App
Insights) with tenant, serial, agent version and target. Agent-side, the re-home is logged as
Endpoint migration: backend re-homed this agent from … to ….
Reach limitation: agents that cannot complete an authenticated config fetch (e.g. cert-broken
devices) never see the signal — they fall back to the local MaxLifetime/emergency-break
lifecycle. During a migration window the old backend must keep running as a serving stub;
keeping the old *.azurewebsites.net name parked afterwards also prevents hostname
re-registration by third parties while stragglers drain.
Citations
src/Shared/AutopilotMonitor.Shared/Services/AgentEndpointMigrationRules.cs— shared validation rulessrc/Shared/AutopilotMonitor.Shared/Models/Config/AgentConfigResponse.cs— wire fieldsrc/Backend/AutopilotMonitor.Functions/Functions/Config/GetAgentConfigFunction.cs—ResolveMigrateTarget+ serving (ConfigVersion 33)src/Agent/AutopilotMonitor.Agent.V2.Core/Configuration/EndpointMigration.cs— agent-side evaluationsrc/Agent/AutopilotMonitor.Agent.V2/Runtime/AgentRuntimeConfig.cs— early return before merge/integritysrc/Agent/AutopilotMonitor.Agent.V2/Program.cs— one-hop rebuild inRunAgent- Tests:
AgentEndpointMigrationTests(backend),EndpointMigrationTests+RemoteConfigServiceCacheHardeningTests(agent)