# Azure Activation Guide

Canonical page: https://www.kuudo.com/docs/cloud/azure-activation-guide/


This guide explains how to prepare Azure so the in-app **environment wizard** (Configuration → Credentials → Validation → Review & create) can create infrastructure successfully.

**Core idea:** every value you paste into the wizard is an **output of Azure setup**. Prepare Azure first (usually with the Azure CLI), then copy IDs and secrets into the product.

---

## Quick path

1. Sign in with your user account and select the correct subscription ([§ Sign in and select the subscription](#sign-in-and-select-the-subscription)).
2. Create or reuse an app registration / service principal and save **Client ID**, **Client Secret** (value), and **Tenant ID** ([§ Service principal](#create-or-reuse-a-service-principal)).
3. Grant the service principal **Contributor** on that subscription ([§ RBAC](#grant-rbac-on-the-subscription)).
4. Register **Microsoft.ContainerRegistry** and **Microsoft.App** ([§ Resource providers](#register-resource-providers)).
5. Log in as the service principal and confirm subscription access ([§ Verify the service principal](#verify-the-service-principal)).
6. Open the wizard: **Configuration** → **Credentials** → run **Validation** → **Review & create** ([§ Complete the wizard](#complete-the-wizard-in-the-app)).
7. If something fails, use [§ Common issues](#common-issues).

---

## Prerequisites

- Access to the target Azure subscription.
- Permission to assign RBAC (for example **Owner** or **User Access Administrator**) when granting the service principal access.
- [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) installed locally, or [Azure Cloud Shell](https://learn.microsoft.com/en-us/azure/cloud-shell/overview).

The CLI is recommended because portal labels and layout change more often than command-line flows.

---

## Field reference

The wizard matches Azure outputs like this:

| What you do in Azure                 | Output to copy                       | Wizard field                             |
| ------------------------------------ | ------------------------------------ | ---------------------------------------- |
| Microsoft Entra ID (tenant)          | Tenant ID                            | **Tenant ID (Directory ID)**             |
| Subscription                         | Subscription ID                      | **Subscription ID** (Configuration step) |
| App registration / service principal | Application (client) ID              | **Client ID (Application ID)**           |
| Certificates & secrets               | **Secret value** (not the secret ID) | **Client Secret**                        |
| Your choice of deploy location       | Region name, e.g. `eastus`           | **Region**                               |
| (your label only)                    | Any name                             | **Environment Name**                     |

**Subscription ID vs Tenant ID:** both look like GUIDs (for example `eb620971-347b-41f1-bb45-e9c8b4f5020d`), but they are different. **Subscription ID** belongs in **Configuration**; **Tenant ID** belongs in **Credentials**.

**Region:** use a valid Azure region identifier (lowercase, no spaces). List names for your subscription:

```bash
az account list-locations --query "[].name" -o tsv
```

---

## Prepare Azure with the CLI

Run the steps below as **your Azure user/admin** unless noted. Replace placeholders such as `<SUBSCRIPTION_ID>` and `<CLIENT_ID>` with your values.

### Sign in and select the subscription

```bash
az login
az account list --output table
az account set --subscription <SUBSCRIPTION_ID>
az account show --output json
```

From the JSON output, record:

- `subscription.id` → **Subscription ID**
- `tenantId` → **Tenant ID**

### Create or reuse a service principal

Reuse an existing app registration if you already have one.

**Option A — new service principal (quick setup):**

```bash
az ad sp create-for-rbac --name <APP_NAME>
```

Note `appId` (**Client ID**), `password` (**Client Secret**), and `tenant` (**Tenant ID**). Save the secret immediately; it is not shown again.

**Option B — portal:** create an app registration in Microsoft Entra ID, add a **client secret** under **Certificates & secrets**, and copy the **Value** column (not the Secret ID).

**Option C — new secret for an existing app:**

```bash
az ad app credential reset --id <CLIENT_ID> --append
```

Use `--append` when rotating so Azure adds a second credential instead of replacing existing credentials. In production, prefer adding a second secret, updating the wizard, verifying deployment, then removing the old secret.

Entra secrets **expire**. When one expires, create a new secret and update **Client Secret** in the wizard.

### Grant RBAC on the subscription

Validation needs the service principal to read the subscription; provisioning needs permissions to create resources (resource groups, Container Apps, registries, etc.). **Contributor** at subscription scope is the usual choice.

```bash
az login
az account set --subscription <SUBSCRIPTION_ID>

az role assignment create \
  --assignee <CLIENT_ID> \
  --role Contributor \
  --scope /subscriptions/<SUBSCRIPTION_ID>
```

Verify:

```bash
az role assignment list \
  --assignee <CLIENT_ID> \
  --scope /subscriptions/<SUBSCRIPTION_ID> \
  --output table
```

You should see **Contributor** for that service principal on the subscription.

For tighter least privilege, some organizations scope **Contributor** to a **resource group** instead of the whole subscription. That only works if all resources the worker creates stay inside that group.

### Register resource providers

Provisioning fails if the subscription is not registered for the services in use. These namespaces are required for the MCP deployment path described here:

- `Microsoft.ContainerRegistry`
- `Microsoft.App`

```bash
az account set --subscription <SUBSCRIPTION_ID>

az provider register --namespace Microsoft.ContainerRegistry --wait
az provider register --namespace Microsoft.App --wait
```

Verify (each should print `Registered`):

```bash
az provider show --namespace Microsoft.ContainerRegistry --query registrationState -o tsv
az provider show --namespace Microsoft.App --query registrationState -o tsv
```

Depending on what the worker provisions, you may also need:

```bash
az provider register --namespace Microsoft.OperationalInsights --wait
az provider register --namespace Microsoft.ManagedIdentity --wait
az provider register --namespace Microsoft.Network --wait
```

### Verify the service principal

This separates Azure misconfiguration from product issues.

```bash
az logout

az login --service-principal \
  --username <CLIENT_ID> \
  --password <CLIENT_SECRET_VALUE> \
  --tenant <TENANT_ID>

az account set --subscription <SUBSCRIPTION_ID>

az rest \
  --method get \
  --url "https://management.azure.com/subscriptions/<SUBSCRIPTION_ID>?api-version=2020-01-01"
```

If this returns subscription JSON, authentication and subscription access are working.

---

## Complete the wizard in the app

Use the [Field reference](#field-reference) for definitions.

### Configuration

- **Environment Name** — label in your app (for example `azure`).
- **Subscription ID** — Azure subscription GUID from [§ Sign in](#sign-in-and-select-the-subscription).

### Credentials

- **Tenant ID**, **Client ID**, **Client Secret** (secret **value**), **Region** — from Entra and the service principal ([§ Service principal](#create-or-reuse-a-service-principal), [§ Sign in](#sign-in-and-select-the-subscription)).

### Validation

Run validation in the UI. It should succeed when the secret is valid, tenant and subscription IDs are correct, and the service principal can read the subscription.

### Review & create

After validation succeeds, finish creating the environment.

---

## Common issues

| Symptom or error                                                                                         | Likely cause                                                             | What to do                                                                                                                    |
| -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| Tenant ID pasted into **Subscription ID** (or the reverse)                                               | Same GUID shape, wrong meaning                                           | Put subscription GUID in **Configuration**; tenant GUID in **Credentials** ([Field reference](#field-reference)).             |
| `AADSTS7000215 Invalid client secret provided`                                                           | Wrong secret, expired secret, or **Secret ID** used instead of **Value** | Create a new client secret; copy the **value**; update the wizard.                                                            |
| Validation OK but provisioning fails with insufficient access                                            | **Reader** only, or wrong scope                                          | Use **Contributor** (or equivalent) on the subscription or target resource group ([§ RBAC](#grant-rbac-on-the-subscription)). |
| `Microsoft.Resources/subscriptions/read` (or similar read denial)                                        | SP cannot read the subscription                                          | Assign **Reader** or **Contributor** on the correct subscription; confirm **Subscription ID**.                                |
| `roleAssignments/write` when running CLI                                                                 | Current user cannot assign RBAC                                          | Sign in as an admin or a user with **Owner** / **User Access Administrator** on the subscription.                             |
| Role assignment commands do nothing useful while logged in as the SP                                     | SP cannot grant itself roles                                             | Use your **user** account for `az role assignment create`.                                                                    |
| `The subscription is not registered to use namespace 'Microsoft.App'` or `'Microsoft.ContainerRegistry'` | Resource provider not registered                                         | `az provider register --namespace <NAMESPACE> --wait` ([§ Resource providers](#register-resource-providers)).                 |
| `The subscription is not registered to use namespace 'Microsoft.X'`                                      | Other provider missing                                                   | `az provider register --namespace Microsoft.X --wait`                                                                         |

## Official references

- [Create an Azure service principal with Azure CLI](https://learn.microsoft.com/en-us/cli/azure/azure-cli-sp-tutorial-1)
- [Azure resource providers and types](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-providers-and-types)
- [Azure built-in roles](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles)
- [Install the Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli)

---

## Appendix: Copy-paste activation script

The block below repeats [Prepare Azure with the CLI](#prepare-azure-with-the-cli) in one place for convenience. Replace placeholders before running.

```bash
# --- As your Azure user ---

az login
az account list --output table
az account set --subscription <SUBSCRIPTION_ID>

# RBAC (Contributor on subscription)
az role assignment create \
  --assignee <CLIENT_ID> \
  --role Contributor \
  --scope /subscriptions/<SUBSCRIPTION_ID>

az role assignment list \
  --assignee <CLIENT_ID> \
  --scope /subscriptions/<SUBSCRIPTION_ID> \
  --output table

# Required providers
az provider register --namespace Microsoft.ContainerRegistry --wait
az provider register --namespace Microsoft.App --wait

az provider show --namespace Microsoft.ContainerRegistry --query registrationState -o tsv
az provider show --namespace Microsoft.App --query registrationState -o tsv

# --- Test as the service principal ---

az logout

az login --service-principal \
  --username <CLIENT_ID> \
  --password <CLIENT_SECRET_VALUE> \
  --tenant <TENANT_ID>

az account set --subscription <SUBSCRIPTION_ID>

az rest \
  --method get \
  --url "https://management.azure.com/subscriptions/<SUBSCRIPTION_ID>?api-version=2020-01-01"
```

After this succeeds, fill the wizard using the [Field reference](#field-reference) and complete [§ Complete the wizard](#complete-the-wizard-in-the-app).

