Skip to content

SNOW-3220158: Azure Workload Identity Federation Metadata Request Header #2784

@Chris-Hastie

Description

@Chris-Hastie

Python version

3.11.15

Operating system and processor architecture

Linux-6.1.146.1-microsoft-standard-x86_64-with-glibc2.36

Installed packages

asn1crypto==1.5.1
azure-core==1.38.2
azure-identity==1.25.2
boto3==1.42.60
botocore==1.42.60
certifi==2026.2.25
cffi==2.0.0
charset-normalizer==3.4.4
cloudpickle==3.1.1
cryptography==46.0.5
filelock==3.25.0
idna==3.11
jmespath==1.1.0
msal==1.35.1
msal-extensions==1.3.1
packaging==26.0
platformdirs==4.9.2
protobuf==6.33.5
pycparser==3.0
PyJWT==2.11.0
pyOpenSSL==25.3.0
python-dateutil==2.9.0.post0
pytz==2026.1.post1
PyYAML==6.0.3
requests==2.32.5
tomlkit==0.14.0
typing_extensions==4.15.0
tzlocal==5.3.1
urllib3==2.6.3

What did you do?

Azure WIF authentication workflow

What did you expect to see?

A successful response from the Azure Instance Metadata Service. Instead, the Metadata Service returns a HTTP/400 error as follows:

snowflake.connector.errors.ProgrammingError: 251018: Error fetching Azure metadata: 400 Client Error: Bad Request for url: http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=api://<tenant_id>&client_id=<client_id>. Ensure the application is running on Azure.

This aligns with a similar error with the Go connector (SNOW-3096925: Azure Workload Identity Federation Metadata Request Header) which has been resolved.

Applying this workaround seems to resolve the issue:

# Workaround for SNOW-3096925: Snowflake connector sends Metadata: True (capital T)
# but Azure IMDS requires lowercase true. Patch the vendored requests session
# to normalise the header before it reaches IMDS. Remove once Snowflake releases
# a fix for the Python connector (Go connector fixed in gosnowflake v2.0.0).
from snowflake.connector.vendored import requests as _sf_requests
_original_request = _sf_requests.Session.request
def _patched_request(self, method, url, **kwargs):
    headers = kwargs.get('headers') or {}
    if headers.get('Metadata') == 'True':
        kwargs['headers'] = {**headers, 'Metadata': 'true'}
    return _original_request(self, method, url, **kwargs)
_sf_requests.Session.request = _patched_request

from snowflake.snowpark import Session

Can you set logging to DEBUG and collect the logs?

Metadata

Metadata

Labels

bugstatus-triage_doneInitial triage done, will be further handled by the driver team

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions