Quando scegliamo di utilizzare una Azure Function App lo facciamo per la velocità di deployment, la sua flessibilità, le varie modalità di hosting (serverless, App Service Plan, Container, etc.) e la sua possibile integrazione con altri prodotti Azure (Blob Storage, Event Grid, etc.) e non, grazie alle possibilità virtualmente infinite forniteci dai Trigger HTTP.
I punti deboli nella configurazione
Purtroppo nel caso delle Azure Function Apps non possiamo dire che Microsoft abbia scelto come impostazioni di default quelle più rigide a livello di sicurezza, vediamo qualche esempio.
URL della function: nel primo step della creazione della Azure Function ci verrà chiesto di assegnarle un nome, il quale viene inserito come terzo livello del dominio “azurewebsites.net“, componendo così l’URL pubblico della nostra Function App. Ad esempio con il nome “davide”, l’URL pubblico derivato sarebbe “davide.azurewebsites.net“. Nel caso in cui decidessimo di aggiungere alla Function App un dominio personalizzato, ci esporremmo al rischio futuro di eliminare l’App dimenticandoci di cancellare il record pubblicato nella nostra zona DNS. Se un malintenzionato dovesse successivamente creare una Function App con lo stesso nome di quella da noi cancellata, potenzialmente potrebbe rendere raggiungibile un server web, sotto il suo controllo, tramite il nostro dominio. Per ridurre questo rischio Microsoft consente ora di creare degli hostname univoci abilitando il relativo flag.

Basic authentication: se non abbiamo bisogno di utilizzare metodi di deployment che richiedano la basic authentication, assicuriamoci di disattivarla nella sezione “Deployment” nel processo di creazione della function:

Modalità di autenticazione verso le risorse esterne: in base opzioni selezionate durante la creazione della Function App, Azure provvederà alla creazione di alcune risorse esterne. Recentemente Microsoft ha introdotto la possibilità di scegliere come la Function si autenticherà verso alcune di queste risorse. Al momento della scrittura di questo articolo non è possibile farlo per tutte le risorse esterne, ma è consigliabile l’utilizzo di una Managed Identity al posto dei secret. Per saperne di più sulle Managed Identities in fondo all’articolo è presente un link ad una pubblicazione precedente.

Admin API pubblicamente accessibili: queste API sono poco utilizzate e la loro documentazione non è molto estensiva, tuttavia esse consentono di interagire con l’host della nostra Function App, interrogandone lo stato, ma soprattutto rendono possibile la creazione di nuove funzioni. Per proteggere queste API da richieste malevole, il client dovrà inserire la master key nelle chiamate HTTPS verso i loro endpoint. Se non ci serve raggiungere le API amministrative da Internet possiamo isolarle, rendendole accessibili unicamente tramite Azure Resource Manager, che grazie al sistema RBAC consente di assegnare i permessi in modo granulare.

Disattivare la pubblicazione del codice tramite basic authentication: nel caso in cui fosse stata attivata nel processo di deployment è possibile intervenire successivamente per disattivarla se non più necessaria. Da notare che la basic authentication potrebbe essere usata, per pubblicare il codice, sia tramite protocollo FTP (nei piani che lo supportano) che tramite l’endpoint SCM. Se l’FTP non ci occorre nemmeno per altri scopi lo possiamo disattivare per ridurre ulteriormente la superficie d’attacco.

Abilitare l’HTTPS: può sembrare un suggerimento banale, ma nel caso in cui non ci siano ragioni insormontabili per cui è necessario utilizzare l’HTTP in chiaro, forzare l’utilizzo dell’HTTPS è un dovere, considerando anche che per le funzioni esposte su Internet è possibile sfruttare (sia per i domini di default, che per quelli custom) il certificato TLS gratuito che Microsoft ci concede.
Raggiungibilità degli Endpoint HTTPS: occorre determinare quali sono i client che utilizzeranno la nostra Function App. Nel caso in cui siano identificabili tramite un gruppo limitato di indirizzi pubblici potremo fare in modo che la Function App accetti richieste solo da essi. Inoltre è possibile applicare controlloi simili su aluni header HTTP per una maggiore granularità.


