Specify Function App Configuration with Key Vault Reference in Azure ARM Template - azure

Is there a way to specify KeyVault References in Function App configuration within my ARM template?
I have an ARM template that will deploy an Azure Function App with different deploy parameter for each environment. Currently I am retrieving the secret in my environment via references in the parameter:
{
"storageAccountSecret": {
"reference": {
"keyVault": {
"id": "/subscriptions/plan-id-goes-here/resourceGroups/group-name-goes-here/providers/Microsoft.KeyVault/vaults/vault-name-goes-here"
},
"secretName": "super-secret-name-goes-here"
}
}
I then reference the parameter in the ARM template, resources -> properties -> siteConfig -> appSettings
{
"name": "AzureWebJobsStorage",
"value": "[parameters('storageAccountSecret')]"
},
Above works fine! However, our team also periodically rotate our keys which change the underlying value of the secret. With my current approach, the secret on this function app config won't update until we run the ARM template again.
My get around is to use KeyVault Reference in the config, with the following syntax in the configuration.
#Microsoft.KeyVault(SecretUri=https://vault-name-goes-here.vault.azure.net/secrets/super-secret-name-goes-here/)
Now when the underlying secret changes, my function App will still get the up to date secret. However this require me to do it manually. I would love to achieve the same effect with just the ARM template alone, is that possible? 🤔

For exactly that reason you should always use the full URL to your secrets in Key Vault - including the version. See here.
When you update a secret in Key Vault, you get a new URL. Once you update the app setting (through your ARM template or any other way), the Function will be restarted. This is the desired behavior when updating app settings.

Related

Azure Data Factory ARM Template has empty parameter for linked service connection string

I have some problems, that I am hoping someone can help me with.
I created a bunch of resources - few linked services, few datasets and few pipe lines in the Datafactory "DevDataFactory".
One of the linked services connecting to a SQL Database is configured this way
Then in the json for that linked service the connection string is seen in this snippet:
"typeProperties": {
"connectionString": "Integrated Security=False;Encrypt=True;Connection Timeout=30;Data Source=#{linkedService().cloudDbDomain};Initial Catalog=#{linkedService().dbName};User ID=#{linkedService().dbUserName}",
"password": {
"type": "AzureKeyVaultSecret",
"store": {
"referenceName": "KeyVaultLink",
"type": "LinkedServiceReference"
},
"secretName": "DBPassword"
},
"alwaysEncryptedSettings": {
"alwaysEncryptedAkvAuthType": "ManagedIdentity"
}
}
All parameters are in place, default values are set and when
pipeline is run it asks for values.
The problem is that when I then go and export the ARM Template so to use the datafactory in another environment, there is a parameter there for this Linked Service's connection String, and this parameter value is blank. ALL AND ANY OTHER PARAMETER used in the ARM template has some default value - why does this one not have it ?
Given the parameters used inside the connection string are present and do have their own default values.
If I use the Azure Portal to import that ARM Template, I can go ahead and enter the connection string, like from the json code snippent above
Integrated Security=False;Encrypt=True;Connection Timeout=30;Data Source=#{linkedService().cloudDbDomain};Initial Catalog=#{linkedService().dbName};User ID=#{linkedService().dbUserName}
.. and everything will be imported and all my pipelines will automatically work out from the newly created datafactory.
The PROBLEM IS that I need to do this from Azure Dev Ops pipelines, which are automatically picked up from Git repo "adf-publish" branch, and this is where I don't know what to do. When ADO pipeline automatically runs, I can't just substitute the "connection string" on the fly.
I am stuck, please help !!

How to get Azure App Configuration feature flag value list in bicep template

I would like to get list of already created feature flags from Azure App Configuration in bicep template. I want to pass it to separate bicep file that will use union function on existing and new feature flags to not override already existing ones.
Simillar thing I'm already using for Web App and list() function get existing app settings:
module appConfig './webappsettings.bicep' = {
name: '${deployment().name}-appSettings'
params: {
webAppName: webapp.name
currentAppSettings: list('${webapp.id}/config/appsettings', '2021-03-01').properties
appSettings: allSettings
}
}
How can I achieve something similar for Azure App Configuration to get key values of feature flags?
I tried with below solution but I only got key values of App Configuration
resource configurationStore 'Microsoft.AppConfiguration/configurationStores#2021-10-01-preview' existing = {
name: 'appcfg'
}
module configStoreKeyValues 'inner.bicep' = {
name: 'config-store'
params: {
existingKeyValues: configurationStore.listKeys().value
keyValues: keyValues
contentType: contentType
}
}
using same list() function or listKeys()
list('${configurationStore.id}/keyValues','2021-10-01-preview').properties
I'm getting an error:
Status Message: The resource namespace 'subscriptions' is invalid. (Code:InvalidResourceNamespace)
The "List" operation of key-values is not supported by the control-plane REST API in App Configuration. The listKeys API you used above returns the "Access keys", not the key-value configuration data you are looking for. You can create/update/read individual key-value, feature flag, Key Vault reference as KeyValues resource using Bicep. Feature flag is a special key-value with certain key prefix and content type. Below is an example of feature flag using the ARM template, but it should give you an idea of how to do the same in Bicep.
https://azure.microsoft.com/resources/templates/app-configuration-store-ff/
Note that the "List" operation of key-values is supported in the data-plane REST API of App Configuration. Besides the REST API, it's also accessible via Azure CLI, Azure portal, and App Configuration SDKs programmatically.

How is secrets resolved when using environment variable reference in a Azure WebApp

I have an environment variable that references a secret in Azure KeyVault:
{
"name": "SECRET",
"value": "#Microsoft.KeyVault(SecretUri=https://keyvault_name.vault.azure.net/secrets/secret_name/)",
"slotSetting": false
}
This is loaded when on Startup.cs in my web api solution:
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions<Secret>().Configure(o => o.ClearText = Configuration["SECRET"]);
services.AddControllers();
}
How is the secret resolved? Is it resolved on every option call? Eg everytime it gets injected into my constructor, or is it resolved when the environment variable is resoved and loaded into the Configuration object?
Reason why I ask is that every call to the vault costs a tiny bit, but it all adds up.
UPDATE
I have added this as an issue on github: https://github.com/MicrosoftDocs/azure-docs/issues/44064#event-2855607916
Based on my testing, Azure web app will load data from Azure key vault in two scenarios :
You submitted a Application settings modify request to Azure.
You restart your Azure Web app.
Your secret will be cached in Azure app service. You can try this scenario : After you add an environment variable that references a secret in Azure KeyVault , create a new version with different value in Azure key vault , you will found that the value in Azure web app will not change : still the old version.
It will not change until you restart your web app or modify your Application settings on portal again.
I also checked metrics of my Azure key vault, I called my Azure web app to retrieve the secret I configed in app settings for about 10 times , but the access metrics of my Azure key vault at that time point is 0. But when I restart my web app , the access metrics of Azure key vault will increase .
Hope it helps .

ARM Template: Looking up a user object Id

I'm trying to programatically insert the object Id of a certain user account into an ARM template, like this:
"objectId": "[reference(resourceId('Microsoft.AAD/domainServices/user/read','domain','User.Name'),'2019-01-01').Id]",
I've tried many different resource providers in an attempt to get this to work. For example:
"objectId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/read','user#domain.onmicrosoft.com'),'2019-01-01').Id]",
and:
"objectId": "[reference(resourceId('Microsoft.Portal/usersettings/read','user#domain.onmicrosoft.com'),'2018-10-01').Id]"
I looked up the API call used to get a list of users, to see if that would hint at the correct provider to use (it didn't):
GET https://graph.windows.net/{TenantId}/users?api-version=1.6 HTTP/1.1
I've been looking through this list of provider operations but have found two problems with this:
1 I can't see an operation which looks relevant to what I want to do.
2 It doesn't provide information on what parameters are required.
So I guess I have two questions really:
How do I dynamically look up the ObjectId of a user in an ARM template?
How do I find out in future which lookup functions are available and which parameters are required?
You could not insert the user object Id in the ARM template.
The user account is managed by your Azure AD tenant, it is not the azure resource, the ARM template is for the azure resources in your subscription.
Reference:https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-overview
Azure Resource Manager is the deployment and management service for Azure. It provides a consistent management layer that enables you to create, update, and delete resources in your Azure subscription.
You can try from below code if you have VM in same template and enabled managed identity
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-template-functions-resource#remarks-1
{
"type": "Microsoft.KeyVault/vaults",
"properties": {
"tenantId": "[reference(concat('Microsoft.Compute/virtualMachines/', variables('vmName')), '2017-03-30', 'Full').identity.tenantId]",
"accessPolicies": [
{
"tenantId": "[reference(concat('Microsoft.Compute/virtualMachines/', variables('vmName')), '2017-03-30', 'Full').identity.tenantId]",
"objectId": "[reference(concat('Microsoft.Compute/virtualMachines/', variables('vmName')), '2017-03-30', 'Full').identity.principalId]",
"permissions": {
"keys": [
"all"
],
"secrets": [
"all"
]
}
}
]
I find the best way to achieve this is to expose the ID as a parameter, then when you call the ARM template deployment, simply pass the parameter into the template.
How do you get the ID into the template parameter? Well, I run my ARM deployments via Azure DevOps CI/CD and I use the pipeline task AzureAppConfiguration.azure-app-configuration-task.custom-build-release-task.AzureAppConfiguration#1 to extract the ID from my own custom configuration setup.
How do you get the ID into the Azure App Configuration service? Well, when I seed an environment for the first time there will be some initial setup, e.g. users and groups. I just then run some scripts to extract this kind of "metadata" into my Azure App Configuration service.
e.g.
APP_ID=$(az ad sp list --all --query "[?displayName=='name-of-spn'].appId" --output tsv)
az appconfig kv set --name name-of-app-config-store --key name-of-spn-app-id --value ${APP_ID}
I think I have solution.
I am tying to refer to a Client ID in a Managed User Identity generated by an ARM template.
I have declared the name of the Managed Identity as a Parameter to use as an administrator for an SQL server:
[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities',parameters('managed-identity')), '2018-11-30', 'full').properties.clientId]
Once you switch our the parameter you should be good to go.

Create database account on Azure with specific password using ARM templates

I want to run Azure Resource Group Deployment as part of my deployment process. This should create two resources: App Service (asp.net core) and DocumentDB account.
After that I need to store account credentials (account name and password) in App Settings block of my App Service. Normally I could configure App Service to read the password from existing Azure Key Vault.
But if the database account is not created yet, the password is generated automatically and I would need to update it manually.
Is it possible to create the database account specifying the password (reading value from Key Vault)? This way the deployment would be automated whether the database account was created or not.
I don't see where's the problem in this one, just specify the secret in your template:
"parameters": {
"adminPassword": {
"reference": {
"keyVault": {
"id": "/subscriptions/{guid}/resourceGroups/{group-name}/providers/Microsoft.KeyVault/vaults/{vault-name}"
},
"secretName": "sqlAdminPassword"
}
}
}
https://azure.microsoft.com/en-us/documentation/articles/resource-manager-keyvault-parameter/

Resources