Azure Key Vault integration
The package Lacuna PKI Azure Connector enables usage of certificates and keys stored on Azure Key Vaults to sign documents, issue certificates etc.
To use certificates or keys stored on a key vault, you will need the following parameters:
- Endpoint: the
DnsName
of the key vault, as shown on the Overview menu on Azure Portal - AppId: the Application ID of an application registered on Microsoft Entra ID
- AppSecret: an authentication secret for the application, generated on Certificates & secrets
You will also need to know the name of the certificate or key you intend to use.
Instructions
Tip
If your application uses ASP.NET Core, see the section below
Once you have the required parameters, create an instance of AzureKeyVaultOptions and, with it, an instance of AzureApiAuthenticator:
var options = new AzureKeyVaultOptions() {
Endpoint = "...",
AppId = "...",
AppSecret = "...",
};
var azureApiAuthenticator = new AzureApiAuthenticator(options);
Note
Your application should keep a single instance of AzureApiAuthenticator
(singleton lifetime).
Then, create an instance of AzureCertificateProvider
and request to it a PKCertificateWithKey passing the certificateName
of the certificate:
Note
If you store only the certificates' keys on Azure Key Vault, but not the certificate themselves, read the section below.
var azureCertProvider = new AzureCertificateProvider(options, azureApiAuthenticator);
var certWithKey = await azureCertProvider.GetCertificateWithKeyAsync(/* certificateName */);
Note
The instance of AzureCertificateProvider
should be created and disposed as needed (transient lifetime).
With a PKCertificateWithKey
, you can perform "single step" signatures (as if they were not remote signatures), e.g.:
var signer = new PadesSigner();
signer.SetPdfToSign(/* PDF file path, content or stream */);
signer.SetSigningCertificate(certWithKey);
signer.SetPolicy(PadesPoliciesForGeneration.GetPadesBasic(TrustArbitrators.PkiBrazil));
signer.ComputeSignature();
var signedPdf = signer.GetPadesSignature();
Here follows a complete sample:
// System-wide singletons
Global.AzureKeyVaultOptions = new AzureKeyVaultOptions() {
Endpoint = "...",
AppId = "...",
AppSecret = "...",
};
Global.AzureApiAuthenticator = new AzureApiAuthenticator(options);
...
var azureCertProvider = new AzureCertificateProvider(Global.AzureKeyVaultOptions, Global.AzureApiAuthenticator);
var certWithKey = await azureCertProvider.GetCertificateWithKeyAsync(/* certificateName */);
var signer = new PadesSigner();
signer.SetPdfToSign(/* PDF file path, content or stream */);
signer.SetSigningCertificate(certWithKey);
signer.SetPolicy(PadesPoliciesForGeneration.GetPadesBasic(TrustArbitrators.PkiBrazil));
signer.ComputeSignature();
var signedPdf = signer.GetPadesSignature();
ASP.NET Core
If your application uses ASP.NET Core, add the following to your ConfigureServices
on your app's startup:
public void ConfigureServices(IServiceCollection services) {
...
services.AddAzureKeys()
.Configure(Configuration.GetSection("AzureKeyVault"));
}
Add a section named AzureKeyVault
to your appsettings.json file:
...
"AzureKeyVault": {
"Endpoint": "https://my-key-vault.vault.azure.net/",
"AppId": "...",
"AppSecret": "..."
},
...
Whenever your need to use certificates stored on a Key Vault, request an instance of IAzureCertificateProvider through dependency injection:
using Lacuna.Pki.AzureConnector;
public MyController : ApiController {
private readonly IAzureCertificateProvider azureCertProvider;
public MyController(IAzureCertificateProvider azureCertProvider) {
this.azureCertProvider = azureCertProvider;
}
...
}
From then on, use the key as described previously:
var certWithKey = await azureCertProvider.GetCertificateWithKeyAsync(/* certificateName */);
var signer = new PadesSigner();
signer.SetPdfToSign(/* PDF file path, content or stream */);
signer.SetSigningCertificate(certWithKey);
signer.SetPolicy(PadesPoliciesForGeneration.GetPadesBasic(TrustArbitrators.PkiBrazil));
signer.ComputeSignature();
var signedPdf = signer.GetPadesSignature();
Using certificates having stored only the key on a Key Vault
You may choose to store only your certificate keys on Azure Key Vault, storing on your application the public portion of the certificates (.cer/.crt/.pem files) corresponding to the keys.
In this case, create an instance of AzureKeyProvider and request to it an AzureKey passing the keyName
of the key:
var azureKeyProvider = new AzureKeyProvider(options, azureApiAuthenticator);
var key = await azureKeyProvider.GetKeyAsync(/* keyName */);
Note
The instance of AzureKeyProvider
should be created and disposed as needed (transient lifetime).
The AzureKey
class implements IPrivateKey, and therefore can be used as such:
byte[] toSignHash = ...;
var signature = key.GetSignatureCsp(DigestAlgorithm.SHA256).SignHash(toSignHash);
However, the easiest way to use the key is by calling the GetCertificateWithKey()
method with the certificate
(which may be available as one of your app's configurations, or stored on the database or even hardcoded):
var certificate = PKCertificate.Decode(/* certificate file path or content */);
var certWithKey = key.GetCertificateWithKey(certificate);
For ASP.NET Core applications, instead of asking for an instance of IAzureCertificateProvider through dependency injection,
ask for IAzureKeyProvider and call its GetKeyAsync()
method:
using Lacuna.Pki.AzureConnector;
public MyController : ApiController {
private readonly IAzureKeyProvider azureKeyProvider;
public MyController(IAzureKeyProvider azureKeyProvider) {
this.azureKeyProvider = azureKeyProvider;
}
...
public async Task<ActionResult> Post() {
...
var key = await azureKeyProvider.GetKeyAsync(/* keyName */);
var certificate = PKCertificate.Decode(/* certificate file path or content */);
var certWithKey = key.GetCertificateWithKey(certificate);
var signer = new PadesSigner();
signer.SetPdfToSign(/* PDF file path, content or stream */);
signer.SetSigningCertificate(certWithKey);
signer.SetPolicy(PadesPoliciesForGeneration.GetPadesBasic(TrustArbitrators.PkiBrazil));
signer.ComputeSignature();
var signedPdf = signer.GetPadesSignature();
...
}
}