简体   繁体   中英

Getting a secret from azure keyvault with node from a linux vm with MSI

I'm having issues getting a secret from azure keyvault using the azure-keyvault package from a node application running on a linux vm on azure.

I am using the following code:

import * as KeyVault from 'azure-keyvault';
import * as msRestAzure from 'ms-rest-azure'

function getKeyVaultCredentials(){
    return msRestAzure.loginWithVmMSI();
}

function getKeyVaultSecret(credentials) {
    let keyVaultClient = new KeyVault.KeyVaultClient(credentials,null);
    return keyVaultClient.getSecret("my keyvault url here", 'my keyvault secret name here', "", null,null);
}

getKeyVaultCredentials().then(
    getKeyVaultSecret
).then(function (secret){
    //not getting here....
}).catch(function (err) {
    //...error handling...
});

I am getting a 401 response when calling getSecret. There are permissions set to the machine on the keyvault and MSI. In the error I get there doesn't seem to be any header of authentication or a token, although I do see a header which looks like an authentication header on the response.

Is there anything I am missing in my implementation?

EDIT: It looks like the example I've shared here would have worked if I would use

msRestAzure.loginWithVmMSI({resource: 'https://vault.azure.net' });

instead of calling it with no params.

In your keyvault, make sure you have added the service principal(created automatically by enabling the MSI) in the Access policies with correct secret permission. Then try to click Click to show advanced access policies -> choose the Enable access to Azure Virtual Machines for deployment option-> Save.

Here is a code sample, you could check the part of retrieving a secret value.

var http = require('http');
const KeyVault = require('azure-keyvault');
const msRestAzure = require('ms-rest-azure');


var server = http.createServer(function(request, response) {
    response.writeHead(200, {"Content-Type": "text/plain"});
});

// The ms-rest-azure library allows us to login with MSI by providing the resource name. In this case the resource is Key Vault.
// For public regions the resource name is Key Vault
msRestAzure.loginWithAppServiceMSI({resource: 'https://vault.azure.net'}).then( (credentials) => {
    const keyVaultClient = new KeyVault.KeyVaultClient(credentials);

    var vaultUri = "https://" + "<YourVaultName>" + ".vault.azure.net/";

    // We're setting the Secret value here and retrieving the secret value
    keyVaultClient.setSecret(vaultUri, 'my-secret', 'test-secret-value', {})
        .then( (kvSecretBundle, httpReq, httpResponse) => {
            console.log("Secret id: '" + kvSecretBundle.id + "'.");
            return keyVaultClient.getSecret(kvSecretBundle.id, {});
        })
        .then( (bundle) => {
            console.log("Successfully retrieved 'test-secret'");
            console.log(bundle);
        })
        .catch( (err) => {
            console.log(err);
        });

    // Below code demonstrates how to retrieve a secret value

    // keyVaultClient.getSecret(vaultUri, "AppSecret", "").then(function(response){
    //     console.log(response);    
    // })
});

For more details, you could refer to :Set and retrieve a secret from Azure Key Vault using a Node Web App .

This has now been simplified in the new @azure/keyvault-secrets package where the SecretClient can take the DefaultAzureCredential from the @azure/identity package which in turn is smart enough to use the MSI details when run in your VM as well as the developer credentials like VS Code or Azure CLI when in your local dev environment. You can learn more about this in the readme for @azure/identity

With this, your code would be simplified to

const { SecretClient } = require("@azure/keyvault-secrets");
const { DefaultAzureCredential } = require("@azure/identity");

async function getValue(secretName, secretVersion) {
  const credential = new DefaultAzureCredential();
  const client = new SecretClient(KEY_VAULT_URI, credential);
  const secret = await client.getSecret(secretName);
  return secret.value;
}

To move your application from the older azure-keyvault package which is now deprecated, you can see the migration guide to the new @azure/keyvault-secrets

You can use read-azure-secrets which will retrieve all secrets from the azure key vault.

For example

let secretClient = require('read-azure-secrets');

async function loadKeyVaultValues() {

    let applicationID = '';
    let applicationSecret = '';
    let vaultURL = 'https://<your-key-vault-name>.vault.azure.net/';
    let secrets = await secretClient.getSecrets(applicationID, applicationSecret, vaultURL);

    secrets.forEach(secret => {
        console.log(secret);
    });

}

loadKeyVaultValues();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM