-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[KeyVault][Certificates] - Get certificate AND private key? #7647
Comments
@sadasant can you take this one? |
@julie-ng I'm gathering information to give you the best response I can. I'll be back as soon as possible 🌞 |
Hello @julie-ng, Thank you so much for getting in touch with us! We're here to help. When a certificate is retrieved from the KeyVault Here I'm going to share some ways of retrieving your certificate's full information. Then I'll mention what further actions we'll be taking to address your feedback. The long route to obtain the public certificate in PEM formatFrom the buffer you receive in the // Let's authenticate our CertificateClient
const credential = await new ClientSecretCredential(
process.env.AZURE_TENANT_ID,
process.env.AZURE_CLIENT_ID,
process.env.AZURE_CLIENT_SECRET
);
const keyVaultName = process.env.KEYVAULT_NAME;
const keyVaultUrl = `https://${keyVaultName}.vault.azure.net`;
const client = new CertificateClient(keyVaultUrl, credential);
// Creating the certificate
const certificateName = "MyCertificate";
const createPoller = await client.beginCreateCertificate(certificateName, {
issuerName: "Self",
subject: "cn=MyCert"
});
const keyVaultCertificate = await createPoller.pollUntilDone();
// Making the PEM formatted public certificate
const { cer } = keyVaultCertificate;
const base64CER = Buffer.from(cer).toString("base64");
const PEMFormattedCER = [
"-----BEGIN CERTIFICATE-----",
base64CER,
"-----END CERTIFICATE-----"
].join("\n");
// We could write this into a .pem file
fs.writeFileSync("MyCertificatePublic.pem", PEMFormattedCer); There are better ways to do this, but first, let's get some context. What happened with the private key of my certificate?Azure's KeyVault's design makes sharp distinctions between Keys, Secrets and Certificates. The KeyVault service's Certificates features were designed making use of it's Keys and Secrets capabilities. Let's evaluate the composition of a KeyVault Certificate:
The KeyVault service stores both the public and the private parts of your certificate in a KeyVault secret, along with any other secret you might have created in that same KeyVault instance. With this separation comes considerable control of the level of access you can give to people in your organization regarding your certificates. The access control can be specified through the policy you pass in when creating a certificate.
You can also dive in the security features of Azure and how they operate in conjunction with KeyVault through the docs section: Secure access to a key vault. How to obtain the private keyKnowing that the private key is stored in a KeyVault Secret, with the public certificate included, we can retrieve it by using the KeyVault-Secrets client, as follows: // Using the same credential object we used before,
// and the same keyVaultUrl,
// let's create a SecretClient
const secretClient = new SecretClient(keyVaultUrl, credential);
// Assuming you've already created a KeyVault certificate,
// and that certificateName contains the name of your certificate
const certificateSecret = await secretClient.getSecret(certificateName);
// Here we can find both the private key and the public certificate, in PKCS 12 format:
const PKCS12Certificate = certificateSecret.value!;
// You can write this into a file:
fs.writeFileSync("myCertificate.p12", PKCS12Certificate); Note that, by default, the contentType of the certificates is PKCS 12. Though specifying the content type of your certificate will make it trivial to get it's secret key in PEM format, let's explore how to retrieve a PEM secret key from a PKCS 12 certificate first. Using
You can also use
Note that in both cases, openssl will ask you for the password used to create the certificate. If you have used my sample code so far, the certificate created didn't specify a password, so you can either leave it blank, or append How to obtain the private key directly in PEM formatIf you will be using PEM formatted certificates in an everyday basis, you can tell Azure's KeyVault service to create and manage your certificates in PEM format by providing the // Creating the certificate
const certificateName = "MyCertificate";
const createPoller = await client.beginCreateCertificate(certificateName, {
issuerName: "Self",
subject: "cn=MyCert",
contentType: "application/x-pem-file" // Here you specify you want to work with PEM certificates.
});
const keyVaultCertificate = await createPoller.pollUntilDone();
// Getting the PEM formatted private key and public certificate:
const certificateSecret = await secretClient.getSecret(certificateName);
const PEMPair = certificateSecret.value!;
console.log(PEMPair); Keep in mind that, in this format, your public certificate will be in the same blob of content as your private key. You can use the PEM headers to extract them accordingly. Shouldn't the KeyVault Certificates Client make this easier?Your issue has highlighted the importance of providing an easier way to retrieve the full certificate. Internally, we have talked about this during the past months, but we haven't added it to our roadmap yet. We are listening, so please stay tuned to the changes that we will be making in these clients. Keep in mind that some other changes might come first. What we can do right awayI've made an initial pull request that adds a couple of integration tests that show how to retrieve the private key and public certificate out of both a PKCS 12 and a PEM formatted KeyVault Certificate here: #7650 I'll be using this PR to bring my teams attention to this issue, so that we can define paths of improvement for the TypeScript client and the clients that we've made for other languages. @julie-ng, does this help? Please don't hesitate to report any other issue you might have already experienced, or any that might come up in the future. Every interaction with our customers help us deliver the best product we can. |
Wow, thanks @sadasant for the very thorough response. I did not know I could fetch the secret, just by using the different client.
Ideally as a developer, I would want to just pull the certs out of Key Vault and pass them in memory (no need to write them to files) to I think this is where we need to improve. Azure has its own way of thinking that doesn't necessarily align with how everyone else in the OSS world does things. In this case, the Next StepsI want to test fetching the secret as you wrote above - and then putting it into a function. Will let you know how that goes. I also plan on throwing this use-case together into an blog article, which could be used for docs. Will share if I get to it tomorrow :) |
@julie-ng sounds good! |
Here's an attempt to improve our READMEs. I'm taking feedback from the docs team and I'm also mentioning information relevant to #7647.
@sadasant thanks for the thorough changes. The customer use case with the Azure Function turned out to be a Networking issue or at least out of SDK scope. So closing for now. |
Dear @sadasant, I'm trying to retrieve the private key following your instructions. Unfortunately, I get the following error message when running e.g.
Same error when trying to extract the private key out of "myCertificatesSecret.p12". The file "myCertificatesSecret.p12" seems to be not in correct PKCS12 format. Please note: I've downloaded the certificates corresponding Key Vault Secret using the Azure CLI command Do you have any idea what I am missing? Thanks for your assistance! P.S.: When downloading the certificate as pfx manually from Azure Key Vault, I can extract the private key with the openssl commands provided. EDIT |
Hello @swisman , thank you for the feedback! I’ll be opening an issue based on your comment. Give me some time to process things on my side. |
If you are a developer and bump into this, there is a gist that will help you a lot. Check this https://gist.github.com/erikbern/756b1d8df2d1487497d29b90e81f8068?permalink_comment_id=4503917#gistcomment-4503917 |
Use Case
As a developer, I want to secure communication between services with client/server certificates. I want to authenticate via client certificate to a server using a custom
httpsAgent
per Node.js documentationBut... how to get both the public certificate AND private key from key vault?
This is standard, not a special library and common practice to require:
-----BEGIN CERTIFICATE-----
part-----BEGIN PRIVATE KEY-----
partProblem: Azure SDK does not return private key
The @azure/keyvault-certificates SDK shows how to get the certificate. But how do you get the private key?
The standard
https
Node.js library expects this, as copied from official node.js docsThe Azure SDK returns something in this format:
Problem: Public Certificate is (technically) incomplete?
When the
cer
buffer is converted to a string, it is missing the-----BEGIN CERTIFICATE-----
and-----END CERTIFICATE-----
parts.Why?
Ask
How is a developer supposed to create a custom https agent with client certificate stored in Key Vault using Key Vault certificates?
At this point, I am questioning the utility (or lack thereof) in using Key Vault certificate abstraction. I am thinking it's better just to use secrets, pure strings.... as suggested here https://social.msdn.microsoft.com/Forums/azure/en-US/c9d515e1-22c4-4e7b-84ea-70fb38a86b1e/azure-key-vault-nodejs-certificate?forum=AzureKeyVault
The text was updated successfully, but these errors were encountered: