Azure / azure-functions-host

The host/runtime that powers Azure Functions
https://functions.azure.com
MIT License
1.93k stars 440 forks source link

Storage Binding using Managed Identity instead of ConnectionString? #6423

Closed dedreira closed 2 years ago

dedreira commented 4 years ago

Is your question related to a specific version? If so, please specify:

What language does your question apply to? (e.g. C#, JavaScript, Java, All)

All

Question

Hi! Is there a possibility to use a blob storage binding against a blob storage using the Managed Service Identity of the Azure Function? I'm checking the documentation and there are only examples of defining the binding using the Storage Account Connection String....

Thanks

balag0 commented 3 years ago

Regarding Malformed SCM_RUN_FROM_PACKAGE when uploading built content, I think the problem is remote build is not compatible with Managed Identity currently. Similar issue exists if the app is using KeyVault reference for AzureWebjobsStorage as well. The problem is at deployment time and not runtime. So potential mitigation is to build the app locally and set WEBSITE_RUN_FROM_PACKAGE to the ExternalUrl containing the built app contents.

Tracking issue to support RunFromPackage = 1 which will sidestep these issues. - https://github.com/Azure/azure-functions-host/issues/7547

spmanjunath commented 3 years ago

@paulbatum I deployed the azure function (with the objective of secretless configuration) using ARM templates with the following configuration,

Few issues that were noticed,

  1. Azure host keys (_master and default) were not generated
  2. It was not possible to generate new keys as it was resulting in error - "Failed to create test: Encountered an error (InternalServerError) from host runtime."

From my test it appears that for Azure Function to automatically generate keys it requires valid storage connection string value in AzureWebJobsStorage (and keys which are appear default). Am i making some error in deployment, or, is this shortcoming of current version of secretless capability?

knervous commented 3 years ago

Will this be available for dotnet-isolated at some point as well?

paulbatum commented 3 years ago

@spmanjunath I was not able to reproduce this. I forced my secretless function app to regenerate keys by deleting the azure-webjobs-secrets container and then I regenerated a key using the portal and everything worked fine. I am wondering if there is any difference here based on the sequence of steps? In the guide I linked above, I created the app without azure files but it did have a full storage connection string, which I then replaced later with just the account name. I am not familiar with how to assign a system identity as part of the ARM template so I have not tried to make a template that creates a secretless app "from the beginning".

@knervous yes. Some updated NuGet packages are coming for using the 5.x extensions in .NET isolated, and that should be sufficient.

fabiocav commented 3 years ago

@knervous the packages for the .NET Isolated model have been published. You'll find new major versions of the packages you're already using mapping directly to their in-proc counterparts (e.g. https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Extensions.Storage/5.0.0-beta.4)

knervous commented 3 years ago

@paulbatum @fabiocav Thank you very much! Perfect timing as I was just starting to implement this use case last week, everything is working as intended on our end

iscottb122 commented 3 years ago

@paulbatum

We have a similar (or perhaps the same) problem as the above, and with my current understanding it is a complete blocker on properly using the nice secretless/managed identity features in the new packages from @fabiocav. It is interesting to hear from @knervous that these packages work well at runtime, but perhaps he is deploying from Visual Studio or something, as I can't see any sensible way to get past the code deployment stage from an automated script or CI.

In your response to @spmanjunath you mention your manual sequence of steps, and difficulty with creating a secretless app "from the beginning", so the following should cleanly reproduce the issue and demonstrate the problem.

az deployment group create --resource-group myresourcegroup --template-file ./azuredeploy.json --parameters functionName="myfunctionapp"

azuredeploy.json ```json { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "functionName": { "type": "string" } }, "variables": { "storageName": "[concat('storage', uniqueString(resourceGroup().id))]" }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2021-02-01", "name": "[variables('storageName')]", "location": "[resourceGroup().location]", "kind": "StorageV2", "sku": { "name": "Standard_LRS" } }, { "type": "Microsoft.Web/serverfarms", "apiVersion": "2020-12-01", "name": "[parameters('functionName')]", "location": "[resourceGroup().location]", "kind": "functionapp,linux", "properties": { "reserved": true }, "sku": { "name": "Y1" } }, { "type": "Microsoft.Insights/components", "apiVersion": "2015-05-01", "name": "[parameters('functionName')]", "location": "[resourceGroup().location]", "kind": "web", "tags": { "[concat('hidden-link:', resourceId('Microsoft.Web/sites', parameters('functionName')))]": "Resource" }, "properties": { "Application_Type": "web", "ApplicationId": "[parameters('functionName')]" } }, { "type": "Microsoft.Web/sites", "apiVersion": "2020-12-01", "name": "[parameters('functionName')]", "location": "[resourceGroup().location]", "kind": "functionapp,linux", "dependsOn": [ "[resourceId('Microsoft.Storage/storageAccounts', variables('storageName'))]", "[resourceId('Microsoft.Web/serverfarms', parameters('functionName'))]", "[resourceId('Microsoft.Insights/components', parameters('functionName'))]" ], "identity": { "type": "SystemAssigned" }, "properties": { "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('functionName'))]", "siteConfig": { "appSettings": [ { "name": "AzureWebJobsStorage__accountName", "value": "[variables('storageName')]" }, { "name": "FUNCTIONS_EXTENSION_VERSION", "value": "~3" }, { "name": "FUNCTIONS_WORKER_RUNTIME", "value": "dotnet-isolated" }, { "name": "APPINSIGHTS_INSTRUMENTATIONKEY", "value": "[reference(resourceId('Microsoft.Insights/components', parameters('functionName')), '2015-05-01').InstrumentationKey]" } ] } } }, { "type": "Microsoft.Storage/storageAccounts/providers/roleAssignments", "name": "[concat(variables('storageName'), '/Microsoft.Authorization/', guid(resourceId('Microsoft.Web/sites', parameters('functionName')), 'StorageBlobDataOwner'))]", "apiVersion": "2021-04-01-preview", "dependsOn": [ "[resourceId('Microsoft.Web/sites', parameters('functionName'))]" ], "properties": { "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", "principalId": "[reference(resourceId('Microsoft.Web/sites', parameters('functionName')), '2020-12-01', 'Full').identity.principalId]", "scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageName'))]" } } ] } ```

This ARM template creates a function app with SystemAssigned managed identity and blob data ownership of a storage account. It deploys fine and I believe follows all the new required configuration and current best practices for secretless function apps.

However, when deploying code to this function app, either using Azure/functions-action on Github, or manually using the following Azure CLI command, the deployment fails due to the lack of an AzureWebJobsStorage setting.

az functionapp deployment source config-zip --resource-group myresourcegroup --name myfunctionapp --src myfunction.zip

myfunction.csproj ```csproj ... v3 <_FunctionsSkipCleanOutput>True net5.0 ... ... ```

The AzureWebJobsStorage__accountName setting alone does not seem to do anything useful at deployment time, so there is no way to actually have a secretless app (which was the whole point of all this). Please advise if we are doing something obviously wrong, because it currently looks like there is no reasonable way to deploy code, making all of the good work on the function worker extensions slightly pointless so far.

(Perhaps this new PR from @balag0 fixes everything above, in which case I look forward to its acceptance and release.)

paulbatum commented 3 years ago

@iscottb122 thanks for these repro steps - super clear. I was able to repro the problem. This won't be fixed by Bala's PR. We need another set of changes in the CLI. You can see this code is looking explicitly for the AzureWebJobsStorage setting:

https://github.com/Azure/azure-cli/blob/d1676f65bc643396ea1f562ac29cf2c66cd55d05/src/azure-cli/azure/cli/command_modules/appservice/custom.py#L539-L545

I filed the following CLI issue: Azure/azure-cli#25375

karavar commented 3 years ago

Do you have any idea if WEBSITE_CONTENTAZUREFILECONNECTIONSTRING will support managed identity in the near feature? E.g. if Azure Files will support it or if Azure Functions will move to a storage technology that supports it? It does not improve things much that we now only have one copy of the shared secret instead of two.

Key vault references do not work for us. Key vault references only allow system-assigned identities, but we only use user-assigned identities. Key vault references cache the secrets for up to one day, but when we regenerate keys, we regenerate the two keys less than half an hour apart from each other.

@jesperkristensen Can you please elaborate why User-assigned doesn't work for you in this scenario to access key vault? It should work exactly like system-assigned.

jesperkristensen commented 3 years ago

Can you please elaborate why User-assigned doesn't work for you in this scenario to access key vault? It should work exactly like system-assigned.

@karavar Support for user-assigned was not available when I wrote that message. It was added two weeks later at https://azure.microsoft.com/en-us/updates/general-availability-updates-to-secrets-configuration-options-in-app-service-and-azure-functions/

So that has solved one of the two blockers for us to use key vault references. The second blocker is that they are cached for one day. We can only handle if they are cached for up to 10 minutes. The reason for this short time period is that most listKeys APIs in ARM templates offer no way to tell which of the two keys should be used at which time, and the only workaround we found for that is to ensure the first key is always used >99% of the time, so we can just hardcode that in our ARM templates.

Zarick commented 3 years ago

Hi folks - we've published a preview extension bundle that you can use to try identity based connections in JavaScript, Java, PowerShell and Python without having to fiddle with explicit extension installation.

To use it, you'll need to modify your host.json:

  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle.Preview",
    "version": "[3.*, 4.0.0)"
  }

@paulbatum I deployed this with Linux/Java runtime. Is it possible to verify the download of the extension within the container? Does the host download this at a certain location?

I can only see the normal (nor preview) under /FuncExtensionBundle I can only see Microsoft.Azure.Functions.ExtensionBundle/3.0.0 but I do not see something like Microsoft.Azure.Functions.ExtensionBundle.Preview/3.0.0

Zarick commented 3 years ago

There is some confusion on the actual configuration key naming.

For value like AzureWebJobsStorage__accountName, what does "accountName" means there? Why do we need this in additions to serviceUri?

And regarding AzureWebJobsStorageserviceUri, as mentioned a few times above and the documentation, it seems changed to AzureWebJobsStorageblobServiceUri and AzureWebJobsStorage__queueServiceUri from the beta4 changelog. Who can help update the official documentation to reflect the correct configuration?

mattchenderson commented 3 years ago

Agreed that docs could be better here. We'll work on improving that. Let me know if the following is helpful at all.

accountName would be an alternative to serviceUri. The idea here is to allow for the different services from the storage account. AzureWebJobsStorage gets used for blobs and queues in some cases. accountName is generally going to be the easiest option - it defaults in the DNS suffixes to create each serviceUri it would need.

So for example, let's consider the storage account mystorage. That would have the following service endpoints:

(technically table and files exist as well, but omitting here since that's not used)

I could configure accountName: mystorage and be done with it. The above endpoints would be used by adding the suffix by convention. I could alternatively configure serviceUri: https://mystorage.blob.core.windows.net, but then I'm limited to blob usage only. However, I could also set both blobServiceUri: https://mystorage.blob.core.windows.net and queueServiceUri: https://mystorage.queue.core.windows.net to get both. The reason I might do this over accountName is if I've actually put a custom DNS suffix on the service. It's for that reason that serviceUri can't infer the URL for a different service even though in my example you could imagine just string replacing "blob" with "queue".

CC @cachai2

mdddev commented 3 years ago

@mattchenderson Thanks for the clarification. However, the only way I get this ro run correctly is by using the AzureWebJobsStorage__accountName setting. The __blobServiceUri suffix is not working for me.

Also note, that even the first __accountName is not working if this is used with a function app using the v4 extension version and NET6 preview 7 (in-process). I realise this might have something to do with the preview status, however, I thought to mention it, so that it can be taken care of before GA of NET6. I tested this with identically configured function apps and the same code.

Left= Working Right= Azure Functions runtime is unreachable

image

If I were to use the __blobServiceUri this is the outcome

image

soninaren commented 3 years ago

@Zarick, One super quick way you can find out which bundle version is being used is by checking the status endpoint. When running locally that would be http://localhost:7071/admin/host/status and for an on azure you would have to provide master key. So something like this. http://<AppName>/admin/host/status?code=<masterKey>

Sample output for an bundle v2

{
    "id": "nasoni-1568501546",
    "state": "Running",
    "version": "3.0.15828.0",
    "versionDetails": "3.0.15828 Commit hash: 70fa587c9dcd1f126abebc6432c4d8c7b2e32155",
    "platformVersion": "",
    "instanceId": "",
    "computerName": "NASONI",
    "processUptime": 25219199,
    "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "2.6.1"
    }
}
Zarick commented 3 years ago

Thanks @mattchenderson, it make much more sense to me now.

Thanks also @soninaren , that trick is useful!

Zarick commented 3 years ago

Is there any schedule for the Preview bundle to be released formally?

paulbatum commented 3 years ago

@Zarick The main prerequisite is that the packages used in that bundle all exit preview. Right now its using the 5.0-preview releases of Storage, Service Bus, etc. I can't say for sure when that will all happen yet, but at a minimum I would say keep an eye on when the preview label is dropped from these new major versions of the functions extensions. The bundle should follow some time after that.

cataggar commented 2 years ago

I see this was published 2 days ago. 🥳 https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.Storage/5.0.0 These docs will need to be updated: https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-queue#storage-extension-5x-and-higher

cataggar commented 2 years ago

I just need a new package for the .NET isolated model. Latest is still 5.0.0-beta.4. https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Extensions.Storage cc @fabiocav

avnet78 commented 2 years ago

I have a Function App with BlobTrigger. I would like to use the Managed Identity of the Function to configure the trigger and connect with the Storage Account. Can anyone please point me to a working code sample?

mattchenderson commented 2 years ago

This is now generally available in the 5.0.0 version of the NuGet package and the v3 bundle.

Announcement: https://azure.microsoft.com/en-us/updates/general-availability-azure-functions-extensions-for-blobs-queues-event-hubs-service-bus-and-event-grid/