Le domande da porsi su un ambiente Microsoft Foundry sono le stesse che ci si pone su un workspace di Azure Machine Learning: chi accede, con che identità, da quale rete. Cambiano gli oggetti e cambiano i nomi dei ruoli, e proprio i nomi sono la parte più insidiosa in questo momento, perché i ruoli di Foundry sono stati rinominati di recente e la documentazione, il portale e i template convivono ancora con entrambe le denominazioni. Un MLOps engineer che scrive automazione deve saperlo prima di scoprirlo in pipeline.

Chiavi API contro Microsoft Entra ID

Foundry accetta due metodi di autenticazione: Microsoft Entra ID e le chiavi API. Non sono equivalenti. Una chiave è un segreto statico associato alla risorsa: concede accesso pieno, non esprime l’identità di chi chiama, non è scopabile e non è auditabile per principale. Microsoft la considera adatta a prototipazione rapida e ambienti di test isolati, e la sconsiglia esplicitamente per i carichi di produzione.

La differenza non è solo di postura di sicurezza: alcune capacità non funzionano affatto con la chiave. Il servizio agenti, le valutazioni e il Toolbox richiedono Microsoft Entra ID, così come l’uso di managed identity, l’attribuzione per richiesta e qualunque forma di least privilege con ruoli built-in o custom. L’inferenza di base, il fine-tuning e le chiamate di content safety funzionano con entrambi.

Sul piano tecnico, i token vanno richiesti per lo scope https://ai.azure.com/.default e la risorsa deve avere un custom subdomain configurato, altrimenti l’autenticazione a token non è possibile. Nel codice si parte da DefaultAzureCredential, ma in produzione conviene passare a una credenziale deterministica come ManagedIdentityCredential, così l’applicazione non dipende dall’ordine di risoluzione della catena.

from azure.identity import DefaultAzureCredential

credential = DefaultAzureCredential()
token = credential.get_token("https://ai.azure.com/.default")

Quando tutti i chiamanti sono passati ai token, si disabilita l’autenticazione a chiave sulla risorsa agendo sulla proprietà disableLocalAuth, esponibile come parametro del template Bicep. Attenzione a un dettaglio che vale una domanda d’esame: disabilitare l’autenticazione locale non annulla le chiavi già distribuite, quindi la rimozione si completa rigenerando Key1 e Key2.

I ruoli Foundry e gli ambiti di assegnazione

I ruoli built-in specifici sono cinque: Foundry Agent Consumer, Foundry User, Foundry Project Manager, Foundry Account Owner e Foundry Owner. I quattro finali si chiamavano rispettivamente Azure AI User, Azure AI Project Manager, Azure AI Account Owner e Azure AI Owner: gli ID dei ruoli e i permessi non sono cambiati con il rinomino, solo l’etichetta. Proprio per questo la documentazione raccomanda di usare nel codice il role definition ID invece del nome, così l’automazione non si rompe mentre il rinomino si propaga.

La divisione dei compiti segue la separazione fra control plane e data plane. Foundry User dà accesso in lettura e le azioni di data plane per costruire e testare: è il ruolo minimo dello sviluppatore. Foundry Project Manager aggiunge la gestione dei progetti e la pubblicazione degli agenti. Foundry Account Owner crea account e progetti e gestisce i modelli, ma non ha le azioni di data plane. Foundry Owner le ha entrambe. Foundry Agent Consumer è il minimo privilegio per chi deve solo invocare l’endpoint di un agente. Da qui una regola operativa spesso richiesta: per fare fine-tuning servono permessi di data plane e di control plane insieme, quindi o si assegna Foundry Owner, oppure si combinano Foundry User e Foundry Account Owner.

Due avvertenze. La prima riguarda i ruoli sbagliati: non vanno usati i ruoli che iniziano con “Cognitive Services” per gli scenari Foundry, e soprattutto non va usato Azure AI Developer, che nonostante il nome è scopato ai workspace di Azure Machine Learning e agli hub, non ai progetti Foundry. La seconda è la più importante per chi automatizza: l’assegnazione automatica di Foundry User al creatore avviene solo quando la risorsa viene creata dal portale, non quando la crei da SDK o da CLI. Un ambiente nato da IaC arriva senza quelle assegnazioni, quindi le role assignment vanno messe nel template.

