azure-functions-python-worker icon indicating copy to clipboard operation
azure-functions-python-worker copied to clipboard

[Bug] Blob trigger uses incorrect authentication method

Open donheerschap opened this issue 1 year ago • 3 comments

Expected Behavior

When using identity-based connection settings it should use the managed identity auth method.

Actual Behavior

It tries to use the connection string method and fails because it tries to parse a non-existent setting.

Steps to Reproduce

  1. Create identity-based connections in the environment variables, in this case: DATALAKE__queueServiceUri & DATALAKE__blobServiceUri
  2. Create a blob trigger using connection="DATALAKE"
  3. Create a test blob in the path defined for the blob trigger
  4. It will result into erroring parsing the non-existent "DATALAKE" env variable.

If you use the AzureWebJobsStorage__accountname and set connection="AzureWebJobsStorage" without having the AzureWebJobsStorage setting it works, so it's only for custom connections which are documented here

Relevant code being tried

{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "python",
    "AzureWebJobsFeatureFlags": "EnableWorkerIndexing",
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "DATALAKE__blobServiceUri": "https://REDACTED.blob.core.windows.net/",
    "DATALAKE__serviceUri": "https://REDACTED.blob.core.windows.net/",
    "DATALAKE__queueServiceUri": "https://REDACTED.queue.core.windows.net/"
  }
}
import logging
import os

import azure.functions as func
from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobClient
import azurefunctions.extensions.bindings.blob as blob

bp = func.Blueprint()

@bp.function_name(name="process_blob_weather_data")
@bp.blob_trigger(
    arg_name="sourceblob", path="bronze/weatherdata/{name}.json", connection="DATALAKE"
)
def process_blob_weather_data(sourceblob: blob.BlobClient):
    logging.info('Starting to process blob')
    logging.info(
        f"Python blob trigger function processed blob! Perms \n"
        f"Properties: {sourceblob.get_blob_properties()}\n"
        f"Blob content head: {sourceblob.download_blob().read(size=1)}"
    )
    
    logging.info('Blob processed')

Relevant log output

