Skip to content

Commit 7d7403b

Browse files
committed
adds new post
1 parent b536b16 commit 7d7403b

12 files changed

+174
-0
lines changed
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
---
2+
title: "How to migrate to Managed Identities and test locally with local debug!"
3+
date: "2025-01-21"
4+
redirect_from : /How-to-migrate-an-Azure-Function-app-to-use-a-Managed-Identity
5+
coverImage: \assets\images\2025\howtomigratetotestmanagedidentities.png
6+
categories:
7+
- "programming"
8+
tags:
9+
- "AzureFunctions"
10+
- "ManagedIdentity"
11+
excerpt: "Recently I came upon the need to harden how some Azure Functions were setup. Specifically, they were Azure Functions setup to fire and run some c# code when a message was dropped into a message queue. They worked great, but we would much rather use the security of a Managed Identity to connect, instead using of using a connection string. This guide will cover migrating a function over to using a managed identity AND also how to do this on local dev"
12+
fileName: '2025-01-21-how-to-migrate-an-azure-function-app-to-use-a-managed-identity.md'
13+
---
14+
Recently I came upon the need to harden how some Azure Functions were setup. Specifically, they were Azure Functions setup to fire and run some c# code when a message was dropped into a message queue. They worked great, but we would much rather use the security of a Managed Identity to connect, instead using of using a connection string.
15+
16+
![Header for this post, reads how to migrate an azure function to managed identities with local debug](<../assets/images/2025/howtomigratetotestmanagedidentities.png>)
17+
18+
19+
So, the process I took here was to first build a new Function App of type Queue Trigger, and configure it to use a Connection String to connect.
20+
21+
Once I had my Queue Trigger created, I looked at the docs for Azure Functions to see the requirements for using Managed Identities.
22+
23+
[Docs Link](https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference?tabs=blob&pivots=programming-language-csharp#configure-an-identity-based-connection)
24+
25+
According to these docs, I need to update to Azure Queues Extension version 5.0.0 or later, so I did that first.
26+
27+
Next, the docs say that to configure Azure Functions to use an MSI instead of an environmental variable for connectionString, we simply add a new variable to our `local.settings.json` file.
28+
29+
30+
```local.settings.json
31+
{
32+
"IsEncrypted": false,
33+
"Values": {
34+
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
35+
"AzureWebJobsStorage__queueServiceUri": "https://testorageaccount22.queue.core.windows.net/testiam"
36+
}
37+
}
38+
```
39+
40+
I added the `AzureWebJobsStorage__queueServiceUri` value, this is just set to the storage account I am using. According to the docs, when you're using Azure Function Extensions v5 or higher, setting this config value instructs the Azure Function runtime to try and connect using a MSI.
41+
42+
>To me, this is extremely non-intuitive and very confusing, but that's how it's done right now.
43+
44+
Next, I updated the signature of my function to be sure it is referencing the value from my settings file.
45+
46+
```c-sharp
47+
//from
48+
//public void Run([QueueTrigger("testiam2", Connection = "connectionString")] QueueMessage message)
49+
50+
//to
51+
public async Task MsiQueueAccess([QueueTrigger("testiam", Connection = "AzureWebJobsStorage")] QueueMessage message)
52+
53+
```
54+
55+
Note how the Connection contains 'AzureWebJobsStorage', while the same settings prefix is found in the `json` file as well. That specific value is what triggers the new MSI features.
56+
57+
58+
So let's see what happens when I fire it up!
59+
60+
![alt text](<../assets/images/2025/fails on startup.png>)
61+
62+
```
63+
Host lock lease acquired by instance ID '000000000000000000000000527A19E4'.
64+
[2025-01-22T16:48:16.609Z] An unhandled exception has occurred. Host is shutting down.
65+
[2025-01-22T16:48:16.612Z] Azure.Identity: ManagedIdentityCredential authentication failed: Service request failed.
66+
[2025-01-22T16:48:16.614Z] Status: 503 (Service Unavailable)
67+
[2025-01-22T16:48:16.615Z]
68+
[2025-01-22T16:48:16.616Z] Content:
69+
[2025-01-22T16:48:16.616Z] {"error":"service_unavailable","error_description":"Service not available, possibly because the machine is not connected to Azure or the config file is missing. Error: missing required agent config properties. Current agent config: {Subscriptionid: Resourcegroup: Resourcename: Tenantid: Location: VMID: VMUUID: CertificateThumbprint: Clientid: Cloud: PrivateLinkScope: Namespace: CorrelationID: ArmEndpoint: AtsResourceId: AuthenticationEndpoint:} (config file location: C:\\ProgramData\\AzureConnectedMachineAgent\\Config\\agentconfig.json). Connection status: Disconnected. Check Agent log for more details.","error_codes":[503],"timestamp":"2025-01-22 11:48:16.5491276 -0500 EST m=+544299.660283901","trace_id":"","correlation_id":"97f841ea-68cd-4521-8278-3e8537341acf"}
70+
```
71+
72+
### Do I even have a Managed Identity Yet?
73+
74+
Hmm, that does not look like success. I noticed that the Subscription, Rg and all of those fields are all empty, likely because my dev laptop does not have an MSI on it. I was assuming this would be smart enough to try and use the same flow as DefaultAzureCredential, but I guess not.
75+
76+
So let's instead enroll my machine in ARC to see what happens when there is an MSI associated...
77+
78+
With that done I can now view the resource in Azure and see the Managed Identity which was created for me.
79+
80+
You can view the MSI created for an Arc device by looking at the 'Resource JSON view', and see it's GUID.
81+
82+
![alt text](../assets/images/2025/arcManagedIdentity.png)
83+
84+
Now, to go to my storage account and give this identity (which Helpfully I can assign just by the name of the machine, not the guid displayed) some permissions to interact with the storage account.
85+
86+
I assigned it 'Storage Blob Data Owner' perms and then restarted the app.
87+
88+
![alt text](../assets/images/2025/addMsi-StorageBlobDataOwnerPerm.png)
89+
90+
Now I have a different problem, instead of an error saying that I don't have an Managed Identity, I get this error that I can't access the Tokens directory.
91+
92+
![alt text](../assets/images/2025/addPermsToReadKeys.png)
93+
94+
To fix this, I navigated to the directory and gave myself owner rights (suitable for debugging, and not needed in prod when this is deployed to a *real worker* with a *real MSI*).
95+
96+
And now a different error. The storage account does not exist?
97+
98+
![error message says 'Azure.Storage.Queues: the requested URI does not represent any resource on the server'](../assets/images/2025/theUriDoesNotRepresent.png)
99+
100+
OH I had the format of the URL incorrect, it should not include the name of the queue as I had done.
101+
102+
```
103+
Before
104+
"AzureWebJobsStorage__queueServiceUri": "https://testorageaccount22.queue.core.windows.net/testiam"
105+
106+
After
107+
"AzureWebJobsStorage__queueServiceUri": "https://testorageaccount22.queue.core.windows.net/"
108+
```
109+
And now to restart once more...and now a new error!
110+
111+
![error code: AuthorizationPermissionMismatch, the request is not authorized to perform this operation using this permission](../assets/images/2025/permissionsMismatch.png)
112+
113+
114+
I thought about it and realized I granted Azure Blob Storage Data owner perms but don't recall doing anything related to queues, so lets try adding that too. I specifically added the `Azure Queue Storage Contributor` role this time and when I fire it up....
115+
116+
Success!
117+
![alt text](../assets/images/2025/success.png)
118+
119+
## Quick Takeaways
120+
The big takeaways here are:
121+
122+
- It IS possible to test Managed Identities on a normal dev machine or laptop, you'll just need to enroll the machine in Arc to assign a managed identity
123+
- You can use the automatic System Assigned MSI for your machine or any user created MSI
124+
- You will need to assign these permissions to the Managed Identity
125+
- - Subscription Reader for the sub holding the Storage Account
126+
- - Storage Data Owner permission for the Storage Account
127+
- - Storage Queue / Table / Blob Contributor for the Storage Account
128+
- When assigning to Prod, instead use User Assigned Managed Identities so one MSI can be shared on your prod devices within a region, for ease of management
129+
130+
Some other weird takeaways is that all of this is configured using appSettings.json files, and namely some properties with very unintuitive names, like `AzureWebJobsStorage_StorageAccountUri`. To me, this feels like something that will likely change in a future release, so I would keep my eyes on this area.
131+
132+
## TLDR
133+
134+
The three most important things are:
135+
* be sure you upgrade to Extensions version 5 or higher
136+
* change your Queue Triggers Connection parameter to match the *prefix* of the setting in your json file (see example image below)
137+
* go to your `local.setttings.json` file and add a setting of `prefix___queueServiceUri` for queues, or the other values for other types of Azure Storage based triggers
138+
139+
Service Type | Value
140+
--|--
141+
Azure Blob Service | AzureWebJobsStorage__blobServiceUri
142+
Azure Queues | AzureWebJobsStorage__queueServiceUri
143+
Azure SQL Tables | AzureWebJobsStorage__tableServiceUri
144+
145+
## Wait, prefix what?
146+
147+
I know, I know, this stuff was rather hard for me to understand too and took a half a day to figure it out.
148+
149+
150+
![alt text](../assets/images/2025/tldr.png)
66.8 KB
Loading
118 KB
Loading
113 KB
Loading
150 KB
Loading
139 KB
Loading
3.15 MB
Loading
94.8 KB
Loading

assets/images/2025/success.png

88.9 KB
Loading
105 KB
Loading

0 commit comments

Comments
 (0)