0

Context

I have several micro-services spread across multiple HTTP triggered Function Apps running in a Consumption Plan on Linux and, up until recently, all the Function App instances were using AuthenticalLevel set to Anonymous.

Now, I have switched the AuthenticalLevel to Function and created Function App keys. Of course, all the clients use the x-functions-key header with the correct key.

It works most of the time.

Problem

However, if I call a function in one of the Function Apps that has not been called in a while, I get an HTTP status code of 401 - Unauthorized and the functions in my Function Apps are not triggered.

Now, the weird part is that if I restart the Function App, it works again.

Investigation

I had a hard time finding any clues about what was going on because every time I started logging, it worked again. I left one of my application insights log window opened for a while and I have been able to get the following trace in one of the Function App that started to fail:

[Information]   Executing StatusCodeResult, setting HTTP status code 401

I do not know what the error means and upon search, I have found the error mentioned on Github in the following comment:

If you get 401 Unauthorized, find the file function.json, change authLevel to anonymous if it is set to function(default value in template). We can't access http trigger in a local container with authlevel other than anonymous. Because we don't have function keys yet, which are available after we create a Function app using the container.

I am not using container (at least not explicitly) so I am worrying that the issue I am facing is out my area of expertise.

Question

Why is the 401 code returned knowing the key used in the header is correct? Is it possible to protect my Function Apps running in a Consumption Plan on Linux using a Function Key?

Logs

Here are more logs starting at the time the request is received by the function host:

[Verbose]   Request successfully matched the route with name 'v1-get-account' and template 'api/v1/accounts'
[Information]   Request [37760fe9-e2cb-4555-b053-09fc7e294d41] HEAD https://<function_app_dedicated_storage>.blob.core.windows.net/azure-webjobs-secrets/<function_app_name>/host.json
x-ms-version:2021-08-06
Accept:application/xml
x-ms-client-request-id:37760fe9-e2cb-4555-b053-09fc7e294d41
x-ms-return-client-request-id:true
User-Agent:azsdk-net-Storage.Blobs/12.13.0,(.NET 6.0.6; Linux 5.10.102.2-microsoft-standard #1 SMP Mon Mar 7 17:36:34 UTC 2022)
x-ms-date:Sun, 25 Dec 2022 16:16:36 GMT
Authorization:REDACTED
client assembly: Azure.Storage.Blobs
[Information]   Response [37760fe9-e2cb-4555-b053-09fc7e294d41] 200 OK (00.0s)
Accept-Ranges:bytes
ETag:"0x8DACA94982533A3"
Server:Windows-Azure-Blob/1.0,Microsoft-HTTPAPI/2.0
x-ms-request-id:e0db0aa4-801e-00a6-2d7c-18269c000000
x-ms-client-request-id:37760fe9-e2cb-4555-b053-09fc7e294d41
x-ms-version:2021-08-06
x-ms-creation-time:Fri, 12 Aug 2022 23:37:07 GMT
x-ms-lease-status:unlocked
x-ms-lease-state:available
x-ms-blob-type:BlockBlob
x-ms-server-encrypted:true
x-ms-access-tier:Hot
x-ms-access-tier-inferred:true
Date:Sun, 25 Dec 2022 16:16:35 GMT
Content-Length:1109
Content-Type:application/octet-stream
Content-MD5:LuFKWHapYzSmnjxmromAuw==
Last-Modified:Sun, 20 Nov 2022 01:14:38 GMT
[Information]   Request [9fe0455e-4e3e-497e-8b1f-a13128d8920c] GET https://<function_app_dedicated_storage>.blob.core.windows.net/azure-webjobs-secrets/<function_app_name>/host.json
x-ms-version:2021-08-06
Accept:application/xml
x-ms-client-request-id:9fe0455e-4e3e-497e-8b1f-a13128d8920c
x-ms-return-client-request-id:true
User-Agent:azsdk-net-Storage.Blobs/12.13.0,(.NET 6.0.6; Linux 5.10.102.2-microsoft-standard #1 SMP Mon Mar 7 17:36:34 UTC 2022)
x-ms-date:Sun, 25 Dec 2022 16:16:36 GMT
Authorization:REDACTED
client assembly: Azure.Storage.Blobs
[Information]   Response [9fe0455e-4e3e-497e-8b1f-a13128d8920c] 200 OK (00.0s)
Accept-Ranges:bytes
ETag:"0x8DACA94982533A3"
Server:Windows-Azure-Blob/1.0,Microsoft-HTTPAPI/2.0
x-ms-request-id:e0db0aa9-801e-00a6-317c-18269c000000
x-ms-client-request-id:9fe0455e-4e3e-497e-8b1f-a13128d8920c
x-ms-version:2021-08-06
x-ms-creation-time:Fri, 12 Aug 2022 23:37:07 GMT
x-ms-lease-status:unlocked
x-ms-lease-state:available
x-ms-blob-type:BlockBlob
x-ms-server-encrypted:true
Date:Sun, 25 Dec 2022 16:16:35 GMT
Content-Length:1109
Content-Type:application/octet-stream
Content-MD5:LuFKWHapYzSmnjxmromAuw==
Last-Modified:Sun, 20 Nov 2022 01:14:38 GMT
[Information]   Request [532132a5-3186-4397-b913-08a0d8a8bb55] HEAD https://<function_app_dedicated_storage>.blob.core.windows.net/azure-webjobs-secrets/<function_app_name>/v1-get-account.json
x-ms-version:2021-08-06
Accept:application/xml
x-ms-client-request-id:532132a5-3186-4397-b913-08a0d8a8bb55
x-ms-return-client-request-id:true
User-Agent:azsdk-net-Storage.Blobs/12.13.0,(.NET 6.0.6; Linux 5.10.102.2-microsoft-standard #1 SMP Mon Mar 7 17:36:34 UTC 2022)
x-ms-date:Sun, 25 Dec 2022 16:16:36 GMT
Authorization:REDACTED
client assembly: Azure.Storage.Blobs
[Information]   Response [532132a5-3186-4397-b913-08a0d8a8bb55] 200 OK (00.0s)
Accept-Ranges:bytes
ETag:"0x8DA7CBB927ADEE5"
Server:Windows-Azure-Blob/1.0,Microsoft-HTTPAPI/2.0
x-ms-request-id:e0db0aac-801e-00a6-347c-18269c000000
x-ms-client-request-id:532132a5-3186-4397-b913-08a0d8a8bb55
x-ms-version:2021-08-06
x-ms-creation-time:Fri, 12 Aug 2022 23:37:08 GMT
x-ms-lease-status:unlocked
x-ms-lease-state:available
x-ms-blob-type:BlockBlob
x-ms-server-encrypted:true
x-ms-access-tier:Hot
x-ms-access-tier-inferred:true
Date:Sun, 25 Dec 2022 16:16:35 GMT
Content-Length:519
Content-Type:application/octet-stream
Last-Modified:Fri, 12 Aug 2022 23:37:08 GMT
[Information]   Request [208dd98f-c802-4ea2-85eb-525716290cc4] GET https://<function_app_dedicated_storage>.blob.core.windows.net/azure-webjobs-secrets/<function_app_name>/v1-get-account.json
x-ms-version:2021-08-06
Accept:application/xml
x-ms-client-request-id:208dd98f-c802-4ea2-85eb-525716290cc4
x-ms-return-client-request-id:true
User-Agent:azsdk-net-Storage.Blobs/12.13.0,(.NET 6.0.6; Linux 5.10.102.2-microsoft-standard #1 SMP Mon Mar 7 17:36:34 UTC 2022)
x-ms-date:Sun, 25 Dec 2022 16:16:36 GMT
Authorization:REDACTED
client assembly: Azure.Storage.Blobs
[Information]   Response [208dd98f-c802-4ea2-85eb-525716290cc4] 200 OK (00.0s)
Accept-Ranges:bytes
ETag:"0x8DA7CBB927ADEE5"
Server:Windows-Azure-Blob/1.0,Microsoft-HTTPAPI/2.0
x-ms-request-id:e0db0ab0-801e-00a6-377c-18269c000000
x-ms-client-request-id:208dd98f-c802-4ea2-85eb-525716290cc4
x-ms-version:2021-08-06
x-ms-creation-time:Fri, 12 Aug 2022 23:37:08 GMT
x-ms-lease-status:unlocked
x-ms-lease-state:available
x-ms-blob-type:BlockBlob
x-ms-server-encrypted:true
Date:Sun, 25 Dec 2022 16:16:35 GMT
Content-Length:519
Content-Type:application/octet-stream
Last-Modified:Fri, 12 Aug 2022 23:37:08 GMT
[Information]   Executing StatusCodeResult, setting HTTP status code 401
Kzryzstof
  • 7,688
  • 10
  • 61
  • 108
  • Can you post all the logs coming from the request that is returning status 401? – funatparties Dec 24 '22 at 22:35
  • @funatparties I have added all the logs related to the failing request. – Kzryzstof Dec 25 '22 at 16:43
  • how are you deploying your app? Via portal or using cli/git? This answer may explain the behaviour you are getting https://stackoverflow.com/a/72384971. When the app isn't getting hits it gets paused, and then when you request it, it gets re-started, and it may be mixing some settings. – funatparties Dec 25 '22 at 18:47
  • I have setup a CI/CD pipeline in Azure DevOps. It uses the staging slot for warm-up / smoke test and then swaps between the staging slot and the production slot. – Kzryzstof Dec 26 '22 at 14:33
  • Check if maybe you are applying different settings when deploying using pipeline vs when you are restarting them manually. Other than that, there could be a lot of reasons why is it happening and probably need live investigation of everything. – funatparties Dec 26 '22 at 17:12

1 Answers1

0

I have not been able to make it work.

I switched to a keyvault as the mean to store the Function App keys and the problem disappeared. The settings of the Function App looks like this:

{
  "IsEncrypted": false,
    ...
    "FUNCTIONS_WORKER_RUNTIME"              : "dotnet-isolated",
    "FUNCTIONS_EXTENSION_VERSION"           : "~4",
    
    "AzureWebJobsStorage"                   : "DefaultEndpointsProtocol=https;AccountName=<storageaccount_name>;AccountKey=<storageaccount_key>;EndpointSuffix=core.windows.net",
    
    "AzureWebJobsSecretStorageType"        : "keyvault",
    "AzureWebJobsSecretStorageKeyVaultUri" : "https://<keyvault_name>.vault.azure.net"
    
    ...
  },
  "Host": {
    "LocalHttpPort": 7075,
    "CORS": "*"
  }
}
Kzryzstof
  • 7,688
  • 10
  • 61
  • 108