Skip to content

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 Contributor role 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

  1. Go to your Azure DevOps organization https://dev.azure.com/{your-org}
  2. Click Organization settings (bottom-left gear icon)
  3. Select Users under the General section
  4. Click Add users
  5. In the search box, enter the display name of your managed identity (e.g. Observes-scanner-identity)
  6. Set Access level to Basic
  7. Under Add to projects, select the project(s) you want the scanner to access
  8. 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:

  1. 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)

  2. 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:

  1. Go to your Azure DevOps organization https://dev.azure.com/{your-org}
  2. Click Organization settings (bottom-left gear icon)
  3. Select Users under the General section
  4. Click Add users
  5. In the search box, enter the display name of your managed identity (e.g. Observes-scanner-identity)
  6. Set Access level to Basic
  7. Under Add to projects, select the project(s) you want the scanner to access
  8. 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