How to Upload Blobs to Azure Storage from an Azure Function with Azure Managed Identities (Part 2)

In this 3 part series we are going to learn a few methods for developing an Azure Function that uploads blobs to Azure Storage using the new Azure Blob Storage SDK and the new Azure Identity SDK’s DefaultAzureCredential. We’ll first get everything running locally without any cloud dependencies via a Storage Emulator. We’ll then run the same code locally, but configure it to upload blobs to Azure Storage using a Service Principal. And lastly, we’ll learn how to deploy an Azure Function to Azure, that uses Azure Storage and Managed Identities. The three different setups allow you to iteratively develop Azure Functions without the cost and inner-loop dev cylce overhead of deploying everything to Azure on every code change.

Code: The code for this series can be found here: https://github.com/jongio/azure-blob-functions-managedid

Part 1: Local Function with Storage Emulator (local function, local storage)
Part 2: Local Function with Azure Storage and Service Principal (local function, cloud storage)
Part 3: Azure Function with Azure Storage and Managed Identity (cloud function, cloud storage)

Local Function with Azure Storage and Service Principal (local function, cloud storage)

In Part 1 of this series, we got the local function setup to upload blobs to a local emulator. Now, let’s setup our Azure resources so we can use that same code to send our blobs to Azure using a Service Principal.

Azure Setup

Let’s get all our Azure resources created and configured.

  1. Install Azure CLI
  2. Login to Azure CLI
az login
  1. Set Active Azure Subscription

This ensures that all of the subsequent commands run under the intended subscription.

az account set -s SUBSCRIPTION_NAME_OR_ID

Parameters:

  • SUBSCRIPTION_NAME_OR_ID The subscription that you want to activate. You can use az account show to show the currently set subscription.
  1. Create Resource Group

This is a grouping for all of your Azure resources.

az group create -n RESOURCE_GROUP_NAME -l LOCATION

Parameters:

  • RESOURCE_GROUP_NAME A unique name that you create.
  • LOCATION The location you want all your resources to live. You can use az account list-locations -o table to get a list of all available locations.
  1. Create Blob Storage Account

This account will hold the blobs that you upload via your Azure Function.

az storage account create -n BLOB_STORAGE_ACCOUNT_NAME -g RESOURCE_GROUP_NAME --kind StorageV2 --sku Standard_LRS

Parameters:

  • BLOB_STORAGE_ACCOUNT_NAME A unique name that you create.
  • RESOURCE_GROUP_NAME The name of the resource group that you created earlier.
  • --sku - List of available SKUs can be found here: SKU Types
  1. Create Service Principal

A Service Principal is an identity that acts upon Azure resources. You assign that identity “roles”, which you can see in the command below. By default the Service Principal is created with Contributor access, but we still need to explicitly give it permission to write to blob storage.

Run the following command to create a Service Principal and assign it to the Storage Blob Data Contributor role.

az ad sp create-for-rbac --role ba92f5b4-2d11-453d-a403-e96b0029c9fe --scope /subscriptions/SUBSCRIPTION_ID

Parameters:

  • SUBSCRIPTION_ID The subscription that you want to create the Service Principal in. You can get by running az account show
  • --role - The GUID ba92f5b4-2d11-453d-a403-e96b0029c9fe is the ID for the Storage Blob Data Contributor role. You can find all of the built-in Azure roles here: Built-in roles for Azure resources

That command will output all of the Service Principal metadata, which you will need for the next step.

Save the output of this command, you’ll need it in the next step.

Configure Function App to use Azure Storage

  1. Set Local Settings

Open local.settings.json and ensure the following values are set:

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet",
        "AZURE_CLIENT_ID": "SERVICE_PRINCIPAL_APP_ID",
        "AZURE_CLIENT_SECRET": "SERVICE_PRINCIPAL_PASSWORD",
        "AZURE_TENANT_ID": "SERVICE_PRINCIPAL_TENANT_ID",
        "AZURE_STORAGE_HOST": "blob.core.windows.net",
        "AZURE_STORAGE_ACCOUNT": "BLOB_STORAGE_ACCOUNT_NAME",
        "AZURE_STORAGE_CONTAINER": "azfuncblobs"
    }
}

Parameters:

  • SERVICE_PRINCIPAL_APP_ID The appId from the previous step.
  • SERVICE_PRINCIPAL_PASSWORD The password from the previous step.
  • SERVICE_PRINCIPAL_TENANT_ID The tenant from the previous step.
  • BLOB_STORAGE_ACCOUNT_NAME The same name that you gave the storage account you created earlier.

Notes:

  • You’ll notice that we added the Environment Variables settings (AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID) that DefaultAzureCredential requires to authenticate with a Service Principal and updated the AZURE_STORAGE_ACCOUNT setting to the new storage account.
  • We also updated AZURE_STORAGE_HOST to blob.core.windows.net instead of 127.0.0.1:10000. That setting is for Azure Public cloud, if you are using a different Azure cloud, then use az cloud list to find your storage host.

Re-run the Azure Function

  1. Start and Run the Function

Run the following command from the root of the project:

func start

When it has finished starting it will output the URL to run the function, like this:

funcblobtest: [GET,POST] http://localhost:7071/api/funcblobtest

Open that link in a browser. Your function will run and you will see output like the following:

00e7d1bd.txt uploaded.
  1. Verify Success with Storage Explorer

Open Storage Explorer and navigate to: Subscription -> Storage Accounts -> Storage Account -> Blob Containers -> azfuncblobs

Verify that your file has been successfully uploaded.

Now that we have our local function uploaded blobs to Azure Storage, lets create the Azure Function in Azure, and use a Managed Identity instead of a Service Principal. Click on the Part 3 link below to continue.

Part 1: Local Function with Storage Emulator (local function, local storage)
Part 2: Local Function with Azure Storage and Service Principal (local function, cloud storage)
Part 3: Azure Function with Azure Storage and Managed Identity (cloud function, cloud storage)

Jon