c# Azure Key Vault

Accessing Azure Key Vault Value From Console App Without Deploying To Azure Platform

Matt 2020/06/29 15:50:28
4306

What Is Azure Key Vault

Azure Key Vault, Safeguard cryptographic keys and other secrets used by cloud apps and services.

Microsoft Azure Key Vault is a cloud-hosted management service that allows users to encrypt keys and small secrets by using keys that are protected by hardware security modules (HSMs). Small secrets are data less than 10 KB like passwords and .PFX files. An HSM is a secure, tamper-resistant piece of hardware that stores cryptographic keys. Keys can also be imported or generated in HSMs that have been certified to FIPS 140-2 level 2 standards.

What I'm saying is, Azure Key Vault can help us to store sensitive data (maybe an API key or else), and keep them safe.

Step By Step

Let's do it. Follow the steps, to grab some important information.

Register App On Azure AD

In order to access Key Vault REST api successfully, we need to register an app on Azure AD first. Please follow these steps.

Azure AD

img "Azure AD"

App registration

img "App registration"

New registration

img "New registration"

Register an application

img "Register an application"

Certificates & secrets

img "Certificates & secrets"

Client secrets: write down the secret. A secret string that the application uses to prove its identity when requesting a token. Also can be referred to as application password.

img "Client secrets"

PS: You have ONLY one shot to write the secret down, after it generated. If missed, you must create a new one.

Key Vault Overview: remember that DNS Name, and directory id.

img "Key Vault Overview"

App registrations: please write down the directory id, and client id, we will need them.

img "App registrations: directory id, client id"

Secret Identifier

img "Secret Identifier"

Get Vault Value by Using SDK

An easier way to get vault value, by using SDK.

NuGet packages

Azure Key Vault ref packages

img "azure key vault ref packages"

As we choose a quick way to get vault value by using SDK, and we will need to Install these packages from NuGet.

Azure.Identity

Azure.Security.KeyVault.Secrets

Microsoft.Azure.KeyVault

Microsoft.IdentityModel.Clients.ActiveDirectory

System.Net.Http.Json

They will be great help.

Code sample

    private static string GetVaultValue()
    {
        var client = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(AccessToken));
        const string vaultBaseUrl = "https://<your-key-vault-name>.vault.azure.net"; // aka DNS name from overview
        const string secretName = "<your-secret-name>";
        var secret = client.GetSecretAsync(vaultBaseUrl, secretName).GetAwaiter().GetResult();
        return secret.Value;
    }

    private static async Task<string> GetAccessToken(string authority, string resource, string scope)
    {
        // AAD: App Registration client id
        const string clientId = "<your-client-id>";
        // AAD: App Registration client secret
        const string clientSecret = "<your-client-secret>";

        var credential = new ClientCredential(clientId, clientSecret);
        var context = new AuthenticationContext(authority, TokenCache.DefaultShared);
        var result = await context.AcquireTokenAsync(resource, credential).ConfigureAwait(false);
        return result.AccessToken;
    }

Get Vault Value by Calling REST APIs

Define models

Before we continue programming, we should generate few models for json parsing.

public class KeyVaultResult
{
    [JsonPropertyName("value")]
    public string Value { get; set; }
    [JsonPropertyName("id")]
    public string Id { get; set; }
    [JsonPropertyName("attributes")]
    public Attributes Attributes { get; set; }
}

public class Attributes
{
    [JsonPropertyName("enabled")]
    public bool Enabled { get; set; }
    [JsonPropertyName("created")]
    public int Created { get; set; }
    [JsonPropertyName("updated")]
    public int Updated { get; set; }
    [JsonPropertyName("recoveryLevel")]
    public string RecoveryLevel { get; set; }
}

public class AccessCredential
{
    [JsonPropertyName("token_type")]
    public string TokenType { get; set; }
    [JsonPropertyName("expires_in")]
    public int ExpiresIn { get; set; }
    [JsonPropertyName("ext_expires_in")]
    public int ExtExpiresIn { get; set; }
    [JsonPropertyName("access_token")]
    public string AccessToken { get; set; }
}

Here's a tip: Edit > Paste Special > Paste JSON As Classess. It provide us a quick way to generate models in a short time.

Paste JSON As Classess

img "Paste JSON As Classess"

Handmade by calling Api

Basically, these handmade methods are original calling by SDK usage, and encapsulate to an easier way to people to use it.

    private static string GetAccessTokenHandMade(HttpClient httpClient)
    {
        const string azureADDirectoryID = "<your-directory-id>";
        var reqUrl = $"https://login.microsoftonline.com/{azureADDirectoryID}/oauth2/v2.0/token";
        var req = new HttpRequestMessage(HttpMethod.Post, reqUrl)
        {
            Content = new FormUrlEncodedContent(new Dictionary<string, string>()
            {
                { "grant_type", "client_credentials" },
                { "client_id", "<your-client-id>" },
                { "client_secret", "<your-client-secret>" },
                { "scope", "https://vault.azure.net/.default" }
            })
        };

        var response = httpClient.SendAsync(req).GetAwaiter().GetResult();
        if (response.StatusCode == System.Net.HttpStatusCode.OK)
        {
            var ret = response.Content.ReadFromJsonAsync<AccessCredential>().GetAwaiter().GetResult();
            return ret?.AccessToken;
        }
        else
        {
            throw new Exception(response.ReasonPhrase);
        }
    }
	

Yes, of course. we still could do it by using Postman.

get access token

img "get access token"

    private static string GetVaultHandMade(HttpClient httpClient, string token)
    {
        // ref: https://docs.microsoft.com/en-us/rest/api/keyvault/getsecret/getsecret
        // Key-Vault Secret Identifier with api-version
        const string reqUrl = "https://<your-key-vault-name>.vault.azure.net/secrets/<your-secret-name>/<secret-version>?api-version=7.0";
        httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");

        try
        {
            var resp = httpClient.GetFromJsonAsync<KeyVaultResult>(reqUrl).GetAwaiter().GetResult();
            return resp?.Value;
        }
        catch (Exception ex)
        {
            return $"{ex.Message}\n{ex.InnerException?.Message}";
        }
    }
get secret value

img "get secret value"

And now, we can get the secret value from Console Application.

Here is an online reference code demo on fiddle. When you open it, you will get some errors. There's nothing to worry about, please change some keys: Directory Id, Client id, Client secret, DNS Name, Secret Identifier, to your own ones. Once you changed them, re-run the program, and you will get vault value on the platform.

Enjoy it.


References:

Key Vault

Azure Key Vault basic concepts

Security in Azure App Service

Quickstart: Register an application with the Microsoft identity platform

Get Secret API

Using Azure Key Vault references with Azure Functions or App Service

Using Managed Service Identity with Key Vault from a .NET Azure Function

Delegates

Using HTTPClientFactory in .NET Core Console Application

Matt