Azure App Service to Key Vault - Managed Identity Access Issue using Python - azure-web-app-service

I have a setup as below.
Azure App Service connects to Azure Key Vault using Azure-Identity Python SDK. Azure KV's data plane has access policy enabled to include App Service's managed identity. I have used the following code to connect to KV from app service webjobs.
import os
import json
from azure.identity import DefaultAzureCredential, ManagedIdentityCredential
from azure.keyvault.secrets import SecretClient
keyVaultName = os.getenv('KeyVaultNm')
KVUri = f"https://{keyVaultName}.vault.azure.net"
credential = DefaultAzureCredential()
_sc = SecretClient(vault_url=KVUri, credential=credential)
srv = _sc.get_secret("server-nm").value
print(f'KV Secret: {srv}')
This setup had been working without any issues for almost a year to allow App service extract secrets from KV but over the last weekend, it started failing with the following error.
[08/29/2022 09:14:14 > 6f77be: ERR ] ManagedIdentityCredential.get_token failed: <urllib3.connection.HTTPConnection object at 0x00000234348D8AC8>: Failed to establish a new connection:
[WinError 10049] The requested address is not valid in its context
[08/29/2022 09:14:14 > 6f77be: ERR ] DefaultAzureCredential failed to retrieve a token from the included credentials.
[08/29/2022 09:14:14 > 6f77be: ERR ] Attempted credentials:
Any idea what's this error is regarding? Will this happen due to any firewall issue?
PS: The same code works well inside a VM using its managed identity and retrieves secrets from KV. The issue happens only when the code is run from Webjobs.

Related

Local azure function runtime fails to retrieve a token from the included credentials despite being logged in

I'd like to read blobs in a storage container, based off this Quickstart. I've already been assigned the role of Storage Account Contributor. Using VS code, I followed the tutorial (in VS code) by starting with az login, then start my environment localy, and finally executing the function. I get the following warning:
DefaultAzureCredential failed to retrieve a token from the included credentials.
Attempted credentials:
EnvironmentCredential: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
Visit https://aka.ms/azsdk/python/identity/environmentcredential/troubleshoot to troubleshoot.this issue.
ManagedIdentityCredential: ManagedIdentityCredential authentication unavailable, no response from the IMDS endpoint.
SharedTokenCacheCredential: SharedTokenCacheCredential authentication unavailable. No accounts were found in the cache.
AzureCliCredential: Failed to invoke Azure CLI
To mitigate this issue, please refer to the troubleshooting guidelines here at https://aka.ms/azsdk/python/identity/defaultazurecredential/troubleshoot.
my code, following the tutorial, looks like:
import azure.functions as func
from azure.storage.blob import BlobServiceClient, BlobClient, ContainerClient
from azure.identity import DefaultAzureCredential
def main(req=None) -> func.HttpResponse:
account_url = "https://<name>.blob.core.windows.net"
default_credential = DefaultAzureCredential()
blob_service_client = BlobServiceClient(account_url, credential=default_credential)
container_client = blob_service_client.get_container_client('<name>')
blob_list = container_client.list_blobs()
for b in blob_list:
return func.HttpResponse(f'{b.name}')
Not sure what else I should do if I've already done the az login part.
I tried in my environment and got below results:
DefaultAzureCredential failed to retrieve a token from the included credentials.
Attempted credentials:
EnvironmentCredential: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
Visit https://aka.ms/azsdk/python/identity/environmentcredential/troubleshoot to troubleshoot.this issue.
ManagedIdentityCredential: ManagedIdentityCredential authentication unavailable, no response from the IMDS endpoint.
SharedTokenCacheCredential: SharedTokenCacheCredential authentication unavailable. No accounts were found in the cache.
AzureCliCredential: Failed to invoke Azure CLI
To mitigate this issue, please refer to the troubleshooting guidelines here at https://aka.ms/azsdk/python/identity/defaultazurecredential/troubleshoot.
The above error suggest you need to define at least one of the credential like environmentcredential,ManagedIdentitycredential,sharedtokencachecredential,AzureCliCredential. to retrieve token.
You can follow this document to retrieve the token with credential.
I followed the document in terminal I tried az login for signing in and used the below code to get the list of blobs using Http trigger function.
Code:
import azure.functions as func
import logging
from azure.storage.blob import BlobServiceClient, BlobClient, ContainerClient
from azure.identity import DefaultAzureCredential
def main(req=None) -> func.HttpResponse:
logging.info('Python HTTP trigger function processed a request.')
account_url = "https://venkat123.blob.core.windows.net"
default_credential = DefaultAzureCredential()
blob_service_client = BlobServiceClient(account_url, credential=default_credential)
container_name="test"
container_client = blob_service_client.get_container_client(container_name)
#blob_list = container_client.list_blobs()
blobs=[]
for b in container_client.list_blobs():
blobs.append(b.name)
logging.info(b.name)
return func.HttpResponse(f"Listed blobs in container: {blobs}")
The above code executed successfully and listed blobs from the storage container.
Console:
Browser:

