skip to Main Content

I’m trying to change an Azure function app which currently uses a System Assigned identity to connect to a KeyVault to a User Assigned Managed Identity. The UAMI has the correct permissions to the KeyVault , but I’m struggling with the sparesly documented keyVaultReferenceIdentity property in bicep. Below is the code for my module.

param uamiId string=''

resource functionApp 'Microsoft.Web/sites@2021-03-01' = {
  name: functionAppName
  location: 'uks'
  kind: 'functionapp'
  identity: empty(uamiId)? {
    type: 'SystemAssigned'
  }:{
    type: 'UserAssigned'
    userAssignedIdentities: {
      '${uamiId}': {}
    }
  }
  properties: {
    serverFarmId: appPlansprimaryId
    siteConfig: {
      ftpsState: 'FtpsOnly'
      minTlsVersion: '1.2'
      use32BitWorkerProcess : false// 64 bit
      keyVaultReferenceIdentity: uamiId
    }
    httpsOnly: true
    keyVaultReferenceIdentity: uamiId
  }
}

I don’t understand why the keyVaultReferenceIdentity is in two places. If I comment out the first reference, the app does reference it in JSON view, but only in one place, the other reference to it in the JSON config is null. If I deploy the bicep script with both references, the deployment completely screws p and it changes back to SystemAssigned in the JSON view. Are both needed? Is something else needed? There seems to be no way of doing this via the portal. The only pointer I can find is this post which suggests a powershell script https://stackoverflow.com/a/72531566/30512

2

Answers


  1. Chosen as BEST ANSWER

    I gt this working by using only the in the properties block:

    properties: {
        serverFarmId: plan.id
        siteConfig: {
          ftpsState: 'FtpsOnly'
          minTlsVersion: '1.2'
          use32BitWorkerProcess : false
          //keyVaultReferenceIdentity: identity.id // don't need this one
        }
        keyVaultReferenceIdentity: identity.id
        httpsOnly: true
      }
    

    Then specifying the correct managed identity ID in the AZURE_CLIENT_ID app setting and grabbing this to pass as a connection string to the keyvault. This is the Client ID, not the Principal ID:

    private static async Task<SecretBundle> GetSecret(KeyVaultClient keyVaultClient, string secretName)
    {
        return await keyVaultClient.GetSecretAsync(SecretUri(secretName));
    }
    public static string SecretUri(string secret)
    {
        return (Environment.GetEnvironmentVariable("kvUri")+"/Secrets/"+secret).Replace("//Secrets", "/Secrets");
    }
    
    ...
    
    var serviceTokenProvider = new AzureServiceTokenProvider(connectionString: "RunAs=App;AppId="+ Environment.GetEnvironmentVariable("AZURE_CLIENT_ID"));
    var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(serviceTokenProvider.KeyVaultTokenCallback));
    var mySecret = await GetSecret(keyVaultClient, "NameOfMySecret");
    

    The app setting kvUri is the full name of the KV - eg: https://mykeyvault.vault.azure.net/


  2. Purpose of keyVaultReferenceIdentity in two places:

    1. Firstly, keyVaultReferenceIdentity under properties block is for specifying the User Managed Identity that will be used by the function app during runtime for interactions with the Key Vault, like retrieving or updating secrets.

    2. The keyVaultReferenceIdentity under site config block is used to specify the User Managed Identity that can be used specifically for accessing Key Vault references within the function app’s configuration settings.

    Note: Adding to the above, including keyVaultReferenceIdentity field is completely depends on your requirement. Adding keyVaultReferenceIdentity only in the properties block will also be sufficient to achieve your output.

    Coming to your bicep code, you need to pass identity id keyVaultReferenceIdentity: uamiId.id with key vault reference field but not keyVaultReferenceIdentity: uamiId.

    Modified code has given below.

    param uidentity string = 'newuser'
    param location string = resourceGroup().location
    param functionappname string = 'latestfuncj'
    param appServicePlanName string = 'newjpla'
    
    resource identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
       name: uidentity
       location: location
    }
    
    resource plan 'Microsoft.Web/serverfarms@2021-02-01' = {
      name: appServicePlanName
      location: location
      kind: 'functionapp'
      sku: {
        name: 'Y1'
      }
      properties: {
      }
    }
    
    resource functionapp 'Microsoft.Web/sites@2021-01-01' = {
      name: functionappname
      location: location
      kind: 'functionapp'
      identity: {
        type: 'UserAssigned'
        userAssignedIdentities: {
          '${identity.id}' : {}
        }
      }
      properties: {
        serverFarmId: plan.id
        siteConfig: {
          ftpsState: 'FtpsOnly'
          minTlsVersion: '1.2'
          use32BitWorkerProcess : false
          keyVaultReferenceIdentity: identity.id
        }
        keyVaultReferenceIdentity: identity.id
        httpsOnly: true
      }
    }
    

    Deployment succeeded:

    enter image description here

    References:

    Blog | Larry Claman

    Complete Bicep code for deploying an Azure Function app with Key Vault references.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search