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?
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With