azure-sdk-for-python: BlobClient returns ClientAuthenticationError when Azure CDN is enabled

  • Package Name: azure-storage-blob
  • Package Version: 12.10.0
  • Operating System: Ubuntu 20.04.4 LTS
  • Python Version: 3.9.5

Describe the bug Calling the BlobClient.exists method raises a ClientAuthenticationError when an Azure CDN account URL is used.

To Reproduce Steps to reproduce the behavior:

from azure.storage.blob import BlobServiceClient

ACCOUNT_NAME = "myaccount"
ACCOUNT_KEY = "myaccount-key"
CREDENTIAL = {"account_name": ACCOUNT_NAME, "account_key": ACCOUNT_KEY}

ACCOUNT_URL = f"https://{ACCOUNT_NAME}.blob.core.windows.net"
ACCOUNT_URL_CDN = f"https://{ACCOUNT_NAME}.azureedge.net"
ACCOUNT_URL_CDN_CUSTOM = f"https://static.{ACCOUNT_NAME}.com"

CONTAINER_NAME = "mycontainer"
BLOB_NAME = "path/to/image.png"

# The "standard" blob client endpoint
blob_client = BlobServiceClient(
    account_url=ACCOUNT_URL,
    credential=CREDENTIAL,
).get_blob_client(
    container=CONTAINER_NAME,
    blob=BLOB_NAME,
)

# This works! It returns True
blob_client.exists()

# Now, using the Azure CDN blob endpoint
blob_client_cdn = BlobServiceClient(
    account_url=ACCOUNT_URL_CDN,
    credential=CREDENTIAL,
).get_blob_client(
    container=CONTAINER_NAME,
    blob=BLOB_NAME,
)

# This does not work, it raises a `ClientAuthenticationError` error
blob_client_cdn.exists()

# Using a custom CDN (which is fully verified)
blob_client_cdn_custom = BlobServiceClient(
    account_url=ACCOUNT_URL_CDN_CUSTOM,
    credential=CREDENTIAL,
).get_blob_client(
    container=CONTAINER_NAME,
    blob=BLOB_NAME,
)

# This does not work, it raises a `ClientAuthenticationError` error
blob_client_cdn_custom.exists()

Expected behavior I would expect the client to authenticate correctly when using an Azure CDN or a custom CDN when the client authenticates correctly when using the standard blob endpoint.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 1
  • Comments: 23 (8 by maintainers)

Most upvoted comments

@vincenttran-msft I have generated a few more RequestIDs for you (just in case you didn’t manage to get to see the others - I guess were a few timezone apart).

# A successful response (without a CDN endpoint)
'x-ms-request-id': '369adfbf-801e-00b5-3d9c-4a2208000000'

# A failed response using the azuredge.net CDN endpoint
'x-ms-request-id': 'dc3b93de-e01e-0035-639d-4add0e000000'

# A failed response using a the CDN with a custom domain
'x-ms-request-id': '44f78dc3-701e-00b1-5d9d-4aaf0f000000'

These were generated using the example code in my original Steps to reproduce the behaviour (with account names and credentials updated).

This issue is preventing us from going live with our project. I would be willing to send you access tokens and keys (which I can recycle, if we do eventually get to go live) so you can reproduce the error yourself.

I have pasted the full output from running my Steps to reproduce the behaviour script if it helps.

In [2]: blob_client.exists()
Request URL: 'https://gamesmap.blob.core.windows.net/media/images/system/photo-2454235000000215156.png'
Request method: 'HEAD'
Request headers:
    'x-ms-version': '2020-10-02'
    'Accept': 'application/xml'
    'User-Agent': 'azsdk-python-storage-blob/12.9.0 Python/3.9.5 (Linux-5.13.0-39-generic-x86_64-with-glibc2.31)'
    'x-ms-date': 'Thu, 07 Apr 2022 16:31:26 GMT'
    'x-ms-client-request-id': '2ba19090-b690-11ec-b637-3d6a688c8c41'
    'Authorization': '*****'
