Una service connection è l'identità con cui una pipeline di Azure DevOps entra in Azure. Questa procedura ne crea due: una automatica, dove l'identità la crea Azure DevOps, e una a mano. Nessuna delle due contiene una password.

Occorre: un account Azure con una sottoscrizione attiva e il ruolo Owner su di essa, un'organizzazione di Azure DevOps con un progetto e un repository, l'interfaccia a riga di comando di Azure con l'accesso già fatto (az login), un browser. Durata: circa trenta minuti. Costo: zero. Gruppi di risorse, etichette e registrazioni di applicazioni non si pagano, e le esecuzioni della pipeline rientrano nei 1.800 minuti gratuiti al mese.

Il portale delle schermate è in inglese: i nomi dei comandi sono riportati come appaiono a schermo.

La connessione automatica

1. Prepara due gruppi di risorse

az group create -n rg-guide-devops-01 -l italynorth
az group create -n rg-guide-devops-02 -l italynorth

Il primo è quello che la pipeline potrà usare. Il secondo serve a dimostrare che non lo può toccare.

2. Apri il modulo

Nel progetto di Azure DevOps: Project settings > Service connections > New service connection. Scegli Azure Resource Manager e premi Next.

L'elenco dei tipi di connessione, con Azure Resource Manager scelto

3. Scegli l'identità e limita l'ambito

  • Identity type: App registration (automatic)
  • Credential: Workload identity federation
  • Scope level: Subscription
  • Subscription: la tua
  • Resource group: rg-guide-devops-01
  • Service Connection Name: sc-guide-auto

Il modulo compilato, con il gruppo di risorse scelto

Il campo Resource group è facoltativo: lasciandolo vuoto la connessione prende il ruolo su tutta la sottoscrizione, compilandolo lo prende su quel solo gruppo.

In fondo al modulo, sotto Security, lascia Grant access permission to all pipelines deselezionato. Premi Save.

4. La connessione è pronta

L'elenco riporta il nome, il tipo e il metodo di autenticazione: Workload identity federation (Automatic).

L'elenco delle connessioni con quella appena creata

Cosa ha creato Azure DevOps al posto tuo

5. La registrazione dell'applicazione e la credenziale federata

Nel portale di Azure: Microsoft Entra ID > App registrations. La voce nuova si chiama <organizzazione>-<progetto>-<identificativo della connessione>. Aprila, poi Certificates & secrets > Federated credentials, e apri l'unica riga.

La credenziale federata, con emittente e soggetto

Dentro non c'è nessuna password. Ci sono due valori:

Issuer   https://login.microsoftonline.com/<identificativo del tenant>/v2.0
Value    /eid1/c/pub/t/.../a/.../sc/<id organizzazione>/<id connessione>

Gli stessi valori si leggono da riga di comando:

az ad app federated-credential list --id <identificativo applicazione> -o json

6. Il ruolo, solo sul gruppo di risorse

Nel portale, il gruppo rg-guide-devops-01 > Access control (IAM) > Role assignments, filtrando per il nome del progetto.

Il ruolo assegnato, limitato a questa risorsa

Una riga sola: Contributor, con ambito This resource. Sul secondo gruppo non c'è niente.

La prova: una pipeline

7. Il file

Metti questo file nel repository, con il nome azure-pipelines.yml:

trigger: none

pool:
  vmImage: ubuntu-latest

steps:
- task: AzureCLI@2
  displayName: Chi sono
  inputs:
    azureSubscription: sc-guide-auto
    scriptType: bash
    scriptLocation: inlineScript
    inlineScript: |
      az account show --query "{identita:user.name, tipo:user.type}" -o yaml

- task: AzureCLI@2
  displayName: Legge il gruppo autorizzato
  inputs:
    azureSubscription: sc-guide-auto
    scriptType: bash
    scriptLocation: inlineScript
    inlineScript: |
      az group show -n rg-guide-devops-01 --query "{nome:name, regione:location}" -o yaml

- task: AzureCLI@2
  displayName: Scrive un'etichetta sul gruppo autorizzato
  inputs:
    azureSubscription: sc-guide-auto
    scriptType: bash
    scriptLocation: inlineScript
    inlineScript: |
      az group update -n rg-guide-devops-01 --tags guida=service-connection --query tags -o yaml

- task: AzureCLI@2
  displayName: Prova il gruppo non autorizzato
  continueOnError: true
  condition: always()
  inputs:
    azureSubscription: sc-guide-auto
    scriptType: bash
    scriptLocation: inlineScript
    inlineScript: |
      az group show -n rg-guide-devops-02 --query name -o tsv

Il nome della connessione si scrive in azureSubscription: il campo vuole il nome della service connection, non quello della sottoscrizione. L'ultimo passo ha continueOnError: true perché deve fallire.

8. Crea la pipeline

Pipelines > New pipeline > Azure Repos Git > il repository > Existing Azure Pipelines YAML file > /azure-pipelines.yml > Continue > Run.

9. La prima esecuzione si ferma e chiede il permesso

L'esecuzione in attesa del permesso sulla connessione

Premi View, poi Permit, e conferma: «Granting permission here will permit the use of Service connection 'sc-guide-auto' for all waiting and future runs of this pipeline.»

10. L'esito

L'esecuzione dura 41 secondi. Nel registro, le righe che contano:

Chi sono
  az login --service-principal -u *** --tenant 4813d8ed-... --federated-token ***
  identita: ***
  tipo: servicePrincipal

Legge il gruppo autorizzato
  nome: rg-guide-devops-01
  regione: italynorth

Scrive un'etichetta sul gruppo autorizzato
  guida: service-connection

Prova il gruppo non autorizzato
  ERROR: (AuthorizationFailed) The client '***' with object id '15bb16b7-...' does not have
  authorization to perform action 'Microsoft.Resources/subscriptions/resourcegroups/read'
  over scope '/subscriptions/.../resourcegroups/rg-guide-devops-02' or the scope is invalid.

L'agente entra con --federated-token. L'identità è coperta dagli asterischi anche nel registro.

La stessa connessione a mano, con un ruolo mirato

11. Crea l'applicazione da riga di comando

Dalla Cloud Shell del portale, oppure da un terminale con az login già fatto:

az ad app create --display-name sc-guide-manual --sign-in-audience AzureADMyOrg
az ad sp create --id <identificativo applicazione>

Il primo comando restituisce l'appId, il secondo crea il service principal.

12. Compila il modulo manuale

New service connection > Azure Resource Manager, poi:

  • Identity type: App registration or managed identity (manual)
  • Credential: Workload identity federation
  • Service Connection Name: sc-guide-manual
  • Directory (tenant) ID: l'identificativo del tenant

Premi Next. Azure DevOps salva la connessione come bozza e mostra i due valori da registrare in Azure.

Il passo due del modulo manuale, con emittente e soggetto da copiare

Compila gli altri campi:

  • Subscription ID: l'identificativo della sottoscrizione
  • Subscription name: il nome della sottoscrizione
  • Application (client) ID: l'appId del passo 11

Lascia la finestra aperta.

13. Registra la credenziale e assegna il ruolo

Con Issuer e Subject identifier copiati dal modulo:

az ad app federated-credential create --id <identificativo applicazione> --parameters '{
  "name": "sc-guide-manual",
  "issuer": "<Issuer copiato dal modulo>",
  "subject": "<Subject identifier copiato dal modulo>",
  "audiences": ["api://AzureADTokenExchange"]
}'

az role assignment create --assignee <identificativo applicazione> --role Reader --scope /subscriptions/<identificativo sottoscrizione>/resourceGroups/rg-guide-devops-01

Il ruolo è Reader, su un solo gruppo. Torna nel modulo e premi Verify and save.

14. Riesegui la pipeline

Cambia una riga nel file, azureSubscription: sc-guide-manual, e fai ripartire la pipeline.

Legge il gruppo autorizzato
  nome: rg-guide-devops-01
  regione: italynorth

Scrive un'etichetta sul gruppo autorizzato
  ERROR: (AuthorizationFailed) The client '***' with object id 'e1fad9c5-...' does not have
  authorization to perform action 'Microsoft.Resources/subscriptions/resourcegroups/write'
  over scope '/subscriptions/.../resourcegroups/rg-guide-devops-01' or the scope is invalid.

Legge, e si ferma sul passo che scrive.

Pulire

az group delete -n rg-guide-devops-01 --yes --no-wait
az group delete -n rg-guide-devops-02 --yes --no-wait
az ad app delete --id <identificativo applicazione manuale>

Le due connessioni si cancellano dal progetto, da Project settings > Service connections. La registrazione creata dalla modalità automatica se ne va insieme alla connessione.

Nomi dei comandi, schermate e tempi rilevati su Azure DevOps e sul portale di Azure il 6 novembre 2026, regione Italy North, con l'interfaccia a riga di comando di Azure 2.91.0 e l'attività AzureCLI@2 versione 2.282.3.