Is it possible in a .NET Core application to retrieve a certificate from AWS Certificate Manager and use it in a HttpClient post?

Viewed 3064

My .Net core application makes a post request to an external web service using HttpClient. The external web service requires a certificate to validate against.

The certificates are installed in AWS and I have an ARN that points to the certificate.

Is it possible to get the certificate programitically from AWS Certificate Manager and use this in my HtppClient, for example this is the code I would use normally to add a certificate but I need to get it from AWS.

   private HttpClientHandler HttpClientHandler()
   {
        var handler = new HttpClientHandler
        {
            ClientCertificateOptions = ClientCertificateOption.Manual,
            SslProtocols = SslProtocols.Tls12
        };
        handler.ClientCertificates.Add(new X509Certificate2("cert.crt")); //TODO: fetch from AWS.
        return handler;
    }
3 Answers

So, it's possible.

I installed AWSSDK.Core and AWSSDK.CertificateManager from NuGet.

Then, I created a credentials file for AWS, see instructions from Amazon https://docs.aws.amazon.com/cli/latest/userguide/cli-config-files.html

Next, I used the AmazonCertificateManagerClient to get the certificate.

AmazonCertificateManagerClient client = new AmazonCertificateManagerClient();
var certificates = client.GetCertificateAsync(arn).Result;

I then converted the certificate from string to bytes and then add to the handler.

var handler = new HttpClientHandler{
  ClientCertificateOptions = ClientCertificateOption.Manual,
  SslProtocols = SslProtocols.Tls12
};

byte[] toBytes = Encoding.ASCII.GetBytes(certificates.Certificate);
var cert = new X509Certificate2(toBytes);

handler.ClientCertificates.Add(cert); 
var httpClient = new HttpClient(handler);

Obviously, not production worthy code, hope it helps.

As mentioned by Zack the accepted answer does not work. It does retrieve a certificate out of ACM but it is not usable as a client certificate for HttpClient because it has no private key.

As far as I can tell there is no way to get the private key out of ACM so I ended up putting it in SecretsManager and doing something like:

var certManagerClient = new AmazonCertificateManagerClient();
var awsCert = certManagerClient.GetCertificateAsync(arn).Result;
byte[] awsBytes = Encoding.ASCII.GetBytes(awsCert.Certificate);
var cert = new X509Certificate2(awsBytes);

var secretsManagerClient = new AmazonSecretsManagerClient();
var privateKey = secretsManagerClient.GetSecretValueAsync(new GetSecretValueRequest { SecretId = secretId }).Result.SecretString;
byte[] privateKeyBytes = Convert.FromBase64String(privateKey);
var privateKey = RSA.Create();
privateKey.ImportRSAPrivateKey(new ReadOnlySpan<byte>(privateKeyBytes), out _);
var certWithPrivateKey = cert.CopyWithPrivateKey(privateKey);

And then using certWithPrivateKey in my HttpClientHandler:

var handler = new HttpClientHandler { ClientCertificateOptions = ClientCertificateOption.Manual };
handler.ClientCertificates.Add(certWithPrivateKey);

If you use the AWS SDK you can get certificates using the AmazonCertificateManagerClient. See the AWS SDK documentation for details. (select Amazon.CertificateManager > AmazonCertificateManagerClient)

Related