在运行时从Azure函数获取Azure函数键?

时间:2018-08-08 15:43:54

标签: c# azure azure-functions

我正在使用SendGrid bindings在Azure Functions中发送电子邮件。作为该电子邮件内容的一部分,我想在Azure Functions实例中包括指向HTTP methods之一的链接以获取更多信息。我的所有HTTP函数都由AuthorizationLevel.Function保护。

我已经看到了scraping the keys from ARM and Kudu in PowerShell(和this one)的解决方案以及output the keys with just ARM的解决方案,但是它们都依赖于我的Azure Functions不具备的功能:对ARM的权限(Azure资源管理)API。

我还发现Key management APIs for the Azure Functions host完全可以在本地运行,但是我不知道在部署Azure功能后如何克服401 Unauthorized的问题。我可以使用_master功能键手动克服它,但是我又回到了不知道如何在运行时获取该键的地方。

问题是这样的:是否有可能在运行时从Azure Function Host获取Azure Function的密钥?我非常希望不需要ARM权限来做到这一点。

5 个答案:

答案 0 :(得分:2)

尝试以下两个步骤:

  1. 获取主机主密钥:

    GET https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourcegroupName}/providers/Microsoft.Web/sites/{functionApp}/functions/admin/masterkey?api-version=2016-08-01
    
  2. 获取功能键:

    GET https://{functionApp}.azurewebsites.net/admin/functions/{functionName}/keys?code={masterKeyFromStep1}
    

第2步的响应:

    {
      "keys": [
        {
          "name": "default",
          "value": "xxxxxxxxxxxxxxxxxxxxxx"
        }
      ],
      "links": [
        {
          "rel": "self",
          "href": "https://myFncApp.azurewebsites.net/admin/functions/myFunction/keys"
        }
      ]
 }

更新

请注意,第1步要求使用以下格式的授权标头:

Authorization: Bearer bearerToken

可以从Azure Active Directory(AAD)获得bearerToken字符串的地方,请参见示例的以下代码片段:

    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;
    }

请注意, clientID 是您在AAD中注册的应用程序的quid,具有对 Windows Azure Service Management API 的API访问权限。

答案 1 :(得分:1)

Powershell方式:

exports.FilelamdaFunctionHandler = async function(event, context){
    try {        
        let contentType = event.headers['Content-Type']
        console.log('content type is--' + contentType)
        contentType = contentType.split("/")[1]
        let type = (contentType == 'plain') ? ".txt" : ".csv"
        const params = {
            Body: event.body,
            Bucket: bucketName + "/" + event.pathParameters.hospital,
            Key: event.pathParameters.hospital + type,
            ContentType: "*"
        };
        const results = await s3.putObject(params).promise();
        console.log('resultss --' + JSON.stringify(results);
    } catch(error) {
        console.log('errors in promise' + error)
        console.log('e--' + error.toString())
        console.log('errorororooror' + JSON.stringify(error));
        const response = {
            'statusCode':500,
            'body':"error"
        }
        return response;
    }       
    
    console.log('second')
    const response = {
        'statusCode':200,
        'body':"sucess"
    }
    return response;
}

答案 2 :(得分:0)

要在使用ARM模板的CI管道中执行此操作,您需要确保密钥库和启动功能在同一资源组中。

  1. 使用ARM部署功能应用程序
  2. 将功能部署到功能应用程序-更新此代码以从keyvault中查找密钥,就像您提到的为SendGrid API密钥所做的那样
  3. 将以下内容作为ARM模板运行,确保以增量的身份运行。这将从指定的函数中获取密钥,并将其放入所需的密钥库中。

    {
        "$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": []
            }
        ]
    }
    

答案 3 :(得分:0)

Nuget: Microsoft.Azure.Management.Fluent API 现在可以管理密钥:

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);

}

您还可以设置新键: (将null作为自动生成的密钥的秘密传递)

foreach (var function in functionApp.ListFunctions())
{
    var functionName = function.Name.Split('/')[1];
    var nameValue = functionApp.AddFunctionKey(functionName, keyName,null);
}

注意事项:要在生产环境中使用此功能,FunctionApp标识必须具有Function App的RBAC所有者角色。这是在访问控制(IAM)刀片服务器上设置的。

答案 4 :(得分:0)

您可以使用Kudu通过HTTP获取主键和功能键:

示例(在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