← All articlesAzure

Securing Azure Functions with Managed Identity

Ishfaq Nazir · Microsoft & Azure Cloud Security Architect 4/7/2026 10 min read

Securing Azure Functions with Managed Identity

Introduction

In the evolving landscape of cloud-native development, Azure Functions have emerged as a powerful, serverless solution for executing event-driven code at scale. While the agility and cost-effectiveness of Azure Functions are undeniable, securing access to other Azure and Microsoft Entra ID-protected resources often presents a critical challenge. Traditionally, developers might resort to managing connection strings, secrets, or certificates, introducing complexities related to rotation, storage, and compromise.

This article delves into leveraging Managed Identities for Azure Functions, a robust and recommended approach for securing resource access. Managed Identities, a feature of Microsoft Entra ID, provide an automatically managed identity for Azure services to authenticate to any service that supports Microsoft Entra authentication, without managing any credentials. This dramatically simplifies security practices, enhances compliance, and reduces the operational overhead associated with credential management.

This guide is intended for cloud architects, Azure developers, and security engineers who are building or maintaining Azure Functions and are looking for a more secure and efficient way to manage access to other Azure resources. A basic understanding of Azure Functions, Microsoft Entra ID, and general cloud security principles will be beneficial.

Why this matters

Securing Azure Functions with Managed Identity addresses several critical business and technical concerns. From a compliance perspective, many industry regulations and internal policies mandate stringent control over credentials and access to sensitive data. By eliminating hard-coded secrets, Managed Identities help meet these requirements by reducing the attack surface and establishing a more auditable access pattern.

Financially, the operational overhead involved in managing and rotating secrets, responding to security incidents stemming from compromised credentials, and the potential for service disruptions due to expired keys can be substantial. Managed Identities streamline these processes, freeing up valuable developer and operations time and thus reducing overall costs.

Technically, the risk of credential leakage is significantly mitigated. When secrets are embedded in code, configuration files, or environment variables, they become potential targets for attackers. Managed Identities abstract this away entirely, as Azure automatically manages the lifecycle of the identity. This enhances the overall security posture, reduces the likelihood of breaches, and improves developer productivity by simplifying authentication logic.

Key concepts

  • Managed Identities for Azure Resources: A feature of Microsoft Entra ID that provides an automatically managed identity for Azure services. This identity can be used to authenticate to any service that supports Microsoft Entra authentication, without managing any credentials in your code.
  • System-assigned Managed Identity: An identity created and tied to the lifecycle of a specific Azure resource (e.g., an Azure Function app). When the resource is deleted, the identity is also deleted. It cannot be shared with other resources.
  • User-assigned Managed Identity (UAMI): A standalone Azure resource that can be assigned to multiple Azure resources. Its lifecycle is independent of the resources it's assigned to. This is useful for scenarios where you need to share an identity across multiple resources or manage its lifecycle separately.
  • Microsoft Entra ID (formerly Azure Active Directory): Microsoft's cloud-based identity and access management service. It provides authentication and authorization services for various Azure resources and applications.
  • Role-Based Access Control (RBAC): Azure's authorization system that allows you to manage who has access to Azure resources, what they can do with those resources, and what areas they have access to. Managed Identities are granted access to resources through RBAC role assignments.
  • Azure Key Vault: A cloud service for securely storing and accessing secrets, such as API keys, passwords, certificates, and cryptographic keys. While Managed Identities reduce the need for applications to access Key Vault for their own credentials, they can be used to grant the function secure access to Key Vault itself to retrieve other application secrets if needed.

Step-by-step implementation

This section outlines how to enable a system-assigned managed identity for an Azure Function App and grant it access to an Azure Storage Account.

  1. Create an Azure Function App:

If you don't already have one, create an Azure Function App in the Azure portal. Navigate to the Azure portal. Search for and select "Function Apps". Click "+ Create". Fill in the necessary details like Subscription, Resource Group, Function App name, Runtime stack, and Region.

  1. Enable System-Assigned Managed Identity for the Function App:

