如何在 ARM 模板中创建一个 azure 功能键?

how to create an azure function key in ARM template?

我整天都在为这个问题苦苦挣扎,我正在尝试从 ARM 模板创建一个 Function App 功能键。

到目前为止,我已经能够使用以下模板在主机级别创建我的功能键:

    {
      "type": "Microsoft.Web/sites/host/functionKeys",
      "apiVersion": "2018-11-01",
      "name": "[concat(parameters('appServiceName'), '/default/PortalFunctionKey')]",
      "properties": {
        "name": "PortalFunctionKey"
      }

然后我找到了几篇文章 link 表明可以通过 API 实现: https://github.com/Azure/azure-functions-host/wiki/Key-management-API

而且我能够通过这个 API 发布到: https://{myfunctionapp}.azurewebsites.net/admin/functions/{MyFunctionName}/keys/{NewKeyName}?code={_masterKey}

但我实在想不出如何在我的 ARM 模板中做到这一点! 我尝试了各种类型和名称的组合,例如:

    {
      "type": "Microsoft.Web/sites/host/functionKeys",
      "apiVersion": "2018-11-01",
      "name": "[concat(parameters('appServiceName'), '/{myfunctionName}/PortalFunctionKey')]",
      "properties": {
        "name": "PortalFunctionKey"
      }

或/functions/{myfunctionName}/PortalFunctionKey 正如某些文章中所建议的那样,我无法正常工作,找不到关于 ARM Microsoft 的太多文档。Web/sites/host/functionKeys 也一样。

有没有人成功在 ARM 模板中创建功能键(不是主机)?我很乐意听听您是如何到达那里的:)!

基本上:

非常感谢,

伊曼纽尔

要解决这个问题,你可以参考这个github问题。 First issue and second issue,这些issues都有关于如何获取ARM模板中的function key的问题

目前获取键值的示例如下所示:

"properties": {
        "contentType": "text/plain",
        "value": "[listkeys(concat(variables('functionAppId'), '/host/default/'),'2016-08-01').functionKeys.default]"
        }

或使用下面的方法获取关键对象。

"functionkeys": {
            "type": "object",
            "value": "[listkeys(concat(variables('functionAppId'), '/host/default'), '2018-11-01')]"                                                                                }
    }

你可以试试看,希望对你有帮助。

因此目前无法在 ARM 模板中创建功能级功能键。

因此,我创建了一个功能请求,如果您对此感兴趣,可以投票: https://feedback.azure.com/forums/169385-web-apps/suggestions/39789043-create-function-level-keys-for-azure-functions-in

虽然现在,我们正在通过 powershell 部署任务步骤创建功能级功能键。方法如下。

将输出参数添加到您的 ARM 模板:

  "outputs": {
    "masterKey": {
      "type": "string",
      "value": "[listkeys(concat(resourceId(resourceGroup().name, 'Microsoft.Web/sites', parameters('appServiceName')), '/host/default'), '2018-11-01').masterKey]"
    },
    "appServiceName": {
      "type": "string",
      "value": "[parameters('appServiceName')]"
    },
    "functionKeys": {
      "type": "array",
      "value": [
        {
          "functionName": "myFunctionName",
          "keys": [ "FunctionKeyName1", "FunctionKeyName2" ]
        }
      ]
    }
  }

将以下 PS 脚本文件添加到您的部署项目中:

param (
    [Parameter(Mandatory=$true)]
    [string]
    $armOutputString
)

Write-Host $armOutputString
$armOutputObj = $armOutputString | convertfrom-json
Write-Host $armOutputObj

$masterKey = $armOutputObj.masterKey.value
$appServiceName = $armOutputObj.appServiceName.value

$httpHeaders = @{
    "x-functions-key" = $masterKey
}
$contentType = "application/json; charset=utf-8"

foreach($function in $armOutputObj.functionKeys.value){

    $retryCount = 5;
    while ($true) {
        try {
            $uriBase = "https://$($appServiceName).azurewebsites.net/admin/functions/$($function.functionName)/keys"
            $existingKeys = Invoke-RestMethod -Method Get -Uri $uriBase -Headers $httpHeaders -ContentType $contentType
            break;
        }
        catch {
            if ($_.Exception.Response.StatusCode.value__ -eq 502) {
                if ($retryCount-- -eq 0) {
                    throw;
                }
                else {
                    Write-Output ("Retry" + ": " + $_.Exception.Response.StatusCode + "; attempts=$retryCount")
                    [System.Threading.Thread]::Sleep(1000);
                    continue;
                }
            }
            else {
                throw;
            }
        }
    }

    foreach ($keyname in $function.keys){
        $keyExists = 0
        foreach($exstingKey in $existingKeys.keys){
            if($exstingKey.name -eq $keyname){
                $keyExists = 1
               Write-Host  "key $($keyname) already exists"
            }
        }

        if($keyExists -eq 0){
            $uri = "$($uriBase)/$($keyname)?code=$($masterKey)";
            Write-Host  "Adding $($keyname) key"
            Invoke-RestMethod -Method Post -Uri "$($uriBase)/$($keyname)" -Headers $httpHeaders -ContentType $contentType;
        }
    }
}

脚本确保如果密钥已经存在则不会被覆盖,如果失败将重试(函数必须存在并且 运行 才能使 API 工作)。

在您的“Azure 资源组部署”任务中,在“高级”下设置“部署输出”到“armDeployOutput”。

添加一个 Powershell 任务,您的脚本路径到部署项目中的 powershell 文件,并将“Arguments”设置为“-armOutputString '$(armDeployOutput )'".

就是这样。

这可能会解决现在的问题:https://docs.microsoft.com/en-us/azure/templates/microsoft.web/2020-06-01/sites/functions/keys

我能够通过传递如下所示的 ARM 模板资源来创建功能键:

{
    "type": "Microsoft.Web/sites/functions/keys",
    "apiVersion": "2020-06-01",
    "name": "{Site Name}/{Function App Name}/{Key Name}",
    "properties": {
        "value": "(optional)-key-value-can-be-passed-here"
    }
}

看来就算属性里没有'value',那也至少得传一个空的属性对象吧