I\'m sending an email in Azure Functions using the SendGrid bindings. As part of the contents of that email, I\'d like to include a link to one of the HTTP methods in the Azure
Powershell way:
$funcKey = (Invoke-AzResourceAction `
-Action listKeys `
-ResourceType 'Microsoft.Web/sites/functions/' `
-ResourceGroupName $resourceGroup `
-ResourceName "$funcAppName/$funcName" `
-Force).default
To do this in a CI pipeline using ARM templates you need to ensure you key vault and function up are in the same resource group.
Run the below as an ARM template ensuring it is run as incremental. This will get the key from the named function and put it into the desired key vault.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"functionAppName":: {
"type": "string",
"metadata": {
"description": "The name of the function app that you wish to get the key from."
}
},
"functionName": {
"type": "string",
"metadata": {
"description": "The name of the function that you wish to get the key from."
}
},
"keyVaultName": {
"type": "string",
"metadata": {
"description": "The name of the key vault you wish to put the key in."
}
}
},
"variables": {
"functionAppName": "[parameters('functionAppName')]",
"keyVaultName": "[parameters('keyVaultName')]",
"functionName": "[parameters('functionName')]"
},
"resources": [
{
"type": "Microsoft.KeyVault/vaults/secrets",
"name": "[concat(variables('keyVaultName'),'/', variables('functionAppName'))]",
"apiVersion": "2015-06-01",
"properties": {
"contentType": "text/plain",
"value": "[listsecrets(resourceId('Microsoft.Web/sites/functions', variables('functionAppName'), variables('functionName'),'2015-08-01').key]"
},
"dependsOn": []
}
]
}
try the following two steps:
get the host master key:
GET https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourcegroupName}/providers/Microsoft.Web/sites/{functionApp}/functions/admin/masterkey?api-version=2016-08-01
Get the function keys:
GET https://{functionApp}.azurewebsites.net/admin/functions/{functionName}/keys?code={masterKeyFromStep1}
response from the step 2:
{
"keys": [
{
"name": "default",
"value": "xxxxxxxxxxxxxxxxxxxxxx"
}
],
"links": [
{
"rel": "self",
"href": "https://myFncApp.azurewebsites.net/admin/functions/myFunction/keys"
}
]
}
Update:
Note, that the step 1 requires an authorization header in the format:
Authorization: Bearer bearerToken
where a bearerToken string can be obtained from Azure Active Directory (AAD), see the following code snippet of the example:
private string AccessToken(string clientID)
{
string redirectUri = "https://login.live.com/oauth20_desktop.srf";
authContext = new AuthenticationContext("https://login.windows.net/common/oauth2/authorize", TokenCache.DefaultShared);
var ar = authContext.AcquireTokenAsync("https://management.azure.com/", clientID, new Uri(redirectUri), new PlatformParameters(PromptBehavior.SelectAccount)).Result;
return ar.AccessToken;
}
Note, that the clientID is the quid of your registered application in the AAD with an API access permission for Windows Azure Service Management API.
You can get master and function keys via HTTP using Kudu:
Example (in Powershell):
$RSGROUP="mygroup"
$WEBAPPNAME="myfunctionsapp"
$function="myfunction"
$DeploymentUrl = Get-AzWebAppContainerContinuousDeploymentUrl -ResourceGroupName $RSGROUP -Name $WEBAPPNAME
$userpass = $DeploymentUrl.split("@")[0].Replace("https://","")
$kuduCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($userpass))
$jwt = Invoke-RestMethod -Uri "https://$WEBAPPNAME.scm.azurewebsites.net/api/functions/admin/token" -Headers @{Authorization=("Basic {0}" -f $kuduCreds)} -Method GET
$masterkey=(Invoke-RestMethod "https://$WEBAPPNAME.azurewebsites.net/admin/host/systemkeys/_master" -Headers @{Authorization="Bearer $jwt"}).value
$functionkey=(Invoke-RestMethod "https://$WEBAPPNAME.azurewebsites.net/admin/functions/$function/keys" -Headers @{Authorization="Bearer $jwt"}).keys[0].value
echo $masterkey
echo $functionkey
Nuget: Microsoft.Azure.Management.Fluent API can now manage the keys:
using Microsoft.Azure.Management.AppService.Fluent;
var functionApp = AzureInstance.AppServices.FunctionApps.GetByResourceGroup(resourceGroupName, functionAppName);
foreach (var function in functionApp.ListFunctions())
{
var functionName = function.Name.Split('/')[1];
var functionKeys = functionApp.ListFunctionKeys(functionName);
functionKeys.TryGetValue(keyName, out string functionKey);
dict.Add(functionName, functionKey);
}
you can also set new keys: (pass null as secret for auto-generated key)
foreach (var function in functionApp.ListFunctions())
{
var functionName = function.Name.Split('/')[1];
var nameValue = functionApp.AddFunctionKey(functionName, keyName,null);
}
Caveat: To make this work in production, the FunctionApp Identity must have the RBAC Owner Role of the Function App. This is set on the Access Control(IAM) Blade.