Azure function + Key Vault (secrets)
Not long ago, if you had a website that required some periodic task, WebJobs were the "go to" answer. Well, at least they were for me. They packaged nicely with the site. However, I was never a big fan overall. You HAD to have a website to have a WebJob. I wanted some periodic thingy out in the cloud that did some periodic maintenace.
Azure Functions are a really cool technology. You can run them "serverless" and get billed by resource consumption only which makes them super ideal to use as replacements for WebJobs... especially for periodic tasks.
In my case, I had a WebJob that needed access to an Azure Key Vault to snag some secret values. Porting the code was trivial.
Debugging locally was mostly trivial. I did need to supply some credentials. It started with something as simple as this:
var client = new SecretClient(new Uri("https://your-vault-here.vault.azure.net"), new DefaultAzureCredential());
Locally, this worked fine. However, when I deployed to the cloud, it didn't work. Google to the rescue and I found I needed to apply a managed identity. This seemed really simple. I went here...
Just by setting that switch from Off to On, Azure kindly creates a managed identity and associates it with the app. Looks like this:
From there, you simply need to grant that managed identity access to use the key vault. So, make note of that Object (principal) ID and go over here:
I've already got some Access policies assigned in this key vault, but you may not have anything assigned. Doesn't matter. What matters is you're on the correct screen to make the assignment. Click on the "Create" button. In my case, I only need read access for a secret and nothing else so applying the concept of least privilege, we get:
Click "Next".
Here's where you assign the service principal to the policy. You've created a policy that allows Get access to secrets. You might think if you've already got such a policy, why not just add as many principals to that policy as you'd like. Microsoft says "nay nay". "Only 1 principal can be assigned per access policy."
OK - so I search for the newly created managed identity. It may have a silly name as it is system created. You can also search by that GUID I said to remember.
Note that the GUID for the principal is different than the GUID I used to search. That's fine. Select that principal; you're just seeing a different ID. (Don't remember which) Since you've selected the system generated SP, you'll get this:
Next, go to Review + Create and let it go. Once done, your Function App should now be able to access the key vault.
HOWEVER, there be dragons here.
Ya gotta read the fine print. Check it out on this page where you added the System assigned SP:
So it'll work - until you deploy a new build and then it's worthless.
Didn't love it.
The workaround is to simply create your own service principal and do the whole key vault thing.
Here's how.
Go create a managed identity. Just search for "Managed Identity" in the portal if you can't readily find it. None of the redacted stuff is particularly important - just remember the name you pick. This will ultimately be the name under which your function runs.
Click "Review + Create" and run it through.
Wait for deployment. It's quick.
Go back to the key vault. Add the access policy as before.
Now, go back to the Function App.
Click "Add", search for your shiny new managed identity and apply.
You'd THINK that's all there is. But it's not.
Turns out, when you create a system generated managed identity, the portal sneaks in a setting in configuration called AZURE_CLIENT_ID. This is what maps the managed identity to the application. When you do this by hand, it DOES NOT. Which means everything looks like it should work, but it doesn't. Failed validations galore.
So, go the dashboard of your function app and go to Configuration.
Add that AZURE_CLIENT_ID and set the value of the setting to the value of the Client ID from the managed identity - which you can get by clicking on the hyperlink for the user assigned managed identity in the Function App/Identity page.
Gets you here...
DON'T FORGET TO SAVE the Application Configuration once you've added the AZURE_CLIENT_ID setting.
After saving, wait a little while, and see if you're not up and running properly. If you've built the app with application insights enabled, you can just nav to the log stream window from the "Monitoring" section of the Function App overview page. Looks like this:
If you've implemented logging, you can throw in some log statements here and there to monitor what's going on and ensure that you now have access to the key vault as necessary.
And now... coffee.
Comments
Comments are closed