5

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;
    }
WooHoo
  • 1,912
  • 17
  • 22

3 Answers3

7

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.

WooHoo
  • 1,912
  • 17
  • 22
3

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);
midgetspy
  • 669
  • 1
  • 5
  • 8
  • I am trying to replicate what you have done here. I keep getting an ASN1 corrupted data when attempting to read the key. How did you set-up / import the key into secrets manager? – JDBennett Aug 03 '21 at 10:58
  • I just copied the base-64 string out of my pem file and into secrets manager, in the same format as required by AWS ACM. – midgetspy Aug 04 '21 at 15:49
  • Interesting. That doesn’t work for me. The ACM console has you include the ——BEGIN RSA — — … The SDK client I suspect handles that when you download the certificate. Loading the PK into secrets manager, I have to strip off the header and footer so I can convert it to a byte array. Convert.FromBase64String() throws an exception if the header and footer included. – JDBennett Aug 07 '21 at 14:28
  • @JDBennett you only need to do this for the secrets manager part, I added the key with ——BEGIN RSA —— in the certificate manager but omitted when putting it in the secrets manager and this worked, no issue. What issue were you experiencing when you did this? – Jade Nov 26 '21 at 16:46
  • 1
    It is possible to get the private key out of ACM in .Net with AmazonCertificateManagerClient.ExportCertificate (https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CertificateManager/MCertificateManagerExportCertificateExportCertificateRequest.html). You pass the cert ARN and a password, and get back an object with the certificate, chain, and private key. – giterdone Aug 15 '22 at 13:44
2

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

ikkentim
  • 1,639
  • 15
  • 30