Set up ACM SSL Certs and Domain Validation with Route53

In this post I will go through the steps that I took get my site setup behind Cloudfront. That was wishfull thinking will happen in part 4 now

I am starting with a domain that has nothing else on it, no subdomains, mx records nothing. I will be updating the domains Nameservers to Route53.

Requirements

Steps I’m going to cover

  1. Add my domain to route53
  2. Update NS servers for my domain at my registrar
  3. Get ACM SSL wildcard Cert for my domain
  4. Update DNS on my domain to verify domain for SSL cert
  5. Create Cloudfront Distribution Now happening in Part4
  6. Update my Cloudfront distribution with a custom CNAME Now happening in Part4
  7. Create the CNAME Now happening in Part4
  8. Hope everything works (it probably won’t so if there are more steps I forgot some stuff)

Cloudfront is like number 5 on that list maybe I should separate part 3 of what was supped to be a simple post into parts 3 and 4. Well we’ll see how it goes.

Let’s roll

Add my domain to route53

Let’s see what we get with aws route53 help I know they call domains “Hosted Zones” so let’s checkout aws route53 create-hosted-zone help Looks like I’m going to end up with aws route53 create-hosted-zone --name gnoinski.ca --caller-reference randomrequiredstring That returned me the following. I am going to take special note of the NameServers in the DelegationSet, this is what we need to update at our registrar.

{
    "Location": "https://route53.amazonaws.com/2013-04-01/hostedzone/Z1UZQNFWWZLI94",
    "HostedZone": {
        "Id": "/hostedzone/Z1UZQNFWWZLI94",
        "Name": "gnoinski.ca.",
        "CallerReference": "randomrequiredstring",
        "Config": {
            "PrivateZone": false
        },
        "ResourceRecordSetCount": 2
    },
    "ChangeInfo": {
        "Id": "/change/C2JUG1GP5MTIYE",
        "Status": "PENDING",
        "SubmittedAt": "2018-04-04T02:38:24.619Z"
    },
    "DelegationSet": {
        "NameServers": [
            "ns-1937.awsdns-50.co.uk",
            "ns-274.awsdns-34.com",
            "ns-555.awsdns-05.net",
            "ns-1153.awsdns-16.org"
        ]
    }
}

Update NS servers for my domain at my registrar

I use namecheap so I went to http://www.google.com and searched for “namecheap update nameservers” I found namecheaps page in the results and didn’t actually follow the instructions as I’ve updated NS records hundreds of times. I hope the page I just linked is correct as it is Namecheaps page, but if it’s not updated or correct you can just follow the search procedure above to hopefully find some correct instructions.

Get ACM SSL wildcard Cert for my domain

I eventually want my site to be https so I need a SSL certificate. Lukily AWS provides Free SSL certs. Free as in puppies, you can only use AWS certs with AWS services, so you’re paying one way or another. I have heard good things about let’s encrypt certs but never used them.

I gave a keyword in the title of this section, my first command is going to be aws acm help which then gives me aws acm request-certificate help And then finally I’ll run aws acm request-certificate --domain-name gnoinski.ca --subject-alternative-names "*.gnoinski.ca" "gnoinski.com" "*.gnoinski.com" --validation-method DNS

came back with

You must specify a region. You can also configure your region by running "aws configure".

This goes back to Part2 where I said I usually either set an environment variable, or set it at run time.

Alright new command AWS_DEFAULT_REGION=us-east-1 aws acm request-certificate --domain-name gnoinski.ca --subject-alternative-names "*.gnoinski.ca" "gnoinski.com" "*.gnoinski.com" --validation-method DNS

The new command gave me:

{
    "CertificateArn": "arn:aws:acm:us-east-1:917788456904:certificate/76a538cf-5eef-43e0-aed9-9d0dd2403990"
}

Hrmmm well there’s no DNS records for me to setup there. Back to aws acm help and then we’ll do aws acm describe-certificate and get’s us to AWS_DEFAULT_REGION=us-east-1 aws acm describe-certificate --certificate-arn arn:aws:acm:us-east-1:917788456904:certificate/76a538cf-5eef-43e0-aed9-9d0dd240399 At this point I’m tired of setting the AWS_DEFAULT_REGION on every command. I’m working with cloudfront/us-east-1 right now so I’ll just do export AWS_DEFAULT_REGION=us-east-1 to set it for the remainder of this shell session.

The above command returned

{
    "Certificate": {
        "CertificateArn": "arn:aws:acm:us-east-1:917788456904:certificate/76a538cf-5eef-43e0-aed9-9d0dd2403990",
        "DomainName": "gnoinski.ca",
        "SubjectAlternativeNames": [
            "gnoinski.ca",
            "*.gnoinski.ca",
            "gnoinski.com",
            "*.gnoinski.com"
        ],
        "DomainValidationOptions": [
            {
                "DomainName": "gnoinski.ca",
                "ValidationStatus": "PENDING_VALIDATION",
                "ResourceRecord": {
                    "Name": "_5d5f31cde5783a68480ab2e202803fb7.gnoinski.ca.",
                    "Type": "CNAME",
                    "Value": "_dd767c2d804d508c3cb53e04c5365bee.acm-validations.aws."
                },
                "ValidationMethod": "DNS"
            },
            {
                "DomainName": "*.gnoinski.ca",
                "ValidationStatus": "PENDING_VALIDATION",
                "ResourceRecord": {
                    "Name": "_5d5f31cde5783a68480ab2e202803fb7.gnoinski.ca.",
                    "Type": "CNAME",
                    "Value": "_dd767c2d804d508c3cb53e04c5365bee.acm-validations.aws."
                },
                "ValidationMethod": "DNS"
            },
            {
                "DomainName": "gnoinski.com",
                "ValidationStatus": "PENDING_VALIDATION",
                "ResourceRecord": {
                    "Name": "_488b81035f413f0e3abf32db7ffbbea6.gnoinski.com.",
                    "Type": "CNAME",
                    "Value": "_6f7e220fc7496402a267d55ef8e382da.acm-validations.aws."
                },
                "ValidationMethod": "DNS"
            },
            {
                "DomainName": "*.gnoinski.com",
                "ValidationStatus": "PENDING_VALIDATION",
                "ResourceRecord": {
                    "Name": "_488b81035f413f0e3abf32db7ffbbea6.gnoinski.com.",
                    "Type": "CNAME",
                    "Value": "_6f7e220fc7496402a267d55ef8e382da.acm-validations.aws."
                },
                "ValidationMethod": "DNS"
            }
        ],
        "Subject": "CN=gnoinski.ca",
        "CreatedAt": 1522813108.0,
        "Status": "PENDING_VALIDATION",
        "KeyAlgorithm": "RSA-2048",
        "SignatureAlgorithm": "SHA256WITHRSA",
        "InUseBy": [],
        "Type": "AMAZON_ISSUED",
        "KeyUsages": [],
        "ExtendedKeyUsages": []
    }
}

Update DNS on my domain to verify domain for SSL cert

From the above we can see that we really only need to add 2 dns records, 1 for gnoinski.ca and 1 for gnoinski.com. Back to our trusty aws route53 help umm aws route53 change-resource-record-sets help? Yeah that looks right. “The request body must include a document with a ChangeResourceRecordSetsRequest element.” Ok, what is that? “Use ChangeResourceRecordsSetsRequest to perform the following actions: CREATE DELETE UPSERT” These are new records so I could use CREATE, but I’ll use UPSERT instead just on the off chance it was somehow added without me knowing. Alright Continuing on I see that we need to create a file with some JSON to do these updates, and we also need the “Hosted Zone ID”. If you look above to the response I got after creating the hosted zone you’ll see that my zone id for gnoinski.ca is “Z1UZQNFWWZLI94”. The command I’m going to run is aws route53 change-resource-record-sets --hosted-zone-id Z1UZQNFWWZLI94 --change-batch file://change-resource-record-sets.json And of course we need some json to go into that file, and it’s going to look like

{
    "Comment": "SSL validation records",
    "Changes": [
        {
            "Action": "UPSERT",
            "ResourceRecordSet": {
                "Name": "_5d5f31cde5783a68480ab2e202803fb7",
                "Type": "CNAME",
                "TTL": 300,
                "ResourceRecords": [
                {
                    "Value": "_dd767c2d804d508c3cb53e04c5365bee.acm-validations.aws."
                }
                ]
            }
        }
    ]
}
An error occurred (InvalidChangeBatch) when calling the ChangeResourceRecordSets operation: RRSet with DNS name _5d5f31cde5783a68480ab2e202803fb7. is not permitted in zone gnoinski.ca.

Well s***, I thought I had that one. Maybe it’s looking for the full domain name, not just the subdomain for the Name.

{
    "Comment": "SSL validation records",
    "Changes": [
        {
            "Action": "UPSERT",
            "ResourceRecordSet": {
                "Name": "_5d5f31cde5783a68480ab2e202803fb7.gnoinski.ca",
                "Type": "CNAME",
                "TTL": 300,
                "ResourceRecords": [
                {
                    "Value": "_dd767c2d804d508c3cb53e04c5365bee.acm-validations.aws."
                }
                ]
            }
        }
    ]
}

Success!

{
    "ChangeInfo": {
        "Id": "/change/CPOWGORDFDLMR",
        "Status": "PENDING",
        "SubmittedAt": "2018-04-05T03:13:46.410Z",
        "Comment": "SSL validation records"
    }
}

What I did after this is updated the change-resource-record-sets.json file that I am using with the records for gnoinski.com as well as the hosted zone id. I used aws route53 list-hosted-zones to get my 2 zones and IDs.

And with that I think I am going to Cloudfront in the next post.