How to use Azure Key Vault in npmrc file? - node.js

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!

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.

keyVaultClient - get a secret

I am using Azure function to do an action, in this action I need to get a secret from a keyvault.
I am using this code in order to get the secret
var azureServiceTokenProvider = new AzureServiceTokenProvider();
var keyVaultClient = new KeyVaultClient((authority, resource, scope) => azureServiceTokenProvider.GetAccessTokenAsync(resource));
var secret= await keyVaultClient.GetSecretAsync($"https://{KeyVaultName}.vault.azure.net/", "SecretName");
When I run it locally it's work but when I run the function in azure I am getting an error "Forbidden"
How can I get the secret from a keyVault inside my azure function?
Thanks!
Forbidden might indicate that the identity assumed by the Azure Function does not have access rights over the specific Azure Key Vault.
From the Azure Portal or via CLI/API, head into the relevant Azure Key Vault resource -> Access Policies -> Add Access Policy -> Assign the Azure Function identity with the following permissions:
Secret List
Secret Get
Instead of using the KeyVault client inside your Function, you can have it much more simple if you can use KeyVault-referenced AppSettings (depends a bit of course on your scenario if thats an option). https://learn.microsoft.com/en-us/azure/app-service/app-service-key-vault-references
Then you can simple use the secret like any setting and read it as an Env variable.

Combine Azure Key Vault with Azure App Configuration

I am pretty new to Azure and I am trying to simulate a real production environment.
So, I've deployed a .netcore 3.1 app to an AppService resource. This web app is able to get the configuration from two other services - KeyVault and App Configuration. I already have configuraed the AppService identity.
I can get the keys from KeyVault using the following code:
var settings = config.Build();
var web = settings["KeyVault:Name"];
var clientId = settings["KeyVault:ClientId"];
var clientSecret = settings["KeyVault:ClientSecret"];
config.AddAzureKeyVault($"https://{web}.vault.azure.net/",
clientId,
clientSecret);
As I can get the keys from the App Configuration:
var settings = config.Build();
config.AddAzureAppConfiguration(settings["AppSettings:Endpoint"]);
And I am able to use them both at the same time through identities and AppConfiguration's key reference
var settings = config.Build();
config.AddAzureAppConfiguration(options =>
{
options
.Connect(settings["AppSettings:Endpoint"])
.ConfigureKeyVault(kv =>
{
kv.SetCredential(new DefaultAzureCredential());
});
});
So, my question is about the code snippet #3: is it safe to store the AppSettings:Endpoint value the appconfig.json in a production environment? To be clear, I am referring to this value:
Moreover, I found here and explanation on how to use the two services together. But first of all, that solution doesn't work for me - I get an Azure.Identity.CredentialUnavailableException: 'ManagedIdentityCredential authentication unavailable, no managed identity endpoint found.'.
On the second hand, he's not clear on where to store the AppSettings:AppConfiguration:Endpoint and AppSettings:Identity:ClientId values, it doesn't answer to my first question then.
Thanks in advance
Short answer - the endpoint https://[your_app_name].azconfig.io is safe to leave anywhere. It does nothing without the other parts that make up the connection string.
Long answer - you can and probably should store the parts that are sensitive, connection strings and their parts, in Key Vault as secrets. If your code needs those values you have options on how to get the values to it. Consider using the web config (it's equivalent as a place that would ordinarily have the secret values but put Key Vault references there instead. Your way works also. Keep in mind that your way may require a code change if your config shifts away from what you've coded.
Be sure that your access policy on KV is using the service principal of your app. I repeat, be sure that your access policy on KV is using the service principal of your app. It will likely only need permissions "list" and "get" for secrets and NOTHING ELSE.
Do not store secrets in your web config or its equivalent. Key Vault is almost free, it's so cheap. I don't deploy apps without them getting their own vault as part of the solution.
Leave comments if this is unclear or needs web references.
You should be able to use Azure Marange Identity to connect to APP Configuration. Use Azure.Identity preview version.
c# Example
https://github.com/nishanperera/Azure-App-Configuration-With-Key-Vault

Hiding a secret in Terraform for Azure with a caveat

So I am trying to find someway to hide a secret in Terraform. The caveat is the secret is a Service Principal that is used to connect to our Key Vault. I can't store the secret in the Key Vault as it hasn't connected to the Key Vault yet at that point. This is part of my main tf file.
provider "azurerm" {
alias = "kv_prod"
version = "1.28"
tenant_id = "<tenant id>"
subscription_id = "<sub id>"
client_id = "<SP client id>"
client_secret = "<SP secret>"
}
This is used further down my module to store Storage Account keys and other secrets. It just happens to be in a Prod subscription that not everyone has access to.
Has anyone run into something like this? If so, how would you go about securing that secret?
#maltman There are several ways to hide a secret in terraform. Here is a blog that talks about them:
https://www.linode.com/docs/applications/configuration-management/secrets-management-with-terraform/
However if you are only concerned about encrypting the secrets file while checking in and checking out from git, you can use something like git-crypt
You would have to create a couple of files:
variables.tf -> Define your variables here
variable "client_secret" {
description = "Client Secret"
}
terraform.tfvars -> Give the value of the variable here
client_secret = 'your-secret-value'
Now use git-crypt to encrypt terraform.tfvars while checking into git
For your requirements, I think there are two secure ways for you in comparison.
One is that stored the credential as environment variables so that you do not expose the secret in the tf files. Here's the example.
The other one is that you can log in with the credential for Azure CLI, then just need to set the subscription without exposing the secret in the tf file. Here's the example.
The above two ways are that what I think is secure and possible for you. Hope it helps you.
Terraform doesn't have this feature but by using third party integration it can be achieved.
Storing Secret in Terraform:
Terraform has an external data resource that can be used to run an external program and use the return value further. I have used Ansible vault feature to encrypt and decrypt the secrets and store it encrypted in repository rather as plaintext.
data "external" "mysecret" {
program = ["bash", "-c", "${path.module}/get_ansible_secret.sh"]
query = {
var = "${var.secret_value}"
vault_password_file = "${path.module}/vault-password.sh"
# The file containing the secret we want to decrypt
file = "${var.encrypted_file}"
}
}
Refer the working example: github example
Going to create an ADO pipeline to handle this instead where the code just does not have to be available.

How to give MSI enabled Function App access to Key Vault?

I have a Function App with Managed service identity (MSI) enabled.
I'm trying to use this Function App to access a secret from my Key Vault.
I have added the code into my Function App to retrieve the secret.
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var secret = await keyVaultClient.GetSecretAsync("https://test-prototype-vault.vault.azure.net/secrets/batman/guidhere").ConfigureAwait(false);
I receive the following error:
Microsoft.Azure.WebJobs.Script: One or more errors occurred. Microsoft.Azure.KeyVault: Access denied.
I think this is because I need to (as described in the link above).
You may need to configure the target resource to allow access from
your application. For example, if you request a token to Key Vault,
you need to make sure you have added an access policy that includes
your application's identity.
I don't know how to do that. I have gone to my Key Vault and tried to add an Access Policy - I can't find the application to Select Principle option.
Setup of Azure Function.
What happens when I try to add the principal.
This blog has details but you need to go into key vault and give the function app access to secrets in a new access policy
https://medium.com/#jeffhollan/getting-key-vault-secrets-in-azure-functions-37620fd20a0b
The name of your function app should show in list of users

Resources