I’m in the process of migrating our functionapps to custom runtime containers. I’m doing this through ARM templates.
I’ve got to the point where I can do this, however, in order to get it to work, I have to manually open the Deployment Center and hit save after provisioning, otherwise the functionapp cannot pull down from the ACR (and the logs say there’s an auth error).
2022-10-10T22:25:29.055Z INFO – Recycling container because of AppSettingsChange and isMainSite = True
2022-10-10T22:25:32.116Z ERROR – DockerApiException: Docker API responded with status code=InternalServerError, response={"message":"Get https://redacted.azurecr.io/v2/redacted/manifests/preview: unauthorized: authentication required, visit https://aka.ms/acr/authorization for more information."}
As soon as I click save (I don’t even change anything) it pulls down and deploys correctly.
Whilst I don’t need to reprovision often, this manual step is a pain and I want to fix it, what do I need to add to my ARM template to facilitate this?
The relevent section of the ARM template is:
{
"type": "Microsoft.Web/sites",
"apiVersion": "2022-03-01",
"name": "[parameters('functionAppName')]",
"location": "[parameters('location')]",
"kind": "functionapp,linux,container",
"identity": {
"type": "SystemAssigned"
},
"dependsOn": [
"[variables('appServicePlanResourceId')]",
"[variables('deploymentStorageAccountId')]",
"[variables('networkResourceId')]",
"[resourceId('microsoft.insights/components', parameters('functionAppName'))]"
],
"tags": {
"Product": "[variables('productTag')]",
"Environment": "[parameters('environmentTag')]"
},
"properties": {
"ftpsState": "FtpsOnly",
"httpsOnly": true,
"reserved": true,
"serverFarmId": "[variables('appServicePlanResourceId')]",
"siteConfig": {
"appSettings": [
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('deploymentStorageAccountName'), ';EndpointSuffix=', environment().suffixes.storage, ';AccountKey=',listKeys(variables('deploymentStorageAccountId'), '2019-06-01').keys[0].value)]"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('deploymentStorageAccountName'), ';EndpointSuffix=', environment().suffixes.storage, ';AccountKey=',listKeys(variables('deploymentStorageAccountId'), '2019-06-01').keys[0].value)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[toLower(parameters('functionAppName'))]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~3"
},
{
"name": "APPLICATIONINSIGHTS_CONNECTION_STRING",
"value": "[concat('InstrumentationKey=', reference(resourceId('Microsoft.Insights/components', parameters('functionAppName')), '2020-02-02-preview').instrumentationKey)]"
},
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "dotnet"
},
{
"name": "EventGridTopicEndpoint",
"value": "[reference(variables('eventGridTopicId')).endpoint]"
},
{
"name": "EventGridTopicAccessKey",
"value": "[listKeys(variables('eventGridTopicId'), '2020-06-01').key1]"
},
{
"name": "WEBSITE_DNS_SERVER",
"value": "redacted"
},
{
"name": "WEBSITE_VNET_ROUTE_ALL",
"value": 1
},
{
"name": "WEBSITES_ENABLE_APP_SERVICE_STORAGE",
"value": "false"
}
],
"linuxFxVersion": "[parameters('linuxFxVersion')]",
"acrUseManagedIdentityCreds": false
}
},
"resources": [
{
"type": "networkConfig",
"apiVersion": "2019-08-01",
"name": "virtualNetwork",
"dependsOn": [ "[variables('functionAppResourceId')]" ],
"properties": {
"subnetResourceId": "[variables('subnetResourceId')]",
"isSwift": true
}
}
]
}
[parameters('linuxFxVersion')]
evaluates to DOCKER|redacted.azurecr.io/redacted:preview
Every answer that I’ve found so far requires either adding config options with docker usernames and passwords, or using a managed identity, neither of which is what we want.
3
Answers
So with hints taken from the other two answers and from here, I've devised two solutions.
Using Service Principal Role
"acrUseManagedIdentityCreds": true
to thesiteConfig
in my ARM templateAcrPull
role to the service principal of the functionapp (I've not tested this snippet because perms weren't set-up quite right and it's too late for me to ask someone to change them)Getting Admin Creds with Reference
You need to add an RBAC assignment to your ACR instance granting the system-assigned identity of your function app the
AcrPull
role.The alternative is using admin credentials.
When you hit "Save" in the deployment center, it’s using one of those two methods — it’s retrieving the admin credentials from the ACR and applying them to the app service. It’s not doing anything special, it’s doing exactly what you can do yourself.
I recommend using managed identities instead. You can even create a single user-assigned identity and share it across multiple function apps, if you really want to.
Reference a secret in a key vault: