1

I'm using a Jupyter Notebook within VS Code and the Azure Python SDK to develop locally.

Relevant VS Code Extensions installed:

  • Python
  • Azure Account
  • Azure Storage (maybe relevant?)

Goal:

  • To retrieve a secret from Azure Keyvault using DefaultCredential to authenticate
  • Since there are no environment variables nor ManagedIdentity credentials, DefaultCredential should default to pulling my creds from VS Code

Issue:

import logging
from azure.keyvault.secrets import SecretClient
from azure.identity import DefaultAzureCredential

keyvault_name = "kv-test"
keyvualt_url = "https://" + keyvault_name + ".vault.azure.net"
keyvault_credential = DefaultAzureCredential()
kv_secret1_name = "secret-test"

keyvault_client = SecretClient(vault_url=keyvualt_url, credential=keyvault_credential)

retrieved_key = keyvault_client.get_secret(kv_secret1_name)
        
logging.info("Account key retrieved from Keyvault")

Error:

EnvironmentCredential.get_token failed: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.

ManagedIdentityCredential.get_token failed: ManagedIdentityCredential authentication unavailable, no managed identity endpoint found.

SharedTokenCacheCredential.get_token failed: SharedTokenCacheCredential authentication unavailable. No accounts were found in the cache.

VisualStudioCodeCredential.get_token failed: **Failed to get Azure user details from Visual Studio Code**.

Tried so far:

  • F1, Azure: Sign in
    • Authenticate via browser
    • No change

It looks like the DefaultCredential() cred chain is running, but its unable to ...get Azure user details from Visual Studio Code..

Is this because I'm developing inside a Jupyter Notebook in VS Code or is there another issue going on? It looks like something similar happened to the Python .NET SDK.

ericOnline
  • 1,586
  • 1
  • 19
  • 54

4 Answers4

3

Not sure why it does not work, it looks correct. If you just want to login with visual studio code, you can also use AzureCliCredential. It works on my side.

You could use az login to sign in your account. Then you will get secret using the code.

from azure.keyvault.secrets import SecretClient
from azure.identity import DefaultAzureCredential,AzureCliCredential

keyvault_credential= AzureCliCredential()

secret_client = SecretClient("https://{vault-name}.vault.azure.net", keyvault_credential)
secret = secret_client.get_secret("secret-name")

print(secret.name)
print(secret.value)

enter image description here

enter image description here

For more details, see the Azure Identity client library for Python.

unknown
  • 6,778
  • 1
  • 5
  • 14
  • This worked, thank you. Unfortunately, I'll have to update the code before moving to production. `DefaultCredential` was perfect for handling `DEV`/`PROD` – ericOnline Sep 10 '20 at 22:14
  • 1
    I would like to note that you can define your own custom authentication flow, so there's no need to have different functions for dev and prod. You can use `ChainedTokenCredential`, the same class `DefaultAzureCredential` inherits from, to define your own flow. – leoschet Oct 14 '22 at 09:05
2

There is another easy way to fix this issue. As I quoted in this article, we can make use of the configurations options as preceding.

if self.local_dev:
   print(f"Local Dev is {self.local_dev}")
   self.az_cred = DefaultAzureCredential(
       exclude_environment_credential=True,
       exclude_managed_identity_credential=True,
       exclude_shared_token_cache_credential=True,
       exclude_interactive_browser_credential=True,
       exclude_powershell_credential=True,
       exclude_visual_studio_code_credential=False,
       exclude_cli_credential=False,
       logging_enable=True,
       )

else:
    self.az_cred = DefaultAzureCredential(
      exclude_environment_credential=True, logging_enable=True
      )

Please be noted that the exclude_visual_studio_code_credential and exclude_cli_credential as set to False and others set to True to exclude for the local development and exclude_environment_credential is set to True for the other environment such as production.

You can see these configuations in the default.py file of azure identity package.

enter image description here

Sibeesh Venu
  • 18,755
  • 12
  • 103
  • 140
2

As stated in the docs:

It's a known issue that VisualStudioCodeCredential doesn't work with Azure Account extension versions newer than 0.9.11. A long-term fix to this problem is in progress. In the meantime, consider authenticating via the Azure CLI.

For reference, this is the issue. With that, it is probably smart to disable the vscode credentials: DefaultAzureCredential(exclude_visual_studio_code_credential=True)

Anyway, depending on the version of the vscode extension, we might need to use another mean of authentication, such as SharedTokenCacheCredential, AzureCliCredential or even InteractiveBrowserCredential.

In my case, my authentication was failing on the SharedTokenCacheCredential step, that from what I read this is a shared cache used between Microsoft products. Thus, I assume it is likely the same is happening to others that have Microsoft products installed.

It was failing because my target tenant was not included in this cache. To fix this I had two options: either I disable the shared token credential or I include the target tenant in the shared cache.

For the first option, we can do something similar as for disabling vscode: DefaultAzureCredential(exclude_shared_token_cache_credential=True)

For the second option, I did it as suggested in this blog post from Microsoft: DefaultAzureCredential(additionally_allowed_tenants=[TENANT_ID]). But by looking at the source code, it seems we can achieve the same by:

  • setting the target tenant ID to an environment variable named AZURE_TENANT_ID, or;
  • directly passing the shared cache tenant id: DefaultAzureCredential(shared_cache_tenant_id="TENANT_ID")

Note that the env variable has the benefit that it is used by other authentication methods, namely InteractiveBrowserCredential and VisualStudioCodeCredential.

leoschet
  • 1,697
  • 17
  • 33
  • There is a second possibility that `SharedTokenCacheCredential ` failed with `AADSTS50173: The provided grant has expired due to it being revoked` error. The solution is to delete the cache locally `%LOCALAPPDATA%\.IdentityService\msal.cache` according to [this thread](https://stackoverflow.com/questions/67165101/azure-chainedtokencredential-fails-after-password-change) – Kit Law Mar 21 '23 at 12:45
0

I had the same problem as @leoschet. Authentication was failing on SharedTokenCacheCredential. Exclude it fixed the problem with exclude_shared_token_cache_credential set to true. It can be seen in the SDK code, that when we have configured some credentials method and this will fail, others in the chain are skipped.

for credential in self.credentials:
        try:
            token = await credential.get_token(*scopes, **kwargs)
            _LOGGER.info("%s acquired a token from %s", self.__class__.__name__, credential.__class__.__name__)
            self._successful_credential = credential
            return token
        except CredentialUnavailableError as ex:
            # credential didn't attempt authentication because it lacks required data or state -> continue
            history.append((credential, ex.message))
        except Exception as ex:  # pylint: disable=broad-except
            # credential failed to authenticate, or something unexpectedly raised -> break
            history.append((credential, str(ex)))
            _LOGGER.debug(
                '%s.get_token failed: %s raised unexpected error "%s"',
                self.__class__.__name__,
                credential.__class__.__name__,
                ex,
                exc_info=True,
            )
            break #<------------------

Note the last break in the cycle. So another way would be to have SharedTokenCacheCredential unavailable.