Due tenant, due audience
Identità e accessi
Al sistema arrivano tre tipi di chiamante e nessuno si autentica allo stesso modo. Un genitore è un'identità consumer esterna. Un amministratore è un'identità workforce con un app role. La macchina in casa non è né l'una né l'altro: non tiene nessuna credenziale Azure.
Perché l'amministratore non è un genitore con un flag
Sarebbe stato un booleano. Il motivo per cui non lo è: la directory External ID è aperta alla registrazione autonoma, e un flag vivrebbe nello stesso container Cosmos che un amministratore modifica — quindi il privilegio e la cosa che lo concede condividerebbero il raggio d'esplosione, e servirebbe comunque un percorso di bootstrap per crearne il primo.
Invece l'amministratore entra da una app registration distinta nel tenant workforce, e il privilegio arriva nel claim roles del token. Le due applicazioni hanno audience diverse, quindi il token di un genitore viene rifiutato dal controllo di audience prima che giri una qualunque logica nostra. È un'affermazione più forte di «controlliamo un campo»: non esiste un percorso di codice in cui un token consumer venga esaminato per diritti amministrativi.
Una trappola che vale la pena scrivere, perché costa un pomeriggio: l'assegnazione di un app role può finire in silenzio su Default Access, il cui appRoleId è tutto zeri. Il token è perfettamente valido e semplicemente non porta il claim roles, quindi il rifiuto sembra un problema di credenziali invece che di assegnazione. Si controlla suservicePrincipals/<id>/appRoleAssignedTo, guardando l'id.
Multi-tenant per costruzione
Niente nel modello dei dati presuppone un nucleo solo. Ogni riga salvata è partizionata per id di nucleo, ogni device key appartiene esattamente a un nucleo, e ogni rotta del genitore risolve il nucleo dal token e non da qualcosa che il chiamante manda. Una seconda casa richiede un provisioning, non un cambio di schema.
È un'affermazione sulla forma, e conviene essere precisi su quanto sia stata esercitata: il codice ha sempre girato con un nucleo solo dentro. Una seconda casa non è mai stata allestita, quindi «multi-tenant» qui vuol dire che i confini sono tracciati e imposti, non che due nuclei siano stati osservati affiancati.
La casa non ha credenziali Azure
L'hub nella stanza non può autenticarsi ad Azure e non ci prova. Presenta una device key in un'intestazione X-Device-Key su TLS, e tutto quello che ha bisogno di un modello — leggere una pagina, interpretare un promemoria, continuare un pomeriggio — è una richiesta all'API, che la credenziale ce l'ha. Chiuso per difetto: senza device key configurata quelle rotte rispondono 503 invece di lasciar passare qualcosa.
Così una macchina fisicamente asportabile da una casa non porta mai qualcosa che si possa rigiocare contro una sottoscrizione. Il costo è quello dichiarato nei flussi: senza cloud, niente lettura.
Due chiavi che non sono la stessa chiave
Il filtro di sicurezza e l'approvazione del genitore sono entrambi sigillati con HMAC, con due chiavi separate, e il sigillo di approvazione copre quello di sicurezza. Condividerne una permetterebbe al filtro di coniare approvazioni del genitore, che è esattamente il guasto per cui la separazione esiste.
Il sigillo di approvazione si conia e si verifica dentro una singola esecuzione sul dispositivo, quindi ruotare quella chiave non costa niente. Il sigillo di sicurezza attraversa processi e giorni — coniato quando il contenuto viene offerto, salvato dal pannello, verificato più tardi — quindi è quella la chiave da proteggere. Nessuna delle due sta sull'hub, e questo è stato verificato cercando i valori letterali nel filesystem invece di fidarsi dello script di deploy.
Pubblicare senza un segreto
La pipeline che pubblica l'API non tiene nessuna password. Una managed identity assegnata dall'utente porta una credenziale federata, GitHub Actions scambia il proprio token OIDC con uno di Azure, e fanno il resto tre assegnazioni di ruolo legate a singole risorse: spingere su un registro, leggerlo, e aggiornare una container app.
Il soggetto di una credenziale federata porta gli id numerici, non i nomi:repo:owner@12345/repo@67890:ref:refs/heads/main. Il messaggio di rifiuto cita per intero il soggetto che ha ricevuto, quindi il metodo affidabile è registrare una volta, lanciare una volta, e leggere il soggetto vero dal rifiuto invece di scriverlo a memoria. Sopravvive anche a una rinomina del repository.
Due buchi, dichiarati
scp non viene verificato. Audience, issuer, scadenza e subject del token si controllano, lo scope no. È innocuo finché lo scope è uno solo, e diventa un buco nel momento in cui qualcuno ne aggiunge un secondo credendo che separi permessi.
Le app registration si creano a mano nel portale, di proposito, e i passi sono scritti invece che scriptati. Quello che si dimentica ogni volta èrequestedAccessTokenVersion: 2 nel manifesto: senza, l'issuer è l'endpoint v1 e ogni accesso fallisce senza dire perché.
I passi di deploy, compresi quelli manuali ·come la pipeline cambia Azure senza un segreto · cosa esce dal dispositivo
Questo sito non usa cookie, non raccoglie statistiche e non carica niente da altri server.