In the Azure portal, navigate to your Function App. In the left-hand navigation pane, under Settings, select Identity. Under the System assigned tab, set the Status to On and click Save. Confirm the activation. Azure will register a new service principal in Microsoft Entra ID for your Function App.

  1. Identify the Target Resource and Grant Access:

For this example, let's assume your Function App needs to interact with an Azure Storage Account. Navigate to your Azure Storage Account in the Azure portal. In the left-hand navigation pane, select Access control (IAM). Click + Add and then Add role assignment. On the Role tab, search for and select a suitable role, such as "Storage Blob Data Contributor" if your function needs to write to blob storage. Click Next. On the Members tab, select Managed identity for "Assign access to". Click + Select members. In the Select managed identities blade: For "Managed identity", choose Function App. Select your subscription. Select your Function App from the list. Click Select. Click Review + assign*.

  1. Update Function Code to Use Managed Identity:

Your Azure Function code can now use the Managed Identity to authenticate to the Storage Account. The specific SDKs will often handle this automatically if standard Azure credential providers are used.

```csharp using Azure.Identity; using Azure.Storage.Blobs; using System; using System.Threading.Tasks;

public static async Task Run(string myQueueItem, ILogger log) { log.LogInformation($"C# Queue trigger function processed: {myQueueItem}");

// The DefaultAzureCredential will automatically pick up the system-assigned // managed identity when deployed to Azure. var credential = new DefaultAzureCredential();

// Replace with your storage account URI var blobServiceUri = new Uri("https://<your_storage_account_name>.blob.core.windows.net"); var blobServiceClient = new BlobServiceClient(blobServiceUri, credential);

// Example: List containers await foreach (var blobContainerItem in blobServiceClient.GetBlobContainersAsync()) { log.LogInformation($"Container: {blobContainerItem.Name}"); }

log.LogInformation("Successfully connected to Azure Storage using Managed Identity."); } ```

Note: For .NET, install the Azure.Identity and Azure.Storage.Blobs NuGet packages. For other languages, similar SDKs are available.

  1. Alternatively, using Azure CLI for role assignment:

```bash # Get the Service Principal ID of your Function App's Managed Identity FUNCTION_APP_NAME="your-function-app-name" RESOURCE_GROUP="your-resource-group" STORAGE_ACCOUNT_NAME="yourstorageaccountname"

IDENTITY_PRINCIPAL_ID=$(az functionapp identity show \ --name $FUNCTION_APP_NAME \ --resource-group $RESOURCE_GROUP \ --query principalId \ --output tsv)

# Get the resource ID of your Storage Account STORAGE_ACCOUNT_ID=$(az storage account show \ --name $STORAGE_ACCOUNT_NAME \ --resource-group $RESOURCE_GROUP \ --query id \ --output tsv)

# Assign the 'Storage Blob Data Contributor' role to the Managed Identity # Role ID for 'Storage Blob Data Contributor' is commonly 0b5d0b98-a05b-4347-96ea-c6edc6585e49, # or you can look up by name using az role definition list --name "Storage Blob Data Contributor" --query "[].id" az role assignment create \ --assignee $IDENTITY_PRINCIPAL_ID \ --role "Storage Blob Data Contributor" \ --scope $STORAGE_ACCOUNT_ID ```

Example configuration

This Bicep snippet demonstrates how to deploy an Azure Function App with a system-assigned managed identity enabled and then assign that identity a "Storage Blob Data Contributor" role to an existing storage account.

param functionAppName string
param location string
param storageAccountName string
param storageAccountResourceGroup string

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' existing = {
  name: storageAccountName
  scope: resourceGroup(storageAccountResourceGroup)
}

resource functionApp 'Microsoft.Web/serverfarms@2022-03-01' existing = {
  // This typically points to an existing App Service Plan for the Function App
  name: 'my-app-service-plan' // Replace with your existing App Service Plan name
}