Request body:
None
Response status: 200
Response headers:
    'Content-Length': '195963'
    'Content-Type': 'image/png'
    'Content-MD5': 'CHWOotVKq8/w7uG6kzMrbA=='
    'Last-Modified': 'Thu, 24 Mar 2022 09:54:18 GMT'
    'Accept-Ranges': 'bytes'
    'ETag': '"0x8DA0D7C436A3DDB"'
    'Server': 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0'
    'x-ms-request-id': '369adfbf-801e-00b5-3d9c-4a2208000000'
    'x-ms-client-request-id': '2ba19090-b690-11ec-b637-3d6a688c8c41'
    'x-ms-version': '2020-10-02'
    'x-ms-creation-time': 'Thu, 24 Mar 2022 09:54:18 GMT'
    'x-ms-lease-status': 'unlocked'
    'x-ms-lease-state': 'available'
    'x-ms-blob-type': 'BlockBlob'
    'Content-Disposition': ''
    'x-ms-server-encrypted': 'true'
    'x-ms-access-tier': 'Cool'
    'x-ms-access-tier-inferred': 'true'
    'Access-Control-Expose-Headers': 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-creation-time,Content-MD5,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,Content-Disposition,x-ms-server-encrypted,x-ms-access-tier,x-ms-access-tier-inferred,Accept-Ranges,Content-Length,Date,Transfer-Encoding'
    'Access-Control-Allow-Origin': '*'
    'Date': 'Thu, 07 Apr 2022 16:31:26 GMT'
Response content:
Body contains image data.
Out[2]: True

In [3]: blob_client_cdn.exists()
Request URL: 'https://gamesmap.azureedge.net/media/images/system/photo-2454235000000215156.png'
Request method: 'HEAD'
Request headers:
    'x-ms-version': '2020-10-02'
    'Accept': 'application/xml'
    'User-Agent': 'azsdk-python-storage-blob/12.9.0 Python/3.9.5 (Linux-5.13.0-39-generic-x86_64-with-glibc2.31)'
    'x-ms-date': 'Thu, 07 Apr 2022 16:32:12 GMT'
    'x-ms-client-request-id': '46beedbe-b690-11ec-b637-3d6a688c8c41'
    'Authorization': '*****'
Request body:
None
Response status: 403
Response headers:
    'Content-Length': '748'
    'Content-Type': 'application/xml'
    'Server': 'Microsoft-HTTPAPI/2.0'
    'X-Cache': 'TCP_MISS'
    'x-ms-request-id': 'dc3b93de-e01e-0035-639d-4add0e000000'
    'x-ms-error-code': 'AuthenticationFailed'
    'Access-Control-Expose-Headers': 'x-ms-request-id,x-ms-error-code,Content-Length,Date,Transfer-Encoding'
    'Access-Control-Allow-Origin': '*'
    'X-Azure-Ref-OriginShield': '0DBJPYgAAAABhQgjqImZdQY9Gfc3OysxBTE9OMjFFREdFMDExMwA2ZmJlNzM3NC03YWIzLTQzNTItODRiNC0xMGIwNjRhYjA4Zjc='
    'X-Azure-Ref': '0DBJPYgAAAACuOb0FYH0IT4JNCm3+NIjtTUFOMzBFREdFMDcxMwA2ZmJlNzM3NC03YWIzLTQzNTItODRiNC0xMGIwNjRhYjA4Zjc='
    'Date': 'Thu, 07 Apr 2022 16:32:12 GMT'
Response content:

---------------------------------------------------------------------------
ClientAuthenticationError                 Traceback (most recent call last)
<ipython-input-3-aade6ad209e1> in <module>
----> 1 blob_client_cdn.exists()

~/projects/games-map/.venv/lib/python3.9/site-packages/azure/core/tracing/decorator.py in wrapper_use_tracer(*args, **kwargs)
     71             span_impl_type = settings.tracing_implementation()
     72             if span_impl_type is None:
---> 73                 return func(*args, **kwargs)
     74 
     75             # Merge span is parameter is set, but only if no explicit parent are passed

~/projects/games-map/.venv/lib/python3.9/site-packages/azure/storage/blob/_blob_client.py in exists(self, **kwargs)
   1153         except HttpResponseError as error:
   1154             try:
-> 1155                 process_storage_error(error)
   1156             except ResourceNotFoundError:
   1157                 return False

~/projects/games-map/.venv/lib/python3.9/site-packages/azure/storage/blob/_shared/response_handlers.py in process_storage_error(storage_error)
    175     try:
    176         # `from None` prevents us from double printing the exception (suppresses generated layer error context)
--> 177         exec("raise error from None")   # pylint: disable=exec-used # nosec
    178     except SyntaxError:
    179         raise error

~/projects/games-map/.venv/lib/python3.9/site-packages/azure/storage/blob/_shared/response_handlers.py in <module>

ClientAuthenticationError: Operation returned an invalid status 'Forbidden'
ErrorCode:AuthenticationFailed

In [4]: blob_client_cdn_custom.exists()
Request URL: 'https://static.gamesmap.uk/media/images/system/photo-2454235000000215156.png'
Request method: 'HEAD'
Request headers:
    'x-ms-version': '2020-10-02'
    'Accept': 'application/xml'
    'User-Agent': 'azsdk-python-storage-blob/12.9.0 Python/3.9.5 (Linux-5.13.0-39-generic-x86_64-with-glibc2.31)'
    'x-ms-date': 'Thu, 07 Apr 2022 16:33:52 GMT'
    'x-ms-client-request-id': '82ea3e9c-b690-11ec-b637-3d6a688c8c41'
    'Authorization': '*****'
Request body:
None
Response status: 403
Response headers:
    'Content-Length': '748'
    'Content-Type': 'application/xml'
    'Server': 'Microsoft-HTTPAPI/2.0'
    'X-Cache': 'TCP_MISS'
    'x-ms-request-id': '44f78dc3-701e-00b1-5d9d-4aaf0f000000'
    'x-ms-error-code': 'AuthenticationFailed'
    'Access-Control-Expose-Headers': 'x-ms-request-id,x-ms-error-code,Content-Length,Date,Transfer-Encoding'
    'Access-Control-Allow-Origin': '*'
    'X-Azure-Ref-OriginShield': '0cRJPYgAAAACpFIw1TVNgRLsvkhpuRcTkTE9OMjFFREdFMDEyMgA2ZmJlNzM3NC03YWIzLTQzNTItODRiNC0xMGIwNjRhYjA4Zjc='
    'X-Azure-Ref': '0cRJPYgAAAABqi3bBiEA9RroHEa+DJoIcTUFOMzBFREdFMDcwOQA2ZmJlNzM3NC03YWIzLTQzNTItODRiNC0xMGIwNjRhYjA4Zjc='
    'Date': 'Thu, 07 Apr 2022 16:33:53 GMT'
Response content:

---------------------------------------------------------------------------
ClientAuthenticationError                 Traceback (most recent call last)
<ipython-input-4-6305c8075a85> in <module>
----> 1 blob_client_cdn_custom.exists()

~/projects/games-map/.venv/lib/python3.9/site-packages/azure/core/tracing/decorator.py in wrapper_use_tracer(*args, **kwargs)
     71             span_impl_type = settings.tracing_implementation()
     72             if span_impl_type is None:
---> 73                 return func(*args, **kwargs)
     74 
     75             # Merge span is parameter is set, but only if no explicit parent are passed

~/projects/games-map/.venv/lib/python3.9/site-packages/azure/storage/blob/_blob_client.py in exists(self, **kwargs)
   1153         except HttpResponseError as error:
   1154             try:
-> 1155                 process_storage_error(error)
   1156             except ResourceNotFoundError:
   1157                 return False

~/projects/games-map/.venv/lib/python3.9/site-packages/azure/storage/blob/_shared/response_handlers.py in process_storage_error(storage_error)
    175     try:
    176         # `from None` prevents us from double printing the exception (suppresses generated layer error context)
--> 177         exec("raise error from None")   # pylint: disable=exec-used # nosec
    178     except SyntaxError:
    179         raise error

~/projects/games-map/.venv/lib/python3.9/site-packages/azure/storage/blob/_shared/response_handlers.py in <module>

ClientAuthenticationError: Operation returned an invalid status 'Forbidden'
ErrorCode:AuthenticationFailed

In [5]: 

I deleted the existing Microsoft CDN (classic) CDN, and created a new one with the Standard Verizon pricing tier. This has resolved the issue.

I will mark this issue as closed. Thank you for your time and patience @vincenttran-msft

Thank you @vincenttran-msft

One of the first things I tried was to recycle my keys, I have also tried using SAS tokens - all give the same response, which is correct operation when using the https://myaccount.blob.core.windows.net, but authentication errors when using an Azure CDN endpoint.