Managed Identity Guide
This guide walks through configuring managed identities in Azure, adding them to your Azure DevOps organization, and using it to run the scanner - eliminating the need for Personal Access Tokens (PATs).
PAT vs Managed Identity
| Feature | PAT | Managed Identity |
|---|---|---|
| Token lifetime | Up to 1 year | ~1 hour (auto-refreshed) |
| Credential management | Manual rotation | Automatic |
| Stored secrets | Token stored in config/env | No secrets to manage |
Important: Microsoft recommends migrating away from PATs toward Microsoft Entra ID-based authentication for automation workloads.
Prerequisites
Before using Managed Identities with Azure DevOps:
- An Azure subscription with permissions to create managed identities (
Managed Identity Contributorrole or higher) - Project Collection Administrator (PCA) access in Azure DevOps - required to add the identity to your organization
- Your Azure DevOps organization must be connected to the same Microsoft Entra ID tenant where you create the managed identity (workaround exists but is not recommended)
-
The scanner must run on:
- An Azure resource that supports managed identities
- OR an Azure DevOps pipeline with access to an ARM service connection
Option 1: Azure DevOps Pipeline with Service Connection
The fastest path: Create an Azure Resource Manager service connection in your ADO project (managed identity with workload identity federation), and add the (automatically, or manually) created User Assigned Managed Identity (UAMI) to the users of your Azure DevOps' organization.
Step 1: Add the Managed Identity to Azure DevOps
- Go to your Azure DevOps organization
https://dev.azure.com/{your-org} - Click Organization settings (bottom-left gear icon)
- Select Users under the General section
- Click Add users
- In the search box, enter the display name of your managed identity (e.g.
Observes-scanner-identity) - Set Access level to Basic
- Under Add to projects, select the project(s) you want the scanner to access
- Click Add
Step 2: Run the Scanner
Use one of the following options to run the scanner: (A) Use the Observes extension; (B) Use the standalone scanner (from source / binary).
A) Using the Observes extension
Install the Observes extension from the Azure DevOps Marketplace. The task handles authentication, dependencies, and execution automatically.
The task supports two authentication methods selected via the authMethod input:
- ARM service connection (recommended for managed identity / WIF / service principal)
- PAT service connection (simpler setup, less recommended for production)
For this guide, we will use the ARM service connection method, so that we leverage WIF. The task automatically maps the ARM connection's auth scheme to the correct --auth-mode.
Using the Observes Extension with an ARM service connection
trigger: none
pool:
vmImage: ubuntu-latest
jobs:
- job: observesScan
timeoutInMinutes: 360
steps:
- task: observes@1
timeoutInMinutes: 360
inputs:
authMethod: arm
armServiceConnection: 'Observes-scanner-identity'
organization: 'my-ado-org'
jobId: $(Build.BuildId)
B) Using the standalone scanner (AzureCLI)
If you are using the scanner source code or binary directly rather than the extension, wrap it in an AzureCLI@2 task. The scanner picks up the active Azure CLI session automatically via DefaultAzureCredential, inheriting the authenticated CLI session from AzureCLI@2.
- task: AzureCLI@2
displayName: 'Run Observes Scanner'
inputs:
connectedServiceNameARM: 'Observes-scanner-identity'
scriptType: bash
scriptLocation: inlineScript
inlineScript: |
python scan.py -o my_org -j $(Build.BuildId) --auth-mode default
Once the managed identity is added to Azure DevOps, you can run the scanner via the Observes extension or an AzureCLI@2 task - no additional credential configuration needed. The scanner defaults to --auth-mode default, which uses DefaultAzureCredential to detect credentials automatically in this order. To force a specific method instead of relying on auto-detection, pass --auth-mode explicitly:
| Flag | Method | Use case |
|---|---|---|
--auth-mode pat -p <TOKEN> |
PAT | Local testing |
--auth-mode service-principal |
Entra App Registration | External CI/CD |
--auth-mode managed-identity |
Managed Identity | Azure DevOps CI/CD, Azure resources |
--auth-mode default |
Follows priority of Azure Default Credentials |
Option 2: Manual Managed Identity Setup
The other option is to manually configure a Managed Identity (user assigned or system assigned) that you can then either use from:
-
A pipeline with access to a service connection that you configure through the same mechanism described in option 1 (after creating the managed identity in the Azure portal, manually associate it with a service connection)
-
Running the script from an Azure service that supports managed identities (such as Azure Kubernetes Services clusters, Azure Functions, Azure VMs, Azure App Services pr Azure Container Instances)
Step 1: Create Managed Identity
You can only create User-Assigned Managed Identities (UAMIs) which you then assigned to a resource. Alternatively, you can enable System-Assigned Managed Identities on the resource you wish to use directly.
Ensure by the end of this step you have an Azure resource that supports managed identity to run the Observes scanner.
Step 2: Add the Identity to Azure DevOps
Important: Managed identities do not automatically appear in Azure DevOps. A Project Collection Administrator must explicitly add the identity.
Find the Correct Object ID
You need the Object (principal) ID of the managed identity - not the client ID.
az identity show --name Observes-scanner-identity --resource-group rg-Observes --query principalId -o tsv
Add via Azure DevOps Portal
Same steps:
- Go to your Azure DevOps organization
https://dev.azure.com/{your-org} - Click Organization settings (bottom-left gear icon)
- Select Users under the General section
- Click Add users
- In the search box, enter the display name of your managed identity (e.g.
Observes-scanner-identity) - Set Access level to Basic
- Under Add to projects, select the project(s) you want the scanner to access
- Click Add
Step 3: Run the Scanner
Use one of the following options to run the scanner: (A) Use the Observes extension; (B) Use the standalone scanner (from source / binary).
A) Using the Observes extension
Install the Observes extension from the Azure DevOps Marketplace. The task handles authentication, dependencies, and execution automatically.
Because you manually created the managed identity and associated it with an ADO ARM service connection, use the arm auth method exactly as shown in Option 1:
- task: observes@1
inputs:
authMethod: arm
armServiceConnection: 'Observes-scanner-identity'
organization: 'my-ado-org'
jobId: $(Build.BuildId)
That's it - the task uses the service connection's identity (managed identity or service principal) and requires no additional auth flags. Alternatively you can use the AzureCLI@2 task if you download the source code or the executable:
B) Using the standalone scanner (AzureCLI)
- task: AzureCLI@2
displayName: 'Run Observes Scanner'
inputs:
connectedServiceNameARM: 'Observes-scanner-identity'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
python scan.py -j my_scan -o my_org --auth-mode default