Setting Azure EnvironmentCredential() - python-3.x

I am on an Azure VM with a dynamic IP adress. When I am logged in, I am able to retrieve secrets using the following python code without any issues;
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
credential = DefaultAzureCredential()
secret_client = SecretClient(vault_url="https://xxxx/", credential=credential)
secret = secret_client.get_secret("testSecret")
I need to retrieve the secrets when the VM is on but when I am not logged to enable other processes to run. I noticed the code above was failing when I am logged off. The system admin gave me the AZURE_CLIENT_ID, AZURE_CLIENT_SECRET,AZURE_TENANT_ID and VAULT_URL for me to set them as EnvironmentCredentials.
I set them in the CMD as follows;
SETX AZURE_CLIENT_ID "pppp"
SETX AZURE_CLIENT_SECRET "mmmm"
SETX AZURE_TENANT_ID "kkkk"
SETX VAULT_URL "xxxx"
When I check the system environment settings, I can see they have been set
I tried retrieving my secret using this code,
from azure.keyvault.secrets import SecretClient
VAULT_URL = os.environ["VAULT_URL"]
credential = EnvironmentCredential()
client = SecretClient(vault_url=VAULT_URL, credential=credential)
password = client.get_secret("testSecret").value
I got this error
raise HttpResponseError(response=response, model=error)
azure.core.exceptions.HttpResponseError: (Forbidden) The user, group or application 'pppp;iss=https://sts.windows.net/kkkk/' does not have secrets get permission on key vault 'name of my vault-vault;location=australiasoutheast'. For help resolving this issue, please see https://go.microsoft.com/fwlink/?linkid=2125287
Question
The system admin confirms the credentials issued are the service principal's correct details.
How can correct this or what am I doing wrong?
Is there a way for me to print DefaultAzureCredentials so that I set the same as EnvironmentCredential because I believe why I recover secrets when I am logged in is that the credentials are cached when I sign in?
Your help will highly be appreciated.

How can correct this or what am I doing wrong?
The error means your service principal does not have the correct secret permission in your keyvault -> Access policies, to solve the issue, add the application(service principal) mentioned in the error message to the Access policies with the Get secret permission in your keyvault in the azure portal. If it still not work, please try to set the environment variables in the System variables instead of User variables for xxx as shown in your screenshot.
Is there a way for me to print DefaultAzureCredentials so that I set the same as EnvironmentCredential because I believe why I recover secrets when I am logged in is that the credentials are cached when I sign in?
No need to do this, the DefaultAzureCredential attempts to authenticate via the following mechanisms in this order, see here. If you didn't set the environment variables before, it should use the managed identity of your VM to authenticate.

Related

Azure Key Vault: The user, group, or app does not have secrets set permission on key vault

I am creating a script using Azure CLI that will automatically generate an App Registration (service principal), and then use that App Registration to create a secret that will be stored in Azure Key Vault.
However, I am getting the following error:
The user, group or application 'appid=04b07795-8ddb-461a-bbee-02f9e1bf7b46;oid=0ec2b0e8-daeb-46a8-b627-0d4f61f87157;numgroups=134;iss=https://sts.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47/' does not have secrets set permission on key vault 'asakeyabcfelaqpgsfnxcy;location=eastus'. For help resolving this issue, please see https://go.microsoft.com/fwlink/?linkid=2125287
Can anyone provide guidance on what this ID is and how to resolve this error? This is not my App Registration Object ID or App ID.
I think there're 2 points you're now concerning, one is you failed to add secret, another is the app id in the error message is not the one you registered.
I think you've followed the document to execute the cli command, so I just want to explain the second point. Pls allow me show you a code sample for a better explanation.
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
public async Task<IActionResult> PrivacyAsync()
{
var kvUri = "https://your_vault_name.vault.azure.net/";
var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());
_ = await client.SetSecretAsync("test0311", "hello");
return View();
}
When we want to add key vault secret to azure, we need to provide a credential so that our operations are authenticated. This is the DefaultAzureCredential() here, and it has several sources to get the authentication like screenshot below.
That means if someone sets the environment variables for authentication, then it will cover the information you entered when executing cli command, this may usually cause the issue that the app is different from what you set. I think you may follow this document to check all your configurations and try again, or you can directly add environment variables with the app you registered on your computer.
By the way, pls don't forget to add access policy in azure portal for the azure ad app you registered.

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")

How to use Azure Key Vault in npmrc file?

I have a secret personal access token (only for building purposes) in my .npmrc file. As this secret is exposed, I thought of replacing this using Azure Key Vault. I haven't found any documentation around it. When I created the personal token before, I had given it only packaging/building access. How can I achieve this, please help me with this? Or is there any better way to include the personal access token in the .npmrc file?
Since you confirmed you are using Azure DevOps for your build, you don't need to maintain PAT in the .npmrc file. Just keep your npm registry URL there (I assume the private npm registry is also in the Azure DevOps) like below:
registry={your npm registry URL}
always-auth=false
Now, in the build pipeline, add npm Authenticate task before npm install.
- task: npmAuthenticate#0
inputs:
workingFile: <relative path to your .npmrc file>
Providing secrets to your resource can be done in many ways.
Some resources in Azure allow you to specify environment variables through the Azure CLI. Here's an example with the Azure container instances: link.
On Azure, once you have a Key Vault instance, you can use your Key Vault to provide secrets to your App Service and Azure Function instances. This is documented here: link, with a focus for Azure Resource Manager templates, which is specially useful for automated deployments.
Although the following is explained in the documentation link above, the general picture on how to use Key Vault secrets from other Azure resources requires the following:
Make a user assigned identity or Azure Active Directory application.
Grant access to this identity (or AAD app) by going to the Access Policies of your Key Vault (this can be done through the portal, of course), and giving your identity at least read access to your Key Vault.
After that, create a secret on your Key Vault, go to the secret details and copy the "Secret Identifier". This will be a URI similar to: https://myvault.vault.azure.net/secrets/mysecret/.
That's the URI you can use to bring Key Vault secrets to other resources.
You'll be able to access this secret from other resources by ensuring the resource has access to the same identity, and by providing the URI through a syntax similar to: #Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/).
For example, if you link an Azure Function to the same identity you granted read access to your Key Vault, you can provide a secret through environment variables by setting configuration properties in your resource. By going to the Azure Portal, locating your resource, then going to Configuration, then to Application settings, if you proceed to add the name of your environment variable, and as the value something similar to: #Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/), you'll be providing the expected environment variable with the expected secret value to your resource.
The final approach I can think of is by using the #azure/keyvault-secrets client. If using an NPM library to retrieve Key Vault secrets sounds interesting, this is the dependency for you. All the information needed to work with this library should be available on NPM: same link. But in any case, a sample using this client would look as follows:
const { DefaultAzureCredential } = require("#azure/identity");
const { SecretClient } = require("#azure/keyvault-secrets");
const credential = new DefaultAzureCredential();
const client = new SecretClient(`https://my-key-vault.vault.azure.net`, credential);
async function main() {
const secretName = "MySecretName";
const latestSecret = await client.getSecret(secretName);
console.log(`Latest version of the secret ${secretName}: `, latestSecret);
}
main();
You could use this library to load your secrets at any point while your service or program is running.
Please let me know if this information is useful for you. I'm here to help!

Issue in accessing Azure Keyvault - DefaultAzureCredential failed to retrieve a token

I'm accessing values stored in an Azure Keyvault. Using Visual Studio for my development I'm able to get the data from Keyvault without any issues. However, when the code is deployment to different environments like Test or Stage, I'm getting an error.
The credentials that I'm using to access the Keyvault is stored in the Environment Variables of the project.
Visual Studio > Project > Right-click on Properties > Debug > Environment variables.
The environment variables contain:
Azure_Client_Id
Azure_Tenant_Id
Azure_Client_Secret
The code to access the Keyvault is below and this works fine when used through Visual Studio.
var KeyVaultData = new Azure.Security.KeyVault.Secrets.SecretClient(vaultUri: new Uri(#"https://{VaultName}.vault.azure.net/"), credential: new Azure.Identity.DefaultAzureCredential());
However when this is deployed to other environments, I'm getting the error below:
Exception occured - Azure.Identity.CredentialUnavailableException: DefaultAzureCredential failed to retrieve a token from the included credentials.
EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
ManagedIdentityCredential authentication unavailable, no managed identity endpoint found.
SharedTokenCacheCredential authentication unavailable. No accounts were found in the cache.
I don't have access to Azure, but was informed that everything has been setup correctly.
Any help on resolving this is very much appreciated.
EDIT:
New code based on the solution given:
const string tenantId = "-----";
const string clientId = "-----";
const string clientSecret = "-----";
var keyvaultCredentials = new ClientSecretCredential(tenantId, clientId, clientSecret);
var KeyVaultData= new SecretClient(new Uri(#"https://{VaultName}.vault.azure.net/"), keyvaultCredentials);
The DefaultAzureCredential will use environment variables automatically in local, so if you have set the environment variables, of course, it will work. If the environment variables are not available, it will try ManagedIdentityCredential,
SharedTokenCacheCredential,
InteractiveBrowserCredential, when you deploy your code to the environments you mentioned, they are all not available, so you will get the error.
In this case, if you want to deploy your code to different environments, you need to use ClientSecretCredential, pass the parameters directly to ClientSecretCredential(String, String, String), then the code will work anywhere.
public ClientSecretCredential (string tenantId, string clientId, string clientSecret);

Resources