Reputation: 5774
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?
Upvotes: 8
Views: 8507
Reputation: 101
You can use the technique that Azure blob storage uses to encrypts data at rest (envelope method): https://learn.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:
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.
Upvotes: 7