From 4289944d29c5e0d47360efb1036f0ee3c448c62f Mon Sep 17 00:00:00 2001 From: Paul Van Eck Date: Fri, 19 Jan 2024 23:41:36 +0000 Subject: [PATCH] [Identity] Loosen imds unreachable error check Signed-off-by: Paul Van Eck --- sdk/identity/azure-identity/CHANGELOG.md | 1 + .../azure-identity/azure/identity/_credentials/imds.py | 4 ++-- sdk/identity/azure-identity/tests/test_imds_credential.py | 5 +++-- .../azure-identity/tests/test_imds_credential_async.py | 5 +++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/sdk/identity/azure-identity/CHANGELOG.md b/sdk/identity/azure-identity/CHANGELOG.md index 092db189f96f..0b3182ef5914 100644 --- a/sdk/identity/azure-identity/CHANGELOG.md +++ b/sdk/identity/azure-identity/CHANGELOG.md @@ -9,6 +9,7 @@ ### Bugs Fixed - Fixed the bug that `ClientAssertionCredential` constructor fails if kwargs are provided. ([#33673](https://github.com/Azure/azure-sdk-for-python/issues/33673)) +- `ManagedIdentityCredential` is more lenient with the error message it matches when falling through to the next credential in the chain in the case that Docker Desktop returns a 403 response when attempting to access the IMDS endpoint. ([#33928](https://github.com/Azure/azure-sdk-for-python/pull/33928)) ### Other Changes diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/imds.py b/sdk/identity/azure-identity/azure/identity/_credentials/imds.py index 70dde1c69260..73dbbb89287b 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/imds.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/imds.py @@ -43,13 +43,13 @@ def _check_forbidden_response(ex: HttpResponseError) -> None: """Special case handling for Docker Desktop. Docker Desktop proxies all HTTP traffic, and if the IMDS endpoint is unreachable, it - responds with a 403 with a message that contains "A socket operation was attempted to an unreachable network". + responds with a 403 with a message that contains "unreachable". :param ~azure.core.exceptions.HttpResponseError ex: The exception raised by the request :raises ~azure.core.exceptions.CredentialUnavailableError: When the IMDS endpoint is unreachable """ if ex.status_code == 403: - if ex.message and "A socket operation was attempted to an unreachable network" in ex.message: + if ex.message and "unreachable" in ex.message: error_message = f"ManagedIdentityCredential authentication unavailable. Error: {ex.message}" raise CredentialUnavailableError(message=error_message) from ex diff --git a/sdk/identity/azure-identity/tests/test_imds_credential.py b/sdk/identity/azure-identity/tests/test_imds_credential.py index 295ff297fedd..a858d4f9feff 100644 --- a/sdk/identity/azure-identity/tests/test_imds_credential.py +++ b/sdk/identity/azure-identity/tests/test_imds_credential.py @@ -65,12 +65,13 @@ def send(request, **kwargs): assert error_message in ex.value.message -def test_imds_request_failure_docker_desktop(): +@pytest.mark.parametrize("error_ending", ("network", "host", "foo")) +def test_imds_request_failure_docker_desktop(error_ending): """The credential should raise CredentialUnavailableError when a 403 with a specific message is received""" error_message = ( "connecting to 169.254.169.254:80: connecting to 169.254.169.254:80: dial tcp 169.254.169.254:80: " - "connectex: A socket operation was attempted to an unreachable network." # cspell:disable-line + f"connectex: A socket operation was attempted to an unreachable {error_ending}." # cspell:disable-line ) probe = mock_response(status_code=403, json_payload={"error": error_message}) transport = mock.Mock(send=mock.Mock(return_value=probe)) diff --git a/sdk/identity/azure-identity/tests/test_imds_credential_async.py b/sdk/identity/azure-identity/tests/test_imds_credential_async.py index 948f5f20f34f..2b19a48524b9 100644 --- a/sdk/identity/azure-identity/tests/test_imds_credential_async.py +++ b/sdk/identity/azure-identity/tests/test_imds_credential_async.py @@ -98,12 +98,13 @@ async def send(request, **kwargs): assert error_message in ex.value.message -async def test_imds_request_failure_docker_desktop(): +@pytest.mark.parametrize("error_ending", ("network", "host", "foo")) +async def test_imds_request_failure_docker_desktop(error_ending): """The credential should raise CredentialUnavailableError when a 403 with a specific message is received""" error_message = ( "connecting to 169.254.169.254:80: connecting to 169.254.169.254:80: dial tcp 169.254.169.254:80: " - "connectex: A socket operation was attempted to an unreachable network." # cspell:disable-line + f"connectex: A socket operation was attempted to an unreachable {error_ending}." # cspell:disable-line ) probe = mock_response(status_code=403, json_payload={"error": error_message}) transport = mock.Mock(send=mock.Mock(return_value=get_completed_future(probe)))