Azure Retrieve Secret from key vault

I am following the Microsoft documentation to retrieve secrets from a key vault using python sdk.
The code and explanation offered by Microsoft leads to this code:
import os
import cmd
from azure.keyvault.secrets import SecretClient
from azure.identity import DefaultAzureCredential
keyvault_name = f'https://<Keyvaultname>.vault.azure.net/'
KeyVaultName = "<Keyvaultname>"
credential = DefaultAzureCredential()
client = SecretClient(vault_url=keyvault_name, credential=credential)
print(" done.")
print(f"Retrieving your secret from {KeyVaultName}.")
retrieved_secret = client.get_secret("test")
print(f"Your secret is '{retrieved_secret.value}'.")
According to my understanding, the DefaultCredentials are the one configured in the az login which is fine, my code runs just fine but I keep getting this message in the terminal.
done.
Retrieving your secret from <KeyvaultName>.
EnvironmentCredential.get_token failed: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
ImdsCredential.get_token failed: ManagedIdentityCredential authentication unavailable, no managed identity endpoint found.
ManagedIdentityCredential.get_token failed: ManagedIdentityCredential authentication unavailable, no managed identity endpoint found.
SharedTokenCacheCredential.get_token failed: SharedTokenCacheCredential authentication unavailable. Multiple accounts
were found in the cache. Use username and tenant id to disambiguate.
I presume that this warnings are due the fact that I have multiple subscription in my azure portal.
I was wondering, how can I get rid of those and set the credentials for only a single subscription?
Thank you so much for any help and explanation you can offer me.
Generally speaking, I would not worry about this warning. When you use DefaultAzureCredential, SDK tries the following credential options in that order (Reference):
EnvironmentCredential
ManagedIdentityCredential
SharedTokenCacheCredential
VisualStudioCredential
VisualStudioCodeCredential
AzureCliCredential
AzurePowerShellCredential
InteractiveBrowserCredential
SDK moves from one credential options to another if that credential option fails. The warning message is just a way for the SDK to tell you what all credential options it has tried.
However if you still want to get rid of this message, there are a few options available to you:
Exclude the credential options that you do not want SDK to try when using DefaultAzureCredential. You can specify those via exclude_xxx_credential option in the constructor. For example, if you want to exclude EnvironmentCredential, you would specify exclude_environment_credential=True in the DefaultAzureCredential constructor. SDK will skip those credential methods. Please see this link for all constructor options.
Use specific credential option. For example, if you always want to use Azure CLI credentials, then instead of using DefaultAzureCredential you can use AzureCliCredential.

Azure Identity and Key Vault: How to use managed identities to authenticate?

I am trying to use the Azure Identity package to access Key Vault secrets. I am using AzureML and it has its own system assigned managed identity ("Identity" in the left-hand blade).
This system assigned managed identity yields me an Object (principal) ID. It also allows me to set Azure role assignments. This managed identity is a: (1) contributor, (2) administrator, and (3) key vaults secret user for the key vault service I want to use with my secrets.
Inside AzureML, on a Python notebook, if I run:
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
# load key vault data
credential = DefaultAzureCredential()
secret_client = SecretClient(vault_url="--KV URL--", credential=credential)
secret_client.get_secret("secret-i-want")
# fails
EnvironmentCredential.get_token failed: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
Fair enough, it tells me to basically create a service principal and put its details into the environment. But, I don't want to. I want to use the Managed Identity which is apparently best in class for security because I am not storing secrets anywhere.
Looking through documentation, there exists a way to allegedly use the Managed Identity, but I cannot make it work. https://azuresdkdocs.blob.core.windows.net/$web/python/azure-identity/1.6.0/azure.identity.html#azure.identity.ManagedIdentityCredential
I am uncertain how to get a client ID for AzureML or its managed identity.
from azure.identity import ManagedIdentityCredential
credential2 = ManagedIdentityCredential(identity_config={"object_id": "principal-id-for-aml-managed-identity"})
secret_client = SecretClient(vault_url="--KV URL--", credential=credential2)
# hangs with no error
I have tested in my environment.
You can use AzureCliCrendential instead of ManagedIdentityCredential.
In the terminal, login using below command to login using System Assigned Identiy
az login --identity
Now, use the below pyhton notebook script :
from azure.identity import AzureCliCredential
from azure.keyvault.secrets import SecretClient
managed_identity = AzureCliCredential()
secret_client = SecretClient(vault_url="https://radapakv.vault.azure.net/", credential=managed_identity)
value = secret_client.get_secret("test")

