|
| 1 | +--- |
| 2 | +title: Service Connections |
| 3 | +description: Create the Azure Resource Manager service connections needed for ado-aw pipelines |
| 4 | +sidebar: |
| 5 | + order: 2 |
| 6 | +--- |
| 7 | + |
| 8 | +import { Tabs, TabItem, Steps } from '@astrojs/starlight/components'; |
| 9 | + |
| 10 | +`ado-aw` pipelines use **Azure Resource Manager (ARM) service connections** to mint Azure DevOps-scoped tokens at runtime. These tokens grant the pipeline controlled access to ADO APIs — separately for the agent (read) and the executor (write). |
| 11 | + |
| 12 | +## Why service connections? |
| 13 | + |
| 14 | +The compiled pipeline uses the `AzureCLI@2` task to call `az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798` — this mints a short-lived ADO token scoped to the service connection's identity. This keeps credentials short-lived and auditable, and avoids storing long-lived PATs. |
| 15 | + |
| 16 | +| Connection | Used by | Purpose | |
| 17 | +|------------|---------|---------| |
| 18 | +| **Write** (required for safe outputs) | Stage 3 — SafeOutputs executor | Create PRs, work items, wiki pages, etc. | |
| 19 | +| **Read** (optional) | Stage 1 — Agent | Query ADO APIs (work items, repos, builds) | |
| 20 | + |
| 21 | +:::tip[Reusing existing connections] |
| 22 | +If your project already has ARM service connections with appropriate ADO permissions, you can reuse them — just reference their names in `permissions.write` / `permissions.read` in your agent file. Skip to [Verify your connection works](#verify-your-connection-works) to confirm they're suitable. |
| 23 | +::: |
| 24 | + |
| 25 | +--- |
| 26 | + |
| 27 | +## Create the write service connection |
| 28 | + |
| 29 | +This is the minimum required connection. It powers Stage 3 safe-output execution. |
| 30 | + |
| 31 | +<Steps> |
| 32 | +1. Go to your **Azure DevOps Project → Project Settings → Service connections** |
| 33 | +2. Click **New service connection → Azure Resource Manager** |
| 34 | +3. Choose your authentication method: |
| 35 | + |
| 36 | + <Tabs> |
| 37 | + <TabItem label="Service principal (automatic)"> |
| 38 | + The simplest option — Azure DevOps creates the app registration and credentials for you. |
| 39 | + |
| 40 | + - Select **Service principal (automatic)** |
| 41 | + - Choose an Azure subscription (the identity needs at least **Reader** on the subscription — this is only used for `az` login, not for ADO operations) |
| 42 | + - Scope to a resource group if preferred |
| 43 | + - Name the connection (e.g. `ado-aw-write`) — this is the value you'll use in `permissions.write` |
| 44 | + - Click **Save** |
| 45 | + |
| 46 | + Azure DevOps creates an Entra ID app registration and configures everything automatically. |
| 47 | + </TabItem> |
| 48 | + <TabItem label="Workload Identity Federation (manual)"> |
| 49 | + Secretless — no client secrets to rotate. Use this if your organization requires manual control. |
| 50 | + |
| 51 | + - Create an [App Registration in Entra ID](https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps) (note the Application ID and Tenant ID) |
| 52 | + - In ADO, select **Workload Identity federation (manual)** |
| 53 | + - Fill in the Subscription ID, Service Principal Id (Application ID), and Tenant ID |
| 54 | + - Name the connection (e.g. `ado-aw-write`) |
| 55 | + - Click **Verify and save** |
| 56 | + - Copy the generated **Issuer** and **Subject identifier** from the connection details |
| 57 | + - Back in Azure Portal → App Registration → **Certificates & secrets → Federated credentials** → **Add credential** with the Issuer and Subject values |
| 58 | + </TabItem> |
| 59 | + <TabItem label="Service principal with secret (manual)"> |
| 60 | + Use if your organization doesn't support Workload Identity Federation or automatic provisioning. |
| 61 | + |
| 62 | + - Create an [App Registration in Entra ID](https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps) (note the Application ID and Tenant ID) |
| 63 | + - In the App Registration → **Certificates & secrets** → **New client secret** (copy the value) |
| 64 | + - In ADO, select **Service principal (manual)** |
| 65 | + - Fill in the Subscription ID, Service Principal Id, Service principal key (secret), and Tenant ID |
| 66 | + - Name the connection (e.g. `ado-aw-write`) |
| 67 | + - Click **Verify and save** |
| 68 | + |
| 69 | + :::caution[Secret rotation] |
| 70 | + Client secrets expire. Set a reminder to rotate before expiry, or prefer Workload Identity Federation to avoid this overhead. |
| 71 | + ::: |
| 72 | + </TabItem> |
| 73 | + </Tabs> |
| 74 | + |
| 75 | +4. **Grant ADO permissions** to the service principal. The identity behind the connection needs permission to perform write operations in Azure DevOps: |
| 76 | + - Go to **Azure DevOps Organization Settings → Users** |
| 77 | + - Add the service principal (search by its app registration name) |
| 78 | + - Set access level to **Basic** |
| 79 | + - Add it to a project-level group with the permissions your safe outputs need — **Contributors** is sufficient for most use cases (PRs, work items, branches, tags, wiki pages) |
| 80 | + |
| 81 | +5. **Reference it** in your agent front matter: |
| 82 | + |
| 83 | + ```yaml |
| 84 | + permissions: |
| 85 | + write: ado-aw-write # ← name of the service connection you created |
| 86 | + ``` |
| 87 | +</Steps> |
| 88 | +
|
| 89 | +:::caution[Least privilege] |
| 90 | +Only grant the permissions your workflows actually use. If your agents only create work item comments, you don't need full Contributor access. See [Safe Outputs reference](/ado-aw/reference/safe-outputs/) for what each tool requires. |
| 91 | +::: |
| 92 | +
|
| 93 | +:::note[Compile-time safety check] |
| 94 | +If you configure safe outputs that require write access (e.g. `create-pull-request`, `create-work-item`, `add-pr-comment`) but omit `permissions.write`, compilation will fail with a clear error. This ensures write operations always have an explicitly configured credential. |
| 95 | +::: |
| 96 | + |
| 97 | +--- |
| 98 | + |
| 99 | +## Create the read service connection (optional) |
| 100 | + |
| 101 | +If your agent needs to query Azure DevOps APIs (e.g. read work items, list PRs, fetch build results), create a second connection with **read-only** ADO permissions. |
| 102 | + |
| 103 | +Follow the same steps as above, but: |
| 104 | + |
| 105 | +- Name the connection `ado-aw-read` (or similar) |
| 106 | +- In ADO, grant the service principal **Readers** group access (or a custom group with only read permissions) |
| 107 | + |
| 108 | +Then reference both in your agent file: |
| 109 | + |
| 110 | +```yaml |
| 111 | +permissions: |
| 112 | + read: ado-aw-read |
| 113 | + write: ado-aw-write |
| 114 | +``` |
| 115 | + |
| 116 | +:::note[Why separate connections?] |
| 117 | +Separation ensures the Stage 1 agent — which runs untrusted AI-generated code inside an AWF sandbox — can never perform write operations, even if prompt-injected. The write token only exists in Stage 3, after detection has passed. |
| 118 | +::: |
| 119 | + |
| 120 | +### Permission combinations |
| 121 | + |
| 122 | +| Configuration | Agent can read ADO? | Safe outputs can write? | |
| 123 | +|---|---|---| |
| 124 | +| Both `read` + `write` | ✅ | ✅ | |
| 125 | +| Only `read` | ✅ | ❌ | |
| 126 | +| Only `write` | ❌ | ✅ | |
| 127 | +| Neither (default) | ❌ | ❌ | |
| 128 | + |
| 129 | +--- |
| 130 | + |
| 131 | +## Authorize the pipeline |
| 132 | + |
| 133 | +On the first run, Azure DevOps will prompt you to authorize the pipeline to use the service connections. You can also pre-authorize: |
| 134 | + |
| 135 | +<Steps> |
| 136 | +1. In the service connection's settings, go to **Security** |
| 137 | +2. Under **Pipeline permissions**, click **+** and add your ado-aw pipeline (or grant access to all pipelines in the project) |
| 138 | +</Steps> |
| 139 | + |
| 140 | +--- |
| 141 | + |
| 142 | +## Verify your connection works |
| 143 | + |
| 144 | +To confirm your service connection can mint ADO tokens, create a test pipeline: |
| 145 | + |
| 146 | +```yaml |
| 147 | +trigger: none |
| 148 | +
|
| 149 | +pool: |
| 150 | + vmImage: ubuntu-latest |
| 151 | +
|
| 152 | +steps: |
| 153 | + - task: AzureCLI@2 |
| 154 | + displayName: "Test ADO token mint" |
| 155 | + inputs: |
| 156 | + azureSubscription: 'ado-aw-write' # your connection name |
| 157 | + scriptType: 'bash' |
| 158 | + scriptLocation: 'inlineScript' |
| 159 | + inlineScript: | |
| 160 | + TOKEN=$(az account get-access-token \ |
| 161 | + --resource 499b84ac-1321-427f-aa17-267ca6975798 \ |
| 162 | + --query accessToken -o tsv) |
| 163 | + if [ -n "$TOKEN" ]; then |
| 164 | + echo "✅ Successfully minted ADO token (${#TOKEN} chars)" |
| 165 | + else |
| 166 | + echo "❌ Failed to mint ADO token" |
| 167 | + exit 1 |
| 168 | + fi |
| 169 | +``` |
| 170 | + |
| 171 | +If this pipeline succeeds, your connection is correctly configured for `ado-aw`. |
| 172 | + |
| 173 | +--- |
| 174 | + |
| 175 | +## Troubleshooting |
| 176 | + |
| 177 | +| Symptom | Likely cause | |
| 178 | +|---------|-------------| |
| 179 | +| `AzureCLI@2` fails with "service connection not found" | The pipeline isn't authorized to use the connection — check pipeline permissions in the connection's Security tab | |
| 180 | +| Token mints but safe outputs return 401/403 | The service principal doesn't have sufficient ADO permissions — verify its group membership in ADO Organization Settings → Users | |
| 181 | +| "AADSTS700024: Client assertion is not within its valid time range" | Federated credential issuer/subject mismatch — regenerate in the App Registration | |
| 182 | +| Compilation error: "require write access to ADO, but no write service connection is configured" | Your agent uses write-requiring safe outputs but is missing `permissions.write` in front matter | |
0 commit comments