Se, invece, la Function App deve essere disponibile solo ad altre risorse del nostro ambiente Azure, possiamo valutare la configurazione di un Private Endpoint, che eviterebbe completamente la pubblicazione su Internet delle nostre funzioni.
Autorizzazione all’esecuzione con le chiavi condivise: per verificare che un client sia effettivamente autorizzato a chiamare una determinata funzione è possibile utilizzare le App Keys. Quando creiamo una nuova funzione ci viene chiesto che livello di autorizzazione vogliamo che sia applicato alla stessa:
- Function: la funzione può essere chiamata solo specificando la Function Key (differente per ogni funzione della nostra app);
- Admin: la funzione può essere chiamata solo specificando la Master Key (uguale per tutte le funzioni della nostra app, e che in aggiunta può chiamare l’endpoint amministrativo);
- Anonymous: la funzione può essere chiamata senza che venga richiesta una chiave di verifica
La chiave può essere passata dal client sia come parametro query dell’URL, che come valore dell’header HTTP “x-functions-key”.
Accorgimenti per la programmazione di funzioni sicure
Non sempre le funzionalità di security messe a disposizione da Microsoft sono sufficienti a coprire tutte le casistiche, oppure potremmo voler implementare dei controlli aggiuntivi o più solidi. La valutazione va fatta in base a quali sono i client che dovranno chiamare le nostre funzioni, ad esempio ci sono servizi Microsoft (esterni ad Azure) che autenticano, mediante firma HMAC, le richieste che inviano. In questo caso dovremo scrivere noi il codice che verifichi la correttezza della firma prima di eseguire l’azione richiesta.
Validazione del certificato del client
Potremmo essere tratti in inganno dal fatto che nella configurazione delle Function Apps sia presente la voce “Incoming client certificates”, pensando che Azure verifichi nativamente il certificato del client prima di eseguire la nostra funzione. Ciò non è vero, l’impostazione regola solo il comportamento del server HTTPS, se attivata si limiterà ad inoltrare il certificato presentato dal client alla nostra funzione. Saremo noi che dovremo implementare la verifica del certificato secondo le nostre esigenze.
Modalità di deployment
Coerentemente a quanto discusso nei paragrafi precedenti, è importante scegliere gli strumenti di sviluppo con il supporto all’autenticazione tramite Entra ID per l’upload del nostro codice verso la Function App. Due esempi sono:
- Visual Studio Code con le relative estensioni per gli approcci meno strutturati che ci consentono di mantenere i file localmente;
- Azure DevOps e le Pipeline, per il deployment contestuale all’aggiornamento del repository (utilizzo dei service principal per l’autenticazione).
Archiviazione e recupero dei secret
Seppur le Function App ci consentano di creare delle variabili d’ambiente, e possa essere una tentazione (o un retaggio del passato) archiviare lì i segreti o le chiavi condivise per l’accesso ad altri servizi, ciò è fortemente sconsigliato. Seguendo quanto descritto nei paragrafi precedenti, la best practice è utilizzare le Managed Identity per accedere in modo sicuro (RBAC, o ancora meglio, Access Policy) a uno o più Key Vault.
Granularità degli accessi
In questo articolo abbiamo citato più volte le Managed Identity, nonostante la loro facilità d’implementazione, il loro utilizzo nasconde delle insidie. È degno di nota il fatto che tutte le funzioni istanziate nella stessa Function App abbiano accesso alla stessa System-Assigned Managed Identity, ed a tutte le User-Assigned Managed Identities. Ne consegue che tutti i permessi assegnati alle Identities siano disponibili indiscriminatamente a tutte le funzioni. Per rispettare il principio del “least privilege” dovremo preoccuparci di ripartire le funzioni in diverse Function App, raggruppandole in base al numero minimo di permessi richiesti
Conclusioni
Questo articolo non vuole essere una checklist infallibile per la security delle nostre Azure Function Apps. Il suo scopo è aiutare a capire dove possono nascondersi alcuni dei pericoli meno lampanti e come intervenire. Di seguito lascio vari riferimenti esterni per approfondire quanto discusso.
Riferimenti esterni
Documentazione ufficiale Microsoft sulla security delle Azure Functions
Modalità di accesso all’endpoint SCM / Kudu
Documentazione delle API amministrative delle Azure Functions
Approfondimenti sull’URL univoco generabile per le Azure Functions
Approfondimento delle chiavi delle Function Apps
Documentazione sull’autenticazione basata su certificato client
Metodi per il deployment del codice senza Basic Authentication