I am using Azure Key Vault to protect our keys and secrets, but I am unsure how I can use the KeyBundle I retrieve using the .net SDK. How can I create an X509Certificate2 objec
You cannot use the KeyBundle result as an X509Certificate2 object because it simply represents the public key portion of a key pair here (no issuer). See the methods in KeyVaultClientExtensions for functions to encrypt data, verify signatures, etc. using this KeyBundle object.
November 2020 Update:
In the current version of Azure Key Vault, Certificates are a first class concept rather than a type of Secret.
If your Key Vault instance already has a certificate with an exportable private key, you'd fetch it and hydrate an X509Certificate2
as follows:
Create the required clients using a DefaultAzureCredential
var certClient = new CertificateClient(new Uri("https://yourKeyVault.vault.azure.net/"), new DefaultAzureCredential());
var secretClient = new SecretClient(new Uri("https://yourKeyVault.vault.azure.net/"), new DefaultAzureCredential());
Get the certificate, which includes a link to the private key secret.
Note: The latest (4.2.0 beta) version of the Key Vault Secrets library includes a helper class called KeyVaultSecretIdentifier that does this parsing for you.
Response<KeyVaultCertificateWithPolicy> certResponse = await certClient.GetCertificateAsync("testCert");
// Get the secretId and parse out the parts needed to fetch the secret.
Uri secretId = certResponse.Value.SecretId;
var segments = secretId.Segments;
string secretName = segments[2].Trim('/');
string version = segments[3].TrimEnd('/');
Get the secret for the certificate and use it to construct a new X509Certificate2
.
Response<KeyVaultSecret> secretResponse = await secretClient.GetSecretAsync(secretName, version);
KeyVaultSecret secret = secretResponse.Value;
byte[] privateKeyBytes = Convert.FromBase64String(secret.Value);
var cert = new X509Certificate2(privateKeyBytes);
For more information about the latest Key Vault Certificate and Secret clients, see their respective README docs here:
Azure.Security.KeyVault.Certificates (migration guide from the old version)
Azure.Security.KeyVault.Secrets (migration guide from the old version)
When you import / create a certificate in KeyVault, 3 entities are created:
Certificate - contains all the relevant details about the certificate, including its public part (i.e. public key, validity period, thumbprint etc.)
Secret - contains the private key (which is the private part of the certificate) in base64
Key - I don't know, but irrelevant for this thread.
You could create X509Certificate2
object with either the Certificate object or the Secret object.
In case you want the X509Certificate2
to contain the private key, then of course you would need to fetch the Secret entity's value and do the following:
SecretBundle certificatePrivateKeySecretBundle =
await keyVaultClient.GetSecretAsync(certificateIdentifierSecretPart);
byte[] privateKeyBytes = Convert.FromBase64String(certificatePrivateKeySecretBundle.Value);
X509Certificate2 certificateWithPrivateKey = new X509Certificate2(privateKeyBytes, (string) null, X509KeyStorageFlags.MachineKeySet);
The certificateIdentifierSecretPart
equals the certificate's secret part path:
https://<vault name>.vaults.azure.net/secrets/<certificate name>
Note the /secrets/ path.