Library or service name.
Azure.Security.KeyVault.Certificates
Is your feature request related to a problem? Please describe.
KeyVaultCertificate only exposes the public key, and for the private key the Azure.Security.KeyVault.Secrets must be used, where a x509certificate2 must be manually constructed from the byte array.
It would be more convenient to have the option to use the CertificateClient to get a x509certificate2 directly. It would also be more consistent with the import API, which does mandate the private key to reside in the cert. So if I upload the private key, it makes sense for me to be able to download it - if I drew an analogy to secrets, it would be having to use one library to create a secret and another library to retrieve it...
Yes, the private key is necessary during import or the certificate would not otherwise be useful, but the ability to export the key requires that it be marked as exportable when importing. We will take this into consideration for future planning.
Sure, if it's not exportable, throw an exception - perfectly reasonable IMHO.
Leaving unassigned till we can schedule this work.
My primary use case for KeyVault is storing and retrieving X509 certificates.
This was awkward in the old API, needing to reconstitute an X509Certificate2 from a byte[].
In the new API I can't even get a byte[], and the obvious place to look for retrieving certificates (Azure.Security.KeyVault.Certificates) only returns the public key (which I could store in a public fileshare).
Is there any clarity on the support timeline for Microsoft.Azure.KeyVault?
Are there plans (with dates) for extending the new API or documenting this obvious use case?
Right now I'm stuck in limbo between a lib with an undefined future and one that doesn't seem complete or fully documented.
Microsoft.Azure.KeyVault will be deprecated soon (/cc @AlexGhiondea), but even in that older code the Cer member was just the public key (that's what the Key Vault service returns). We don't do anything different in the new code when deserializing it to a byte[] array. Can you describe how you did with this with the older KeyVaultClient?
At this time, we haven't scheduled the work. We'd gladly accept a PR that pulls in (as shared source) enough of the KeyClient and models to expose this. In the meantime, I've published a sample at https://docs.microsoft.com/samples/azure/azure-sdk-for-net/get-certificate-private-key/ that shows how.
You're right, since it was all one client I didn't notice I was pulling in from secrets:
var provider = new AzureServiceTokenProvider();
using (var client = new KeyVaultClient(
new KeyVaultClient.AuthenticationCallback(
provider.KeyVaultTokenCallback)))
{
// Get cert data and password from vault and reconstruct X509
var certSecret = await client.GetSecretAsync(baseUrl, "CertName");
var bytes = Convert.FromBase64String(certSecret.Value);
var cert = new X509Certificate2(bytes, (string)null,
X509KeyStorageFlags.MachineKeySet);
...
}
My new theoretical code looks a little funny:
var client = new SecretClient(_vaultUrl, new DefaultAzureCredential(true));
var contents = await client.GetSecretAsync("CertName");
var cert = new X509Certificate2(
Convert.FromBase64String(contents.Value.Value), // <- Any docs on Azure.Response<KeyVaultSecret>
(string)null,
X509KeyStorageFlags.MachineKeySet);
So does Azure.Response<KeyVaultSecret>.Value.Value actually contain the string-encoded certificate bytes?
Also, looks like your example is for the Azure command line, not the C# API?
The sample README uses the CLI only to set up a test environment. The code you can browse or download has basically what you did in your snippet.
Yes, Response<KeyVaultSecret>.Value actually gets the KeyVAultSecret, and KeyVaultSecret.Value gets the full certificate. Our API docs are available at https://docs.microsoft.com/dotnet/api/azure.security.keyvault.secrets.secretclient.getsecretasync?view=azure-dotnet, which is also conveniently listed in our README for each package.
The ParseSecretName method in your sample should be part of the library, IMO.
In the UI, or the CLI, everything I touch is a certificate. But in code, I need to get a secret?
And, the Secrets SDK requires a string, but the certificate SDK gives me a URI (?!?)
I'm sure there is a good reason that the certificate points to a specific secret version/instance using a URI. How about an overload in the Secrets API that accepts a URI? Making the consumer find this thread/sample to put the pieces together is sub-optimal.
Our preview out now includes APIs for parsing the URI.
I am using 4.2.0-beta3. I can get the X509Certificate2 object calling DownloadCertificate but I am still getting "Key not valid for use in specified state." The apps credentials have all access to the certificate in question.
What am I missing?
Uri url = new Uri("<KeyVault in Azure>");
DefaultAzureCredential credential = new DefaultAzureCredential();
CertificateClient certificateClient = new CertificateClient(url, credential);
Response<X509Certificate2> response = certificateClient.DownloadCertificate("<Certificate name in the KeyVault>");
X509Certificate2 certificate = response.Value;
certificate.PrivateKey.ToXmlString(true);
On what line? What's the stack trace? If it's the last line, please open a new bug with the stack trace. You should also check if the key was marked exportable when originally created or imported. If not, only the public key is stored and will be downloaded (the private key isn't accessible).