Gli ambiti disponibili sono tre: risorsa Foundry, progetto Foundry e singolo agente. L’ambito agente è particolare, perché le assegnazioni a quel livello sono valutate solo per l’accesso agli endpoint dell’agente e non concedono permessi di management.

Identità gestite fra risorsa, progetto e servizi collegati

Le managed identity non sono un’opzione decorativa: sono il modo in cui i pezzi si parlano senza segreti. L’assegnazione minima consigliata prevede Foundry User sulla risorsa sia per il principale utente sia per la managed identity del progetto. Verso le risorse esterne vale la regola opposta: è la managed identity della risorsa Foundry a dover ricevere il ruolo sul servizio di destinazione — per esempio Storage Blob Data Reader su uno storage account portato da te, o l’assegnazione corrispondente su Azure AI Search.

C’è poi un ruolo che serve solo in scenari di rete privata: Azure AI Enterprise Network Connection Approver, da assegnare alla managed identity dell’account perché i private endpoint gestiti verso Storage, Cosmos DB e Azure AI Search vengano creati e approvati automaticamente.

Ingresso e uscita: due decisioni di rete distinte

L’isolamento di rete in Foundry si progetta su due assi indipendenti, ed è così che l’esame lo presenta. In ingresso si agisce sul flag di public network access, che ha tre stati utili: abilitato, disabilitato con private endpoint, oppure abilitato solo da indirizzi IP selezionati. Creando un private endpoint, Azure aggiorna il record CNAME della risorsa verso un alias nel sottodominio privatelink e crea la zona DNS privata corrispondente: dall’interno della virtual network il nome risolve all’IP privato, dall’esterno continua a risolvere all’endpoint pubblico. Due comportamenti da ricordare: rimuovere i private endpoint non rende il progetto pubblico, e riabilitare l’accesso pubblico non rimuove i private endpoint esistenti.

In uscita si sceglie fra managed virtual network e virtual network propria. La rete gestita ha due modalità di isolamento: AllowInternetOutbound e AllowOnlyApprovedOutbound, quest’ultima basata su regole di tipo fqdn, privateendpoint e servicetag, con un firewall gestito creato automaticamente quando aggiungi la prima regola FQDN e limitato alle porte 80 e 443. Le transizioni sono a senso unico: da internet outbound non si torna a disabilitato, e da approved outbound non si torna a internet outbound. Con la virtual network propria si usa la network injection su una subnet delegata a Microsoft.App/environments e di dimensione almeno /27.

La trappola operativa è la stessa in entrambi i casi: la rete in uscita non si aggiunge dopo. Non puoi cambiare la subnet delegata, non puoi aggiungere l’injection a un deployment esistente e non puoi disattivare la rete gestita una volta abilitata — serve ridistribuire la risorsa. E i private endpoint verso Storage, Azure AI Search e Cosmos DB non vengono creati in automatico con la risorsa: vanno creati a parte.

Da ricordare per l esame

  • Le chiavi API danno accesso pieno alla risorsa e non identificano il chiamante; agenti, valutazioni, managed identity e least privilege richiedono Microsoft Entra ID. Token sullo scope https://ai.azure.com/.default, con custom subdomain obbligatorio.
  • disableLocalAuth spegne l’autenticazione a chiave, ma le chiavi già distribuite restano valide finché non le rigeneri.
  • I ruoli Foundry sono stati rinominati (Azure AI User è diventato Foundry User e così via): gli ID non sono cambiati, quindi negli script si usa il role definition ID, non il nome.
  • L’assegnazione automatica di Foundry User avviene solo creando dal portale: un ambiente creato da CLI o SDK richiede le role assignment esplicite nel template.
  • Ingresso e uscita sono decisioni separate: public network access più private endpoint da un lato; managed virtual network (AllowInternetOutbound o AllowOnlyApprovedOutbound) oppure injection su subnet delegata a Microsoft.App/environments dall’altro. L’isolamento in uscita si decide alla creazione, non dopo.