Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

X509Certificate2 failing in Azure Webjobs calling Google API

I have a console app that is scheduled using Azure WebJobs. The execution always fails when attempting to read the private key of p12 certificate. Interestingly enough I can't catch the exception, I've had to use good old Console.WriteLine to debug.

Here is my snippet of code:

var certificate = new X509Certificate2(data, "notasecret", X509KeyStorageFlags.Exportable);

ServiceAccountCredential credential = new ServiceAccountCredential(
 new ServiceAccountCredential.Initializer(serviceAccountEmail)
 {
     Scopes = new[] { BigqueryService.Scope.Bigquery }
 }.FromCertificate(certificate));

Other posts have mention that the flags should be X509KeyStorageFlags.MachineKeySet but unfortunately that causes an error in the Google API. It requires the X509KeyStorageFlags.Exportable flag to be set.

Can anyone confirm that X509KeyStorageFlags.Exportable is usable on Azure Websites and WebJobs?

like image 795
Perry Stathopoulos Avatar asked Sep 16 '14 16:09

Perry Stathopoulos


2 Answers

Using X509KeyStorageFlags.Exportable is not usable in IIS. I've tried it with Azure Webjobs, Azure Websites and IIS on my own virtual machine. It works in a development environment when using IISExpress because the process is running in the user's context.

So for it work in an IIS context (including Webjobs), it has to be set to MachineKeySet but the Google API will fail since it needs the private key.

The solution to my problem was actually pretty simple, create a console app that creates the X509Certificate2 object with Exportable flag set and then call ToXmlString(). Here is the snippet:

var certificate = new X509Certificate2(data, "notasecret", X509KeyStorageFlags.Exportable); var xml = certificate.PrivateKey.ToXmlString(true);

I then save the XML and use that XML to create an RSACryptoServiceProvider like this:

var rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(xmlKey);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
 {
  Scopes = new[] { BigqueryService.Scope.Bigquery },
  Key = rsa
 });

Hope this helps others.

like image 125
Perry Stathopoulos Avatar answered Oct 21 '22 20:10

Perry Stathopoulos


This solution worked in an Azure setting. However I also found one for my needs that was much simpler. Simply add additional Flags so everyone is happy...

 var certificate = new X509Certificate2(data,"notasecret",
                       X509KeyStorageFlags.MachineKeySet | 
                       X509KeyStorageFlags.PersistKeySet | 
                       X509KeyStorageFlags.Exportable);

I found this solution

like image 37
jmcnly Avatar answered Oct 21 '22 18:10

jmcnly