How to upload SSL certificate to IAM or ACM

ยท 1236 words ยท 6 minute read

During the work from time to time we need to upload SSL certificates for Load Balancer to AWS accounts into Amazon Certificate Manager (ACM) or AWS Identity and Access Management (IAM). How to achieve that and on what we need to pay attention, I’ll be follow up onto this article

How to verify SSL certificate before uploading it to AWS ๐Ÿ”—

Before uploading certificate, we need to make sure certificate consistency: when private key match with root certificate, when intermediate chain match root certificate, check end date of certificate and make all data to PEM format. For working with SSL certificates you should have openssl lib pre-installed in your OS1.

Once you have openssl installed on your OS, reporter gives you appropriate SSL certificate stuff, you can verify MD5 hashes of that files to make sure, that private key fit to the root certificate

TIP: PRIVATE KEY IS ENCRYPTED

if you received private key as encrypted, you can decrypt it via openssl tool. So if your key is encrypted, you can decrypt it by following command: openssl rsa -in encrypted.key -out decrypted.key

TIP: CHECK SSL VALIDITY FOR DOMAIN FROM CLI

if you want to check SSL certificate for validity that already installed on webserver level, you can use openssl tool by special: openssl s_client -connect command. Full command example located below

Bash

openssl s_client -connect {fqdn}:443 /dev/null | openssl x509 -inform pem -text

Get MD5 hash for private key:

Bash

openssl rsa -noout -modulus -in server.key | openssl md5

Get MD5 hash for root certificate:

Bash

openssl x509 -noout -modulus -in server.crt | openssl md5

by running commands above you should get something like this2:

> openssl x509 -noout -modulus -in server.crt | openssl md5

66efee91c62456e0559c7b24bd77000f

> openssl rsa -noout -modulus -in server.key | openssl md5

66efee91c62456e0559c7b24bd77000f

Then you can verify subject and issuer of root certificate:

Bash

openssl x509 -text -in server.crt | grep -E '(Subject|Issuer):' | sed 's/^ *//g'

by running command above you can get Issuer info for root certificate

~(root) openssl x509 -text -in server.crt | grep -E '(Subject|Issuer):' | sed 's/^ *//g'

Issuer: C=LT, O=GlobalSign nv-sa, CN=GlobalSign RSA OV SSL CA
Subject: C=US, ST=Illinois, L=Chicago, O=My Company, CN=my.awesome.domain.example.com

Then you should check end date of the certificate, to make sure, that they woudn’t expire soon(1-2 month)

Bash

openssl x509 -enddate -noout -in server.crt

example of command output:

> openssl x509 -enddate -noout -in 78ce6c96-ea3d-485b-9d75-abc133b1b434.pem

notAfter=Jun  5 18:16:12 2023 GMT

Last stage to verify if intermediate chain fit to root certificate by running command:

Bash

openssl verify -untrusted intermediate.pem server.crt

Should be like this:

> openssl verify -untrusted OV_SSL_CA_2018_R3.pem server.crt

server.crt: OK

In some specific cases Issuer could be differ, so command above could produce some errors, that intermediate chain doesn’t match with root certificate. In that case you should follow download appropriate CAfile and Intermediate chain and run verify command below:

Bash

openssl verify -CAfile cafile.crt -untrusted intermediate.pem server.crt

As a result you’ll get the same outout like described above

> openssl verify -CAfile cafile.crt -untrusted RootIntermediateCACert.pem server.crt

server.crt: OK

Optional stage: save certificate and private key in PEM format

Certificate:

Bash

openssl rsa -in server.key -out server-key.pem -outform PEM

Private Key:

Bash

openssl x509 -in server.crt -out server.pem -outform PEM

How to upload SSL certificate to AWS IAM ๐Ÿ”—

As a first step before uploading new certificate, we need to check if this certificate already exists in IAM. You can do that by using one of these following commands:

Bash

aws iam list-server-certificates --query "ServerCertificateMetadataList[]" | jq '.[] | select(.ServerCertificateName | contains("some.awesome.url.example.com"))'

OR

Bash

aws iam list-server-certificates --query "ServerCertificateMetadataList[]" | jq '.[] | select(.Arn | contains("some.awesome.url.example.com"))'

by using command above you’ll get something like this (e.g for unifiedcommunications.me):

> aws iam list-server-certificates --query "ServerCertificateMetadataList[]" | jq '.[] | select(.ServerCertificateName | contains("unifiedcommunications.me"))'
{
  "Path": "/",
  "ServerCertificateName": "unifiedcommunications.me",
  "ServerCertificateId": "ABCDEFGAHJIK09753FD",
  "Arn": "arn:aws:iam::012345678910>:server-certificate/unifiedcommunications.me",
  "UploadDate": "2023-07-12T14:18:57+00:00",
  "Expiration": "2023-11-18T12:16:01+00:00"
}

First you should authorize in AWS account by saml2aws. Then you can upload certificate to AWS by using following command and set name for cert

Bash

aws iam upload-server-certificate --server-certificate-name some-url.example.com --certificate-body file://server.pem --private-key file://server-key.pem --certificate-chain file://intermediate.pem

by using command above you’ll get something like this:

{
    "ServerCertificateMetadata": {
        "Path": "/",
        "ServerCertificateName": "some-url.example.com",
        "ServerCertificateId": "ABCDEFGAHJIK1234FDBSD",
        "Arn": "arn:aws:iam::xxxxxxxxxxxx:server-certificate/some-url.example.com",
        "UploadDate": "2022-05-06T14:11:32+00:00",
        "Expiration": "2023-06-05T18:16:12+00:00"
    }
}

How to upload SSL certificate to AWS ACM ๐Ÿ”—

ACM is known as AWS Certificate Manager that handles the complexity of creating, storing, and renewing public and private SSL/TLS X.509 certificates and keys that protect your AWS websites and applications. By using ACM instead of IAM you’re able to manage SSL certificates on the fly and re-import them if they already exists in ACM, which would update SSL listeners for all LoadBalancers what bind to the particular certificate deployed in ACM.

So, after all necessary checks described above if you’re going ACM (or requestor asked for that), firstly you need to check if certificate for target domain already presented in ACM. You can do that by using following command:

Bash

aws acm list-certificates --query "CertificateSummaryList[]" | jq '.[] | select(.DomainName == "some.awesome.url.example.com")'

by using command above you’ll get something like this (e.g for unifiedcommunications.me):

> aws acm list-certificates --query "CertificateSummaryList[]" | jq '.[] | select(.DomainName == "unifiedcommunications.me")'
{
  "CertificateArn": "arn:aws:acm:eu-west-1:123456789123:certificate/3dc54c37-5ce5-4f46-aeb9-14228a14fbc5",
  "DomainName": "unifiedcommunications.me",
  "SubjectAlternativeNameSummaries": [
    "unifiedcommunications.me",
    "*.unifiedcommunications.me"
  ],
  "HasAdditionalSubjectAlternativeNames": false,
  "Status": "ISSUED",
  "Type": "IMPORTED",
  "KeyAlgorithm": "RSA-2048",
  "KeyUsages": [
    "DIGITAL_SIGNATURE",
    "KEY_ENCIPHERMENT"
  ],
  "ExtendedKeyUsages": [
    "TLS_WEB_SERVER_AUTHENTICATION",
    "TLS_WEB_CLIENT_AUTHENTICATION"
  ],
  "InUse": true,
  "RenewalEligibility": "INELIGIBLE",
  "NotBefore": "2023-06-06T09:11:29+03:00",
  "NotAfter": "2024-07-07T09:11:28+03:00",
  "CreatedAt": "2019-06-21T11:40:57+03:00",
  "ImportedAt": "2023-06-12T12:01:09.526000+03:00"
}

Then if certificate is already exists, what can be checked by command above, you able to re-import certificate with new one by following command:

Bash

aws acm import-certificate --certificate fileb://server.pem --private-key fileb://server-key.pem  --certificate-chain fileb://intermediate.pem --region {region} --certificate-arn {certificate_arn}

for our example, result would be:

aws acm import-certificate --certificate fileb://server.pem --private-key fileb://server-key.pem  --certificate-chain fileb://intermediate.pem --region eu-west-1 --certificate-arn arn:aws:acm:eu-west-1:123456789123:certificate/3dc54c37-5ce5-4f46-aeb9-14228a14fbc5

In case of it will be first upload certificate to ACM for particular domain, because you checked and commands above return to you empty response for target domain what you checked, you can easily import certificate initially for domain, by using following command:

aws acm import-certificate --certificate fileb://server.pem --private-key fileb://server-key.pem  --certificate-chain fileb://intermediate.pem --region eu-west-1

INFO

Please pay attention, that ACM is regional-depended AWS service with compare to IAM, which means, that you should upload/re-import certificates with pointing out correct <region>. So if you missed or put wrong region in the aws-cli command quite proable when you will try to use certificate ARN what you’ll provide after the uploading in their services - it quite probable won’t be work for their services, because certificate has been uploaded to wrong region.


IMPORTANT

You cannot install certificates with 4096-bit RSA keys or EC keys on your Elastic Load Balancer (Classic) through integration with ACM. You must upload certificates with 4096-bit RSA keys or EC keys to IAM in order to use them with your load balancer.

More details: SSL/TLS certificates for Classic Load Balancers

If you need to verify or determine corrent chain of your certificate, you can use WhatsMyChainCert resource, which quite simple and useful for these purposes


  1. How to install openSSL on Linux you can find here ↩︎

  2. Pay attention, that hashes is matched. If you’ll get different hashes it will be means, that probably private key doesn’t match with root certificate, so you cannot upload this files to AWS in that case. You should ask reporter to verify matching between certificate and private key ↩︎