I'm trying to do a very simple HTTP/SSL request with a client certificate in an Azure Web App (App Service) with .NET. For context, it's to write logs to an Elasticsearch cluster.
Enabling tracing for System.Net
and System.Net.Sockets
shows that the request fails while attempting to load the private key for the client certificate - which was loaded in memory.
System.Net Information: 0 : [4064] SecureChannel#49205706 - Certificate is of type X509Certificate2 and contains the private key.
System.Net Information: 0 : [4064] AcquireCredentialsHandle(package = Microsoft Unified Security Protocol Provider, intent = Outbound, scc = System.Net.SecureCredential)
System.Net Error: 0 : [4064] AcquireCredentialsHandle() failed with error 0X8009030D.
System.Net.Sockets Verbose: 0 : [0764] Socket#8628710::Dispose()
System.Net Error: 0 : [0764] Exception in the HttpWebRequest#53036123:: - The request was aborted: Could not create SSL/TLS secure channel.
System.Net Error: 0 : [0764] Exception in the HttpWebRequest#53036123::EndGetRequestStream - The request was aborted: Could not create SSL/TLS secure channel.
Searching for AcquireCredentialsHandle() failed with error 0X8009030D
reveals that it's apparently to do with permissions in the certificate store - which I am not using.
My guess is that for some reason, AcquireCredentialsHandle
tries to access a certificate store, which it fails to do because of the sandboxed environment of Azure Web Apps.
It definitely does not seem to be an IIS-specific issue, because again, it fails in a regular executable. The following code fails in a simple webjob.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
namespace IFHM
{
class Program
{
static void Main(string[] args)
{
Environment.CurrentDirectory = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path));
var req = (HttpWebRequest) WebRequest.Create("https://myapp.com");
req.Method = "GET";
req.ServerCertificateValidationCallback = (sender, cert, chain, errors) => true;
req.ClientCertificates.Add(new X509Certificate2("client.pfx"));
try
{
var resp = req.GetResponse();
var respStr = new StreamReader(resp.GetResponseStream()).ReadToEnd();
Console.WriteLine(respStr);
}
catch (WebException e)
{
Console.Error.WriteLine(e);
var errRespStr = new StreamReader(e.Response.GetResponseStream()).ReadToEnd();
Console.WriteLine(errRespStr);
}
}
}
}
It seems that you need to upload the .pfx file to the Azure WebApp and first make it accessible to your application code. You do this with the WEBSITE_LOAD_CERTIFICATES app setting.
You could get the detail steps and demo code from azure official document.
User contributions licensed under CC BY-SA 3.0