Azur Key Vault - CORS Error after using Azure KeyVault in Azure App Service

I'm trying to get value from Azure Key Vault. It's working well in localhost but when we deploy to Azure App Service. it shows CORS Error:
Access to XMLHttpRequest at 'https://xxxxxxxx.azure-api.net/xxxxxx/api/xxx/xxxx' from origin 'https://xxxxxxx.azurewebsites.net' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I'm using below code in my .Net Core Web API:
const string secretName = "XXXXXXXXXXXXXX";
var kvUri = $"https://xxxxxxxx.vault.azure.net";
var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());
var secret = client.GetSecretAsync(secretName).GetAwaiter().GetResult().Value;
conString = secret.Value;
Thanks in advance
CORS isn't permitted for Key Vault at this time because it's not designed to be used by browsers. I spoke with the KV product team about this a good while back and created a UserVoice submission for this feature a few years ago: https://feedback.azure.com/forums/906355-azure-key-vault/suggestions/34753195-enable-cors-for-key-vault
Were you logged in to Azure when you tested this application locally?
Also for app service to access key vault you would need some authentication mechanism
like service principal or managed Identity.
You can check this link for your reference:
Access key vault from app service

Accessing Azure Storage via certificate based service principal credentials; azure.identity vs azure.common.credentials

I have experimented trying to access Azure Blob Storage using service principal credentials through Python SDK & have some confusions I thought the community could help with.
#1 azure.common.credentials vs azure.identity-------------------------------------------------
I have noticed two different python packages in Azure having credential classes.
- azure.common.credentials
- azure.identity
What is the difference between the two, and when should one be used against other? More specifically, when attempting to work with Azure service principals,
**azure.identity** provides both **ClientSecretCredential & CertificateCredential** so we can use either shared secret, or SSL certificate.
**azure.common.credentials** package provides only the **ServicePrincipalCredentials** class that needs a shared secret, and there is no counterpart for working with certificate credentials.
Am I missing something? I am looking to use certificate based service principal.
#2 ServicePrincipalCredentials works, but ClientSecretCredential fails ------------------------------------------------
My test code to access Azure storage works successfully with ServicePrincipalCredentials class.
But fails with ClientSecretCredential class with Exception message: 'ClientSecretCredential' object has no attribute 'signed_session'"
Appreciate any help with understanding why. There is no difference in the code apart from instantiating the credentials to be one of the two classes above.
The #2 issue above is important mainly because of #1. I am looking to use certificate based Auth, but can't find a supporting class under azure.common.credentials.
Python Environ details:
>python3 --version
Python 3.6.9
>pip3 freeze | grep -i azure
azure-common==1.1.25
azure-core==1.5.0
azure-identity==1.3.1
azure-mgmt-resource==9.0.0
azure-mgmt-storage==10.0.0
azure-storage-blob==12.3.1
msrestazure==0.6.3
snippets from my code:
# for credential classes
from azure.identity import ClientSecretCredential
from azure.identity import CertificateCredential
# for storage & other resource mgmt classes
from azure.mgmt.resource import ResourceManagementClient
from azure.mgmt.storage import StorageManagementClient
tenant_id = params['tenant-id']
client_id = params['client-id']
client_secret = params['secret']
subscription_id = params['subscription-id']
creds = ClientSecretCredential(tenant_id=tenant_id, client_id=client_id, client_secret=client_secret)
# create resource group
resource_client = ResourceManagementClient(creds, subscription_id)
# create storage group, access keys etc
storage_client = StorageManagementClient(creds, subscription_id)
When attempting with certificate rather than secret, here is the code snippet for creating credential instance; rest of code is same.
client_keycert_path = params['cert-path']
creds = CertificateCredential(tenant_id =tenant_id, client_id = client_id, certificate_path = client_keycert_path)
The current situation is misleading, I admit, here's a few details as of today (monitor the situation here https://github.com/Azure/azure-sdk-for-python/issues/9310):
For azure-storage-blob, azure.common is used for storage SDK <= 2.x, and azure-identity is used for storage SDK >= v12.x.
For any package starting with azure-mgmt-xxx, azure-common is still the official way. Check this issue for workaround on how to write mgmt code that uses azure-identity (https://github.com/Azure/azure-sdk-for-python/issues/9310)
This will change SOON, by summer 2020 mgmt SDKs should support azure-identity out of the box.
Hope this helps, feel free to open an issue on Github too if there is further questions:
https://github.com/Azure/azure-sdk-for-python/issues
(I work in the Azure SDK team at MS)

Resources