从 Azure 函数应用程序检索主机密钥

Retrieve the host keys from an azure function app

我正在尝试使用 Azure cli 编写环境脚本。我已经创建了一些函数应用程序,并想添加一个主机密钥或至少检索自动创建的默认密钥。 azure cli 对此完全不支持。

函数本身似乎有一个 api(它的文档似乎很少)允许我获取密钥,但是你需要一个密钥才能使用它所以..没有帮助.

https://github.com/Azure/azure-webjobs-sdk-script/wiki/Key-management-API

例如:https://example-functions.azurewebsites.net/admin/host/keys?code=somecodeyoualreadyknow

我看到了一些使用 webapps scm api 下载包含密钥的 json 文件的其他示例,但是我不确定如何使用此 API 进行身份验证.我有一个服务主体(用户标识、密码、租户标识),我希望不必向我的脚本添加另一个身份验证方案。

步骤如下。

  1. 假设您已经拥有 Kudu 部署凭据。 (听起来您已经知道如何执行此操作。您可以通过服务原则等通过 ARM 调用来获取它)
  2. 从 kudu 部署凭证中,您可以获得一个 JWT,它可以让您调用 Functions 键 API。
  3. 从函数API,你可以获得你所有的钥匙(包括你的主人)。

这是一个 powershell 脚本,它演示了从 Kudu 部署凭据到 Function Master 密钥的确切调用:

# You need to start with these:
$site = "YourSiteName"
$username='YourDeploymentUserName'
$password='YourDeploymentPassword'

# Now... 
$apiBaseUrl = "https://$($site).scm.azurewebsites.net/api"
$siteBaseUrl = "https://$($site).azurewebsites.net"

# For authenticating to Kudu
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password)))


# Call Kudu /api/functions/admin/token to get a JWT that can be used with the Functions Key API 
$jwt = Invoke-RestMethod -Uri "$apiBaseUrl/functions/admin/token" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method GET

# Call Functions Key API to get the master key 
$x = Invoke-RestMethod -Uri "$siteBaseUrl/admin/host/systemkeys/_master" -Headers @{Authorization=("Bearer {0}" -f $jwt)} -Method GET

$masterKey = $x.value

I do not know how to get "kudu" credentials with my service principal credentials

如果 C# 代码可以接受,我们可以使用 Microsoft.Azure.Management.ResourceManager.Fluent and Microsoft.Azure.Management.Fluent 轻松完成。以下是如何获取kudu凭证和运行密钥管理API的演示。我在本地测试它,它在我这边正常工作。

 string clientId = "client id";
 string secret = "secret key";
 string tenant = "tenant id";
 var functionName ="functionName";
 var webFunctionAppName = "functionApp name";
 string resourceGroup = "resource group name";
 var credentials = new AzureCredentials(new ServicePrincipalLoginInformation { ClientId = clientId, ClientSecret = secret}, tenant, AzureEnvironment.AzureGlobalCloud);
 var azure = Azure
          .Configure()
          .Authenticate(credentials)
          .WithDefaultSubscription();

 var webFunctionApp = azure.AppServices.FunctionApps.GetByResourceGroup(resourceGroup, webFunctionAppName);
 var ftpUsername = webFunctionApp.GetPublishingProfile().FtpUsername;
 var username = ftpUsername.Split('\').ToList()[1];
 var password = webFunctionApp.GetPublishingProfile().FtpPassword;
 var base64Auth = Convert.ToBase64String(Encoding.Default.GetBytes($"{username}:{password}"));
 var apiUrl = new Uri($"https://{webFunctionAppName}.scm.azurewebsites.net/api");
 var siteUrl = new Uri($"https://{webFunctionAppName}.azurewebsites.net");
 string JWT;
 using (var client = new HttpClient())
  {
     client.DefaultRequestHeaders.Add("Authorization", $"Basic {base64Auth}");

     var result = client.GetAsync($"{apiUrl}/functions/admin/token").Result;
     JWT = result.Content.ReadAsStringAsync().Result.Trim('"'); //get  JWT for call funtion key
   }
 using (var client = new HttpClient())
 {
    client.DefaultRequestHeaders.Add("Authorization", "Bearer " + JWT);
    var key = client.GetAsync($"{siteUrl}/admin/functions/{functionName}/keys").Result.Content.ReadAsStringAsync().Result;
  }

感谢两位的回复。使用您的答案 Mike S 并翻遍 csharp 流畅的源代码(感谢 Tom Sun),我最终得到了这个。当然需要很多代币!我开始使用的凭据是您将从 az ad sp create-for-rbac -n $name --role contributor

获得的凭据
$credentials = (ConvertFrom-Json $env:AzureCliLogin)

$tenant = $credentials.tenant
$clientId = $credentials.appId
$clientSecret = $credentials.password
$subscriptionId = "<subscription id>"

$body = @{
    "grant_type"="client_credentials";
    "client_id"=$clientId;
    "client_secret"=$clientSecret;
    "resource"="https://management.azure.com/"
}

$authInfo = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenant/oauth2/token" -Body $body -Method Post -Headers @{"Content-Type"="application/x-www-form-urlencoded"} 

$publishData = Invoke-RestMethod -Uri "https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroup/providers/Microsoft.Web/sites/$name/publishxml?api-version=2016-08-01" -Method Post -Headers @{"Authorization"="Bearer $($authInfo.access_token)"}

$userName = $publishData.publishData.publishProfile[0].userName
$password = $publishData.publishData.publishProfile[0].userPWD

$apiBaseUrl = "https://$name.scm.azurewebsites.net/api"
$siteBaseUrl = "https://$name.azurewebsites.net"

# For authenticating to Kudu
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password)))    

# Call Kudu /api/functions/admin/token to get a JWT that can be used with the Functions Key API 
$jwt = Invoke-RestMethod -Uri "$apiBaseUrl/functions/admin/token" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method GET

# Call Functions Key API to get the master key 
$x = Invoke-RestMethod -Uri "$siteBaseUrl/admin/host/systemkeys/_master" -Headers @{Authorization=("Bearer {0}" -f $jwt)} -Method GET

$masterKey = $x.value

如果您想在 bash 中执行此操作,请先参阅 this gist

我刚刚能够使用此命令将其与 Azure CLI 一起使用:

az rest --method post --uri \
"/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Web/sites/$FUNCTION_APP_NAME/host/default/listKeys?api-version=2018-11-01" \
--query functionKeys.default --output tsv

我意识到这个答案晚了几年,但它可能对现在正在搜索的人有所帮助。

如果您只想获取密钥而不需要自动执行身份验证过程:

Get-AzResource -Name RESOURCE-NAME | Invoke-AzResourceAction -Action host/default/listkeys -Force

确保您拥有最新版本的 Az 模块。

安装:

Install-Module -Name Az -Force

更新:

Update-Module -Name Az

确保在 运行 执行上述命令之一后启动新的 PowerShell window。

然后您可以在设置资源组名称和函数名称变量后运行执行以下操作:

$azureFunction = Get-AzFunctionApp -ResourceGroupName $resourceGroupName -Name $azureFunctionName
$keys = Invoke-AzResourceAction -ResourceId $($azureFunction.Id) -Action "host/default/listKeys" -Force
$defaultKey = $keys.functionKeys.default