Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Azure Key Vault for storing username and password

I am working on an app where I want to store username and password for service account which will be used by a daemon service.

The idea is to provide application administrator a dashboard where he / she can enter credentials for service account and later it can be stored somewhere safe.

I can think of storing it in secure place like Azure Vault and get it from there whenever required. However, key and secret are different entities in Azure Vault. I can not store them somewhere as a combination.

Has anyone done that before? Or is there any better alternative to store credentials in Azure?

like image 925
Rahul Patil Avatar asked Oct 20 '16 03:10

Rahul Patil


1 Answers

You can use the technique that Azure blob storage uses to encrypts data at rest (envelope method): https://docs.microsoft.com/en-us/azure/storage/storage-client-side-encryption

KeyVault has the ability to Wrap / Unwrap (encrypt/decrypt) symmetric keys so they are safe for you to store along with your encrypted data.

Here are the general steps:

  1. Generaete an AES key (256 bit, CBC mode) using RNGCryptoServiceProvider
  2. Encrypt the data (credentials)
  3. Save the Initialization Vector (IV). You can just concat it to the ciphertext byte array for retrieval later when you want to decrypt - IV doesn't need protected.
  4. Wrap (encrypt) the genereated AES Symmetric Key using the Key in KeyVault.
  5. Store Wraped AES Key, IV, CipherText, and Key Version (GUID at the end of the URI in KeyVault).
  6. Make sure you grant the Wrap / Unwrap permissions in KeyVault to the Application Registration created in Azure AD. Use the Client Id / Application ID + Key or pfx to auth to Azure in GetToken().

You'll need these nuget packages:

Install-Package Microsoft.Azure.KeyVault
Install-Package Microsoft.Azure.KeyVault.Extensions
Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory -Version 2.16.204221202

Get a ref to KeyVaultKeyResolver

KeyVaultKeyResolver cloudResolver = new KeyVaultKeyResolver(Utils.GetToken);

// Example GetToken implementation
public class Utils {
    // Retrive JWT token to be used for KeyVault access.
    internal async static Task<string> GetToken(string authority, string resource, string scope)
    {
        var authContext = new AuthenticationContext(authority);
        // Could use pfx instead
        ClientCredential clientCred = new ClientCredential(
            ConfigurationManager.AppSettings["clientId"],
            ConfigurationManager.AppSettings["clientSecret"]);

        AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);

        if (result == null)
            throw new InvalidOperationException("Failed to obtain the JWT token.");

        return result.AccessToken;
    }
}

Once you have have KeyResolver, you can get an IKey to Wrap / Unwrap your AES symmetric key as follows...

Wrap / Encrypt AES Key

The keyID is the URI from Key Vault and aesKey is the byte[] of your AES key to encrypt:

// Resolve an IKey by Key ID from URI in KeyVault
var keyEncryptionKey = cloudResolver.ResolveKeyAsync(keyId, CancellationToken.None).GetAwaiter().GetResult();

// Take our gen'ed AES Key and wrap (encrypt) it.
Tuple<byte[], string> wrappedKey = keyEncryptionKey.WrapKeyAsync(aeskey, null /* algorithm */, CancellationToken.None).GetAwaiter().GetResult();

The byte[] in the Tuple contains the encrypted bytes of the symmetric key and the name of the algorithm used. Save these as meta data with your ciphertext.

Unwrap / Decrypt AES key

Call using the same key (key version matters), algoName is the name of the algorithm used to wrap the key (e.g. "RSA-OAEP").

// Retrieve the IKey by Key ID
// Unwrap Key
byte[] aesKey = rsa.UnwrapKeyAsync(wrappedKeyBytes, algoName, CancellationToken.None).GetAwaiter().GetResult();

Other details to think about are the Key backup/recovery and key rotation.

like image 173
m0nty Avatar answered Nov 15 '22 05:11

m0nty