ContextEnabledTask exception was never retrieved
future: <ContextEnabledTask finished name='Task-8' coro=<Dispatcher._dispatch_grpc_request() done, defined at C:\Program Files\Microsoft\Azure Functions Core Tools\workers\python\3.11\WINDOWS\X64\azure_functions_worker\dispatcher.py:263> exception=UnboundLocalError("cannot access local variable 'http_v2_enabled' where it is not associated with a value")>
Traceback (most recent call last):
  File "C:\Program Files\Microsoft\Azure Functions Core Tools\workers\python\3.11\WINDOWS\X64\azure_functions_worker\dispatcher.py", line 565, in _handle__invocation_request  
    args[pb.name] = bindings.from_incoming_proto(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Program Files\Microsoft\Azure Functions Core Tools\workers\python\3.11\WINDOWS\X64\azure_functions_worker\bindings\meta.py", line 183, in from_incoming_proto       
    return deferred_bindings_decode(binding=binding,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Program Files\Microsoft\Azure Functions Core Tools\workers\python\3.11\WINDOWS\X64\azure_functions_worker\bindings\meta.py", line 301, in deferred_bindings_decode  
    deferred_binding_type = binding.decode(datum,
                            ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Source\InSparkSolutions\smallestAzureDataplatform\functions\.venv\Lib\site-packages\azurefunctions\extensions\bindings\blob\blobClientConverter.py", line 43, in decode
    return BlobClient(data=data).get_sdk_type()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Source\InSparkSolutions\smallestAzureDataplatform\functions\.venv\Lib\site-packages\azurefunctions\extensions\bindings\blob\blobClient.py", line 35, in get_sdk_type
    return BlobClientSdk.from_connection_string(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Source\InSparkSolutions\smallestAzureDataplatform\functions\.venv\Lib\site-packages\azure\storage\blob\_blob_client.py", line 347, in from_connection_string        
    account_url, secondary, credential = parse_connection_str(conn_str, credential, 'blob')
                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Source\InSparkSolutions\smallestAzureDataplatform\functions\.venv\Lib\site-packages\azure\storage\blob\_shared\base_client.py", line 368, in parse_connection_str   
    conn_str = conn_str.rstrip(";")
               ^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'rstrip'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Program Files\Microsoft\Azure Functions Core Tools\workers\python\3.11\WINDOWS\X64\azure_functions_worker\dispatcher.py", line 274, in _dispatch_grpc_request       
    resp = await request_handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Program Files\Microsoft\Azure Functions Core Tools\workers\python\3.11\WINDOWS\X64\azure_functions_worker\dispatcher.py", line 655, in _handle__invocation_request  
    if http_v2_enabled:
       ^^^^^^^^^^^^^^^
UnboundLocalError: cannot access local variable 'http_v2_enabled' where it is not associated with a value

requirements.txt file

azure-functions pandas requests azure-identity azure-storage-blob azurefunctions-extensions-bindings-blob

Where are you facing this problem?

Local - Core Tools

Function app name

No response

Additional Information

No response

donheerschap avatar Oct 23 '24 21:10 donheerschap

Hi @donheerschap, thanks for reporting.

What version of azurefunctions-extensions-bindings-blob are you using? Support for managed identity was added in 1.0.0b2. If you're not using that version, can you update and try again?

hallvictoria avatar Oct 24 '24 15:10 hallvictoria

Hi @hallvictoria I updated it, I was on version 1.0.0b1 locally, my CICD for the FA already installed 1.0.0b2 and shows another error in the logs, which now also show locally:

[2024-10-25T06:30:46.545Z] Executed 'Functions.process_blob_weather_data' (Failed, Id=0a4d9f70-4774-4994-8b3d-229ca51f7de2, Duration=82ms)
[2024-10-25T06:30:46.548Z] System.Private.CoreLib: Exception while executing function: Functions.process_blob_weather_data. System.Private.CoreLib: Result: Failure
Exception: ClientAuthenticationError: Operation returned an invalid status 'Server failed to authenticate the request. Please refer to the information in the www-authenticate header.'
ErrorCode:NoAuthenticationInformation
Stack:   File "C:\Program Files\Microsoft\Azure Functions Core Tools\workers\python\3.11\WINDOWS\X64\azure_functions_worker\dispatcher.py", line 604, in _handle__invocation_request
    call_result = await self._loop.run_in_executor(
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\DonHeerschap\AppData\Local\Programs\Python\Python311\Lib\concurrent\futures\thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Program Files\Microsoft\Azure Functions Core Tools\workers\python\3.11\WINDOWS\X64\azure_functions_worker\dispatcher.py", line 933, in _run_sync_func
    return ExtensionManager.get_sync_invocation_wrapper(context,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Program Files\Microsoft\Azure Functions Core Tools\workers\python\3.11\WINDOWS\X64\azure_functions_worker\extension.py", line 215, in _raw_invocation_wrapper
    result = function(**args)
             ^^^^^^^^^^^^^^^^
  File "C:\Source\InSparkSolutions\smallestAzureDataplatform\functions\blueprints\blob_process_weather_data.py", line 19, in process_blob_weather_data     
    f"Properties: {sourceblob.get_blob_properties()}\n"
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Source\InSparkSolutions\smallestAzureDataplatform\functions\.venv\Lib\site-packages\azure\core\tracing\decorator.py", line 94, in wrapper_use_tracer
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Source\InSparkSolutions\smallestAzureDataplatform\functions\.venv\Lib\site-packages\azure\storage\blob\_blob_client.py", line 1080, in get_blob_properties
    process_storage_error(error)
  File "C:\Source\InSparkSolutions\smallestAzureDataplatform\functions\.venv\Lib\site-packages\azure\storage\blob\_shared\response_handlers.py", line 186, in process_storage_error
    exec("raise error from None")   # pylint: disable=exec-used # nosec
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<string>", line 1, in <module>
  File "C:\Source\InSparkSolutions\smallestAzureDataplatform\functions\.venv\Lib\site-packages\azure\storage\blob\_blob_client.py", line 1070, in get_blob_properties
    blob_props = cast(BlobProperties, self._client.blob.get_properties(
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Source\InSparkSolutions\smallestAzureDataplatform\functions\.venv\Lib\site-packages\azure\core\tracing\decorator.py", line 94, in wrapper_use_tracer
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Source\InSparkSolutions\smallestAzureDataplatform\functions\.venv\Lib\site-packages\azure\storage\blob\_generated\operations\_blob_operations.py", line 1900, in get_properties
    map_error(status_code=response.status_code, response=response, error_map=error_map)
  File "C:\Source\InSparkSolutions\smallestAzureDataplatform\functions\.venv\Lib\site-packages\azure\core\exceptions.py", line 161, in map_error
    raise error
.

This is the RBAC of the targeted storage account (db-test being SP being set on my local machine with environment vars with AZURE_TENANT_ID, AZURE_CLIENT_ID, & AZURE_CLIENT_SECRET), which I think is not missing anything:

Image

donheerschap avatar Oct 25 '24 06:10 donheerschap

Looks like a credential is missing. The error is happening when trying to use the client, not when creating it. I'll look into adding a change that will allow users to input their own credentials, but for now, we can create a default one on the extension side and use that to authenticate correctly. Here is the BlobServiceClient documentation for reference.

The fix for this will be in azurefunctions-extensions-bindings-blob version 1.0.0b3. It might take some time to test, so ETA is sometime next week. I'll post an update here when it's finished!

Thanks for your patience!

hallvictoria avatar Oct 25 '24 16:10 hallvictoria

Posting an update here -- the work has been tested and validated, but as we are currently halting releases for the holidays, the fix will be released sometime early January. I'll update here once it has been released. Thanks for your patience, and sorry for the delay!

hallvictoria avatar Nov 15 '24 23:11 hallvictoria

v1.0.0b3 has been released! Sorry for the delay, and please let me know if you're still facing issues with this

hallvictoria avatar Feb 04 '25 19:02 hallvictoria