Get X509 Certificate WITH PRIVATE KEY from Azure Keyvault c#
Asked Answered
K

5

11

I am currently working on an authentication server developed in C #, this one is hosted on an azure function app, and I use a KeyVault where my secrets are stored. My problem is the following, in my keyvault, I store a certificate (certificate + private key) and when I retrieve it in my code, but the private key is not returned. if I test the following method: HasPrivateKey the code returns false ... but if i use the same .pfx in localy the code return me true ... my code:

 var client = new CertificateClient(vaultUri: new Uri("https://diiage2p1g3chest.vault.azure.net/"),credential: new DefaultAzureCredential());
         KeyVaultCertificate kcertificate = client.GetCertificate("try");
         var cert_content = kcertificate.Cer;
       X509Certificate2  certificate = new X509Certificate2(cert_content, "password", X509KeyStorageFlags.EphemeralKeySet);

any idea where the problem comes from?

Kook answered 17/9, 2021 at 13:3 Comment(0)
K
0
 var _keyVaultName = $"VAULTURL";
        var secretName = "CERTIFICATENAME";
        var azureServiceTokenProvider = new AzureServiceTokenProvider();
        var _client = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
        var secret = _client.GetSecretAsync(_keyVaultName, secretName);
        var privateKeyBytes = Convert.FromBase64String(secret.Result.Value);
        certificate = new X509Certificate2(privateKeyBytes, string.Empty);

i solve my probleme like that :)

Kook answered 17/9, 2021 at 13:48 Comment(1)
KeyVaultClient has been deprecated.Oligocene
P
22

CertificateClient has a method that returns a certificate with private key, but it's not obvious that's what it does.

From CertificateClient.DownloadCertificate:

Because Cer contains only the public key, this method attempts to download the managed secret that contains the full certificate. If you do not have permissions to get the secret, RequestFailedException will be thrown with an appropriate error response. If you want an X509Certificate2 with only the public key, instantiate it passing only the Cer property. This operation requires the certificates/get and secrets/get permissions.

So just refactor your code to use DownloadCertificate to get a cert with the private key.

var client = new CertificateClient(new Uri("https://diiage2p1g3chest.vault.azure.net/"),  new DefaultAzureCredential()); 
X509Certificate2 certificate = client.DownloadCertificate("try");
Presignify answered 29/7, 2022 at 14:12 Comment(5)
This is THE answer!Ceratoid
When trying to deploy this to Azure in a webjob , to do the client.DownloadCertificate is there physical file being brought down or is it only in memory ?Fairyfairyland
This method is not showing in the dropdown menu for some reason. I'm using the latest package!Adnah
@Adnah - Still there as of version 4.6.0, not marked for Obsolete either. You might be using the wrong type or an older version of the package that doesn't have it?Presignify
@DanielGimenez, I was using the latest version of a deprecated package :)Adnah
P
6

The simplest way to get the full bytes of a certificate with its private information from keyvault is this. Please note you need permission to get secrets in your client id.

You need the following packages:

Azure.Identity
Azure.Security.KeyVault.Secrets

The following are deprecated:

Microsoft.IdentityModel.Clients.ActiveDirectory
Microsoft.Azure.KeyVault

Code:

using System;
using System.Threading.Tasks;
using Azure;
using Azure.Identity;
using System.Security.Cryptography.X509Certificates;
using Azure.Security.KeyVault.Secrets;

...

public async Task<X509Certificate2> GetCertificate(string certificateName,string clientId, string clientSecret, string keyVaultAddress, string tenantId)
        {
            ClientSecretCredential clientCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
            var secretClient = new SecretClient(new Uri(keyVaultAddress), clientCredential);
            var response = await secretClient.GetSecretAsync(certificateName);
            var keyVaultSecret = response?.Value;
            if(keyVaultSecret != null)
            {
                var privateKeyBytes = Convert.FromBase64String(keyVaultSecret.Value);
                return new X509Certificate2(privateKeyBytes);
            }
            return null;
        }
Pernas answered 23/6, 2022 at 10:29 Comment(0)
P
1

Adding Certificate to KeyVault

  1. Head to KeyVault
  2. Choose Certificates from side-bar
  3. Click +Generate/Import
  4. Select Import
  5. Fill in details
  6. Click Create

Giving Access to Application

To retrieve the public certificate, the application can be added to the access policies, however, to retrieve the full certificate including the private key, a longer procedure is required.

  1. Open Microsoft Entra ID
  2. Select 'App registrations' from side bar
  3. If the application is not yet registered create one
    1. Click '+ New Registration'
    2. Fill details
    3. Click 'Register'
  4. Navigate to KeyVault
  5. Select 'Access policies' from sidebar
  6. Select Permissions Get and List Certificates
  7. As a Principal use the created app registration
  8. Create

Accessing Certificate from Code

  1. Get Vault URI from the vault overview page
  2. Get the certificate name from the vault certificates page
  3. Get application tenant ID, and client ID from App registration in Microsoft Entra ID
  4. Navigate to 'Certificates & Secrets' from the sidebar of App registration
  5. Create a new client secret and the value will be the client's secret
  6. Use the following code
    public X509Certificate2 GetCertificate(string vaultName, string certName, string tenantId, string clientId, string clientSecret)
    {
                ClientSecretCredential credentials = new ClientSecretCredential(tenantId, clientId, clientSecret);
                var client = new SecretClient(new Uri(vaultName), credentials);
                KeyVaultSecret secret = client.GetSecret(certName);
                byte[] certificate = Convert.FromBase64String(secret.Value);
                X509Certificate2 x509 = new X509Certificate2(certificate);
                return x509;
    }
Pretypify answered 1/8 at 10:1 Comment(0)
K
0
 var _keyVaultName = $"VAULTURL";
        var secretName = "CERTIFICATENAME";
        var azureServiceTokenProvider = new AzureServiceTokenProvider();
        var _client = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
        var secret = _client.GetSecretAsync(_keyVaultName, secretName);
        var privateKeyBytes = Convert.FromBase64String(secret.Result.Value);
        certificate = new X509Certificate2(privateKeyBytes, string.Empty);

i solve my probleme like that :)

Kook answered 17/9, 2021 at 13:48 Comment(1)
KeyVaultClient has been deprecated.Oligocene
R
0
        X509Certificate2 certificate;
        ClientSecretCredential clientCredential = new ClientSecretCredential(TenantId,ClientId,ClientSecret);
        var secretClient = new SecretClient(new Uri(KeyVaultUrl), clientCredential);
        var response = await secretClient.GetSecretAsync(individualEnrollment.DeviceId.Replace("-", ""));
        var keyVaultSecret = response?.Value;
        var privateKeyBytes = Convert.FromBase64String(keyVaultSecret.Value);
        certificate = new X509Certificate2(privateKeyBytes);

        
        using (var security = new SecurityProviderX509Certificate(certificate))
        using (var transport = new ProvisioningTransportHandlerAmqp(TransportFallbackType.TcpOnly))
        {
            ProvisioningDeviceClient provClient =
                ProvisioningDeviceClient.Create(GlobalDeviceEndpoint, Scope, security, transport);

            var deviceClient = await ProvisionX509Device(provClient, security);
            
        }
Reclinate answered 24/11, 2022 at 12:39 Comment(2)
Hello, please see meta.stackoverflow.com/editing-help Thanks!Starshaped
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Stupid

© 2022 - 2024 — McMap. All rights reserved.