# Deploy Agent Mission Control

Agent Mission Control (AMC) is delivered as an Azure **managed application**. When you deploy it, Azure
creates a dedicated, single-tenant instance of the product inside your own subscription: your data never
leaves it.

This article walks through a complete deployment: preparing Microsoft Entra ID, filling in the
deployment form, completing the post-deployment configuration, and verifying the result.

**Applies to:** release **2026.10.16** (October 2026). Release versions use the date-based format `YYYY.MM.DD`; this release carries the same code as the earlier `0.0.25` build.

**Time required:** about 15 minutes of your attention, plus roughly 25 minutes of unattended
deployment time.

> [!NOTE]
> Two of the required configuration steps can only be completed **after** the deployment finishes,
> because they need a value that Azure generates during it — the instance's URL. Plan to return to the
> Azure portal once the deployment reports success: the application cannot be signed in to until you do.

## Before you begin

### Permissions

| Where | What you need | Used for |
|---|---|---|
| Target Azure subscription | **Owner**, or **Contributor** on the resource group where the instance is created | Creating the managed application |
| Microsoft Entra ID | **Application Developer** or higher (or an existing registration prepared for you) | Registering the sign-in application |

If your organization separates these duties, note that the Entra work (Step 1 and Step 3) can be
delegated to a directory administrator. Only Step 2 requires subscription permissions.

### Resource providers

The deployment fails early with a `MissingSubscriptionRegistration` error if any of these providers is
not registered in the target subscription. Most subscriptions already have them.

`Microsoft.Solutions` · `Microsoft.App` · `Microsoft.ContainerInstance` · `Microsoft.Sql` ·
`Microsoft.Cache` · `Microsoft.KeyVault` · `Microsoft.ServiceBus` ·
`Microsoft.OperationalInsights` · `Microsoft.Insights` · `Microsoft.Storage` · `Microsoft.Network` ·
`Microsoft.ManagedIdentity` · `Microsoft.Security`

One more provider, `Microsoft.EventGrid`, is not used by the deployment itself but by the malware
scanning of uploaded files (Microsoft Defender for Storage), which creates an Event Grid system topic
next to the file storage account. The deployment succeeds without it; scanning does not work. Register
it before you deploy, and read the [known issue](#known-issue-malware-scanning-of-uploaded-files)
below.

To register one:

```azurecli
az provider register --namespace Microsoft.ContainerInstance
```

### Choosing a region

Pick a region that supports **Azure Container Apps**, **Azure SQL Database** and
**Azure Managed Redis**. The last is the most restricted of the three, so verify it first. This release
has been validated in **West US 2**.

> [!NOTE]
> The instance hosts no email infrastructure. Notification email is sent through each tenant's own
> SMTP service, which an administrator connects after deployment ([Step 6](#step-6-connect-email)).
> Where email data is stored and processed is therefore decided by that service, not by the region
> you choose here.

### What gets created

Everything below is created inside a **managed resource group** that Azure creates alongside the
instance. You can view these resources, but the group is locked for writes — the application owns its
own infrastructure.

| Component | Notes |
|---|---|
| 8 container apps | `api`, `client`, `streaming`, `run-executor`, and four background workers |
| Container Apps environment | VNet-injected; only `client` has a public ingress |
| Azure SQL Database | Standard S1 (20 DTU), private endpoint |
| Azure Managed Redis | Balanced B1, TLS 1.2, no public access |
| Key Vault | Purge protection enabled, private endpoint |
| Service Bus namespace | One queue and one topic |
| Log Analytics workspace | Application and platform logs |
| 2 storage accounts | One for the deployment's own files, one for files users and agents upload (HITL attachments, run artifacts). The second is configured for **Microsoft Defender for Storage** on-upload malware scanning; a file is released only after a clean verdict. See the known issue below |
| Virtual network, 5 private endpoints, 8 managed identities | Supporting infrastructure |

#### Known issue: malware scanning of uploaded files

In release 2026.10.16, on-upload malware scanning may not activate on a managed instance even though
the deployment reports success: the setting is written, but Defender's own follow-up (its scanner role
and Event Grid topic inside the managed resource group) does not always complete, and the setting then
reads back as disabled. On an affected instance every uploaded file stays in **Scanning…** and cannot be
opened or downloaded; human-in-the-loop requests, runs and everything else work normally. We have seen
this on upgraded instances and have not yet verified a fresh installation either way.

If you hit it, contact the publisher with the instance's name and managed resource group: re-enabling
scanning is done on our side, and the fix for the deployment template is tracked. Registering
`Microsoft.EventGrid` beforehand is a prerequisite for the fix, not a fix by itself.

> [!NOTE]
> As the publisher, we receive **Owner** access to the managed resource group so we can support and
> upgrade the instance. We have no access to your subscription outside that group. You can review the
> exact grant on the managed application's **Authorizations** blade at any time.

## Step 1: Register the sign-in application in Microsoft Entra ID

AMC signs your users in with your own Entra directory. It never stores passwords and never sees your
users' Entra tokens beyond the sign-in exchange.

You can create this registration in advance — recommended — or create it inline from the deployment
form in Step 2. Doing it in advance is easier, because the form's inline path does not let you set
every option.

1. In the Azure portal, go to **Microsoft Entra ID** > **App registrations** > **New registration**.
2. Enter a name, for example `Agent Mission Control`.
3. Under **Supported account types**, select **Accounts in this organizational directory only
   (single tenant)**.

   > [!IMPORTANT]
   > The portal preselects a multi-tenant option. Change it. AMC is a single-organization application,
   > and a multi-tenant registration invites sign-in attempts from directories you do not control.

4. Leave **Redirect URI** empty for now and select **Register**. You will add the redirect URIs in
   Step 3, once the deployment has told you the instance's URL.
5. From the **Overview** page, copy the **Application (client) ID**. You need it in Step 2.

### Create a client secret

1. Go to **Certificates & secrets** > **Client secrets** > **New client secret**.
2. Enter a description and an expiry. We recommend 12 months.
3. Select **Add**, then copy the secret **Value** immediately — Entra shows it only once.

   > [!WARNING]
   > Record the expiry date in your own calendar. When the secret expires, users can no longer sign
   > in, and the rotation procedure is not yet published — see
   > [Rotating the client secret](#rotating-the-client-secret).

### Add the `email` optional claim

AMC identifies users by their Entra object ID and displays their email address. Work accounts do not
receive an `email` claim by default.

1. Go to **Token configuration** > **Add optional claim**.
2. Select **ID**, then select **email**, then **Add**.

If you skip this step, users are still created and can sign in, but their display email is derived from
their user principal name, which is not always their real address.

## Step 2: Deploy the managed application

1. In the Azure portal, open the AMC offer and select **Create**.
2. Complete the wizard using the tables below.
3. On the **Review + create** tab, select **Create**.

### Basics

| Field | Guidance |
|---|---|
| Subscription | The subscription that will own and pay for the instance |
| Resource group | Where the managed application *object* lives. This is not where the resources go |
| Region | See [Choosing a region](#choosing-a-region) |
| Application name | A name for this instance, for example `amc-production` |
| Managed resource group | **Accept the generated name.** See the warning below |

> [!WARNING]
> Do not reuse a managed resource group name from a previous deployment, even a deleted one. Resource
> names are derived from it, and a deleted Key Vault is retained in a recoverable state for up to 90
> days — a reused name collides with your own earlier deployment and the new deployment fails.

### Identity & Tenant

| Field | Required | Guidance |
|---|---|---|
| Tenant name | Yes | The display name of your organization inside AMC, for example `Contoso, Ltd.` |
| Sign-in application | Yes | Select **Select existing** and choose the registration from Step 1 |
| Client secret | Yes | The secret value from Step 1 |
| Super Admin Entra object ID | No | See [Choosing how to claim the Super Admin role](#choosing-how-to-claim-the-super-admin-role) |
| Super Admin email | No | Display cross-check only; ignored if you leave the object ID blank |
| Sign-in directory (tenant) ID override | No | Under **Advanced**. Leave blank unless your users sign in from a different Entra directory than the one that owns this subscription |

> [!NOTE]
> The application picker is labelled **service principal** and lists every service principal in your
> directory, including Microsoft's own first-party applications. Choose the one that corresponds to
> your app registration from Step 1 — matching on the **Application (client) ID** is the reliable way
> to be sure. If you choose **Create new** instead, the portal registers a new application inline;
> remember to set its account type to single tenant, and you will need to create its client secret in
> the blade the portal opens for you.

### Choosing how to claim the Super Admin role

Every installation needs one first administrator. There are two ways to establish it, and you choose by
either filling in the Super Admin object ID or leaving it blank.

| Approach | How it works | When to use it |
|---|---|---|
| **Nominate a user** — enter their Entra object ID | That person becomes Super Admin automatically the first time they sign in | You already know who administers AMC |
| **Use a one-time setup code** — leave both fields blank | The deployment produces a setup code among its outputs. The application asks for it at first sign-in, and whoever enters it becomes Super Admin | You do not yet know the administrator, or a different person will deploy than will administer |

> [!IMPORTANT]
> The setup code is a credential, and anyone who can read the deployment's outputs can read it. **Claim
> the role promptly after deployment.** The code stops working the moment the role is assigned — the
> stored secret is deleted at that point, and it is never reissued, so the copy left in the deployment
> outputs becomes inert. Until you claim it, it is live: prefer nominating a Super Admin by object ID if
> you can, which issues no code at all.

### Start the deployment

1. Select **Review + create**. The portal validates your entries and reports any field it cannot accept.
2. Select **Create**.

Deployment takes about 25 minutes. Most of that time goes to the database, the cache and the Container
Apps environment; the application containers start last, after a one-time setup task has applied the
database schema, seeded your tenant and created the instance's signing key.

You can close the portal — the deployment continues without you. To follow its progress, open the
resource group you selected and select **Deployments**, or watch the managed application's **Overview**
blade.

When the provisioning state reaches **Succeeded**, continue with Step 3.

> [!NOTE]
> A successful deployment is not yet a usable instance: sign-in fails until you complete Step 3. This is
> expected, not a fault.

If the deployment fails, there is nothing to repair in place — delete the managed application, resolve
the cause (see [Troubleshooting](#troubleshooting)), and deploy again with a **new** managed resource
group name.

## Step 3: Register the redirect URIs

The deployment cannot know the instance's URL in advance, so this step happens afterwards.

1. When the deployment reports success, open the managed application and select
   **Settings** > **Parameters and Outputs**.
2. Copy the values of **clientUrl** and **entraRedirectUri**.

   You can also read them with the Azure CLI:

   ```azurecli
   az managedapp show --resource-group <group> --name <instance> \
     --query "properties.outputs.{clientUrl:clientUrl.value, redirect:entraRedirectUri.value}"
   ```

3. Go back to your app registration from Step 1 and select **Authentication**.
4. Under **Platform configurations**, select **Add a platform** > **Web** (or edit the existing Web
   platform).
5. Add **both** URIs:

   | URI | Purpose |
   |---|---|
   | `https://client.<domain>/api/auth/callback` — the `entraRedirectUri` output | Signing in |
   | `https://client.<domain>` — the `clientUrl` output | Signing out |

6. Select **Save**.

> [!IMPORTANT]
> Register both. Entra validates the sign-out destination against this same list, so an instance with
> only the first URI signs users in correctly and then fails to sign them out.

## Step 4: First sign-in

1. Browse to the **clientUrl** value.
2. Sign in with an Entra account from your directory.

What happens next depends on the choice you made in Step 2:

- **You nominated a Super Admin.** When that person signs in, the role is assigned automatically.
  Other users can sign in too, but they hold no permissions until an administrator grants them.
- **You left the fields blank.** The application presents a **Finish setting up this installation**
  prompt asking for the one-time setup code. Read the **superAdminBootstrapCode** output from the
  **Parameters and Outputs** blade, or:

  ```azurecli
  az managedapp show --resource-group <group> --name <instance> \
    --query "properties.outputs.superAdminBootstrapCode.value" -o tsv
  ```

  Enter it and select **Claim Super Admin**. The role is granted immediately and the code is **destroyed**:
  the deployment's copy of it stops working, and the stored secret is deleted. Claiming it again is not
  possible, and neither is claiming it after you later remove that administrator. An installation that ends
  up with no Super Admin is recovered with the publisher's help: a redeployment into the same managed
  resource group issues no new code, and a new deployment starts with an empty database.

## Step 5: Verify the deployment

| Check | Where | Expected |
|---|---|---|
| Deployment succeeded | Managed application > **Overview** | Provisioning state **Succeeded** |
| Post-deployment tasks completed | **Parameters and Outputs** > `postdeployStatus` | `migrationApplied`, `tenantSeeded`, `signingKeyCreated` all `true`, and `usersCreated` greater than zero |
| Application responds | `clientUrl` in a browser | The sign-in screen, not an error page |
| Sign-in works | Sign in with an Entra account | You reach the application |
| Administrator established | Your profile inside AMC | Your account holds **Super Admin** |
| Release version | **Settings → System** | Shows the release you installed (for example `2026.10.16`); a Super Admin also sees the update section there |

## Step 6: Connect email

AMC sends no email until a tenant connects its own SMTP service. Each AMC tenant has its own
settings, in **Settings → Notifications**. A Tenant Admin configures their own tenant, and a Super
Admin can configure any tenant by signing in to it. Until a tenant is configured, its email
notifications are recorded as `skipped` and its administrators see an "email off" banner. Everything
else in the application works without email.

- **Presets:** Exchange Online (OAuth), and Other SMTP server (any SMTP service with a username and password, SendGrid included; you enter the server). A preset fills in the server, port, TLS mode and
  login method; you enter the secret.
- **TLS is required:** STARTTLS on port 587 or implicit TLS on port 465. The server must have a public
  internet address.
- **The secret** (password, API key or client secret) is stored in the instance's Key Vault and is
  never shown again.
- **Send test email** sends a message to your own address and shows the result at once.

Step-by-step setup for each service, and how to read the connection status, are in the separate
article **Email: connecting your SMTP service**, delivered with this guide.

## Troubleshooting

| Symptom | Cause | Resolution |
|---|---|---|
| `AADSTS50011: The redirect URI ... does not match` at sign-in | The sign-in URI is missing or mistyped on the registration | Repeat Step 3. The URI must match the `entraRedirectUri` output exactly, including `/api/auth/callback` |
| Sign-in works, sign-out does nothing or errors | Only one redirect URI is registered | Add the `clientUrl` value as a second Web redirect URI (Step 3) |
| `AADSTS7000215: Invalid client secret provided` | The secret supplied at deployment does not belong to the selected application, or it has expired | Confirm the secret was created on the same registration whose client ID you supplied. See [Rotating the client secret](#rotating-the-client-secret) |
| The setup code is rejected | The code has already been claimed, or it was mistyped | An installation accepts the code **exactly once, permanently** — it is not reissued if the administrator is later removed. If an administrator already exists, no code is needed: sign in normally. To recover an installation with no Super Admin, contact the publisher; a redeployment issues no new code. Trailing spaces from a copy-paste are a common cause of a mistyped code |
| Deployment fails within the first minute | A resource provider is not registered, or the region does not offer one of the required services | See [Resource providers](#resource-providers) and [Choosing a region](#choosing-a-region) |
| Deployment fails with a Key Vault name conflict | The managed resource group name was reused from an earlier deployment | Redeploy with a new managed resource group name |
| Deployment fails on quota | The subscription lacks capacity for Container Apps, SQL or Redis in the chosen region | Request a quota increase, or choose another region |
| Uploaded files stay in **Scanning…** and cannot be opened | Malware scanning on the file storage account did not activate — see the [known issue](#known-issue-malware-scanning-of-uploaded-files) | Make sure `Microsoft.EventGrid` is registered in the subscription, then contact your publisher; re-enabling scanning is done on the publisher's side |

To collect diagnostics for a support request, include the managed application's name, its managed
resource group name, the deployment's correlation ID, and the `postdeployStatus` output.

## Operate and maintain

### Connecting a workflow or agent

Nothing about your orchestrator is configured while the instance is being created, and the deployment
form asks for nothing about it. You connect workflows and agents **inside the application**, after it is
running: each one is registered individually, with its own endpoint and its own credentials. Register as
many as you need, from more than one orchestrator if you want, and change them later without
redeploying.

A registration can authenticate to its endpoint in one of two ways:

- **A key you provide.** Nothing further is required — the key is stored in the instance's own Key
  Vault and presented on every call.
- **The instance's managed identity.** AMC calls the endpoint as itself, with no shared secret to
  distribute or rotate. Available for **Microsoft Foundry** endpoints, and it requires one grant on your
  side, described next. For an endpoint of your own it is **not available on a Marketplace installation**:
  the installation-wide list of endpoints allowed to receive the managed-identity token is empty and is
  not part of the deployment form, so such a registration is refused with "AMC's managed identity isn't
  set up for … Use an API key instead". Use a key for your own endpoints.

#### Granting the instance's identity access

If you choose managed-identity authentication, grant the instance's identities access to whatever the
registration points at. This is a **post-registration step**: do it once, after registering the
resource, and only for that authentication mode.

The instance runs under six identities and **all six** need the grant — different parts of the product
call your endpoint (registering and starting a run, executing and streaming it, polling for status, and
starting budget-released and scheduled runs). Granting only the first leaves scheduled or executed runs
failing with a permission error on an otherwise healthy instance. Collect all six principal IDs from the
managed application's **Parameters and Outputs** blade.

For a **Microsoft Foundry** endpoint, assign the built-in role **Foundry User**
(`53ca6127-db72-4b80-b1b0-d745d6d5456d`) to each of the six principal IDs, at the scope of the Foundry
**account** — not the individual project.

> [!IMPORTANT]
> Assign the role at the **account** scope. A grant made only on the project is not sufficient: AMC
> reads the project's agent catalog to confirm the resource exists and that it has access, and that read
> is refused by a project-only grant. The symptom is a registration that fails validation with a
> permissions error even though the endpoint and the workflow name are correct.

An endpoint of your own cannot use the managed identity on a Marketplace installation (see above), so
there is nothing to grant for it.

### Rotating the client secret

> [!NOTE]
> **Not yet verified — this procedure is still being confirmed and will be published here.** Until it
> is, set a reminder well before the expiry date you chose in Step 1 and contact us ahead of it; do not
> let the secret lapse, because users cannot sign in once it does.

### Deleting an instance

Deleting the managed application deletes its managed resource group and everything in it, including the
database. Export anything you need first.

Note that the Key Vault is retained in a recoverable state for up to 90 days after deletion, and that
its name derives from the managed resource group name — so a replacement deployment must use a new
managed resource group name.

## Reference

### Deployment outputs

| Output | Description |
|---|---|
| `clientUrl` | The instance's address, and its sign-out redirect URI |
| `entraRedirectUri` | The sign-in redirect URI to register in Entra |
| `postdeployStatus` | Post-deployment task results: `usersCreated`, `migrationApplied`, `tenantSeeded`, `signingKeyCreated`. Contains no secrets |
| `superAdminBootstrapCode` | The one-time setup code. Present only when you left the Super Admin fields blank |
| `instanceId` | The instance's identifier. It is not shown inside the application; read it here (or from the suffix of the managed resource group's resource names) and quote it when you ask the publisher to act on the instance |

The deployment also emits six managed-identity principal IDs — `apiPrincipalId`,
`streamingPrincipalId`, `statusSyncWorkerPrincipalId`, `budgetWorkerPrincipalId`,
`schedulerWorkerPrincipalId` and `runExecutorPrincipalId`. No step in this guide uses them. You need
them only later, and only if you connect a workflow that authenticates AMC by its managed identity — see
[Connecting a workflow or agent](#connecting-a-workflow-or-agent).

### Related content

- [Register an application with the Microsoft identity platform](https://learn.microsoft.com/entra/identity-platform/quickstart-register-app)
- [Optional claims in Microsoft Entra ID](https://learn.microsoft.com/entra/identity-platform/optional-claims)
- [Azure managed applications overview](https://learn.microsoft.com/azure/azure-resource-manager/managed-applications/overview)


## Upgrading an instance

An installed instance is upgraded **in place**: the release's deployment template is re-executed into
the instance's existing managed resource group. No resource is recreated, the database and its managed
identities are kept, and the application stays reachable throughout (a proven run takes 5 to 17
minutes). Nothing about this requires you to redeploy the managed application or to touch
`Microsoft.Solutions`.

### Email after an upgrade

Notification email is sent only through the SMTP service each tenant connects in **Settings → Notifications**
([Step 6](#step-6-connect-email)). After an upgrade from a release that did not yet have this setting, email
stays off for every tenant until a Tenant Admin or Super Admin of that tenant configures SMTP; nothing else in
the application is affected.

### The promotion gate

A release becomes available to instances only after the publisher **promotes** it — a reviewed,
human-approved step that moves the release pointer every instance's update check reads. Until then an
instance reports no update, however many releases have been built. Promotion is per release, not per
instance: once promoted, the same release is what every instance is offered.

### What the Update button does

In **Settings → System**, a Super Admin sees the promoted release and can press **Request update**. That
sends a signed update request to the publisher, which verifies it came from your instance and queues
it. The request then shows as `Requested`, moves to `InProgress` once the publisher's upgrade executor
has picked it up, and ends as `Applied <version>` or `Failed <reason>`. The executor runs in the
publisher's own subscription under a managed identity; it acts only on an instance's own verified
request and only for a release a human has already promoted.

### What the executor refuses, and why

The executor stops — and records a one-word reason — rather than guess. The reasons you may see:

| Reason | What it means | What happens next |
|---|---|---|
| `not_verified` | the request's signature did not verify | the request stays in the publisher's triage queue; contact your publisher |
| `not_promoted` | the version requested is no longer the promoted one | ask your publisher; a later promotion supersedes it |
| `already_at_or_above` | the instance already runs that version or newer | nothing to do |
| `instance_forbidden` | the publisher's executor is not exempt from the deny assignment on your managed resource group (Marketplace: the offer's authorizations do not include the publisher's operations group) | the publisher reviews the Marketplace authorizations; until then it upgrades by hand on your request |
| `instance_not_found` | the managed resource group the instance reported no longer exists | contact the publisher |
| `whatif_unexpected` | the upgrade would add or remove an Azure resource | the publisher reviews the change and runs it with explicit approval |
| `deployment_failed`, `health_gate_failed` | the deployment did not finish, or finished but a health check missed | the instance keeps running; the publisher investigates. There is **no automatic rollback** |

A refusal never changes the instance. Every outcome is visible in Settings → System, and every start
is logged on the publisher side.

### If you need the publisher to act

Tell your publisher the instance's identifier (the `instanceId` deployment output) and the version you
expect.
The publisher can start the same upgrade by hand, review the preview, and run it with any tolerance the
release needs.

### Rolling back

A rollback is the publisher starting the same procedure with the **previous** version and forcing it
past the "already newer" check. Images and configuration converge back; the database schema does not
roll back. That is why every release's schema changes are **expand/contract** (add first, remove one
release later): a release never drops or renames a column or table that the previous release still
uses, so the previous release keeps working on the newer schema. A release that deliberately drops
something carries that in its release notes — and such a release is never rolled back across the
drop; the way forward is the next release.