resource functionAppResource 'Microsoft.Web/sites@2022-03-01' = {
  name: functionAppName
  location: location
  kind: 'functionapp'
  identity: {
    type: 'SystemAssigned'
  }
  properties: {
    serverFarmId: functionApp.id
    httpsOnly: true
    // Other Function App properties like WEBSITE_RUN_FROM_PACKAGE, SCM_DO_BUILD_DURING_DEPLOYMENT etc.
    siteConfig: {
      appSettings: [
        {
          name: 'FUNCTIONS_WORKER_RUNTIME'
          value: 'dotnet' // or 'node', 'python', etc.
        }
        {
          name: 'AzureWebJobsStorage'
          value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageAccount.id, storageAccount.apiVersion).keys[0].value}'
        }
        // ... other settings
      ]
    }
  }
}

// Assign 'Storage Blob Data Contributor' role to the Function App's Managed Identity
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(functionAppResource.id, storageAccount.id, 'StorageBlobDataContributor') // Unique name for the role assignment
  properties: {
    roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', '0b5d0b98-a05b-4347-96ea-c6edc6585e49') // Role Definition ID for 'Storage Blob Data Contributor'
    principalId: functionAppResource.identity.principalId
    principalType: 'ServicePrincipal'
  }
  scope: storageAccount // Assign role at the Storage Account scope
}

Common pitfalls

  • Forgetting to grant necessary RBAC roles: Simply enabling Managed Identity on the Function App is not enough. You must explicitly grant the identity appropriate RBAC roles on the target resource(s) it needs to access.
  • Incorrect scope for RBAC roles: Assigning a role at too broad a scope (e.g., subscription level) when a more granular scope (e.g., resource group or individual resource) would suffice introduces an unnecessary security risk. Conversely, too narrow a scope can prevent access.
  • Assuming automatic access to all resources: Managed Identities only provide an identity. Each resource that supports Microsoft Entra authentication still requires explicit permission granted via RBAC.
  • Using hardcoded connection strings/secrets alongside Managed Identity: This negates the security benefits of Managed Identities. Ensure all dependencies are updated to leverage the Managed Identity for authentication.
  • Confusion between System-assigned and User-assigned identities: While both are useful, understand their differences. System-assigned is simpler for single-resource scenarios. User-assigned is better for shared identities across multiple resources or when an identity's lifecycle needs to be decoupled from a specific resource.
  • Firewall rules blocking Managed Identity access: If a target resource has IP-based firewall rules, ensure that the Azure infrastructure's outbound IP ranges (or a Private Endpoint) are configured to allow the Managed Identity access. Managed Identity requests originate from Azure infrastructure IP addresses, which are dynamic unless Private Endpoints are used.

Best practices

  • Principle of Least Privilege: Always apply the principle of least privilege when assigning RBAC roles to Managed Identities. Grant only the permissions absolutely necessary for the Function App to perform its intended tasks.
  • Use User-Assigned Managed Identities for Shared Identities: When multiple Function Apps or other Azure services require the same set of permissions to a resource, consider using a User-assigned Managed Identity. This simplifies management and role assignments. Aligns with the Azure Well-Architected Framework's security pillar for consistent access control.
  • Avoid Hardcoded Credentials: The primary goal of Managed Identities is to eliminate the need for hardcoded credentials. Ensure your code is refactored to use DefaultAzureCredential or similar SDK constructs that automatically leverage Managed Identities when deployed to Azure.
  • Use Azure Key Vault for Other Application Secrets: If your Function App still needs to access other third-party API keys or non-Azure-AD-protected secrets, use Azure Key Vault. Grant the Function's Managed Identity access to the Key Vault secrets, rather than storing them directly in app settings.
  • Regularly Review RBAC Assignments: Periodically review the RBAC role assignments for your Managed Identities to ensure they are still appropriate and follow the principle of least privilege. This is a core tenet of the Zero Trust model.
  • Monitor Managed Identity Usage: Leverage Azure Monitor and Microsoft Entra ID audit logs to track the usage of Managed Identities, helping to identify unauthorized access attempts or suspicious activity.

Further reading

#Functions#Identity

Related articles