A number of our clients want vanity domains for their experiences, which adds a laywer (or two) of operations overhead beyond just having a line item in the invoice. In the spirit of ‘infrastructure as code’-all-the-things, this is now my process for registering new domains for our clients

  1. Register the domain through Route 53
  2. Delete the hosted zone that is automatically created. (It would be nice if there was an option when getting the domain to not automatically create the hosted zone.)
  3. Login to Google Apps and add the domain as an alias. When prompted to verify, choose Ghandi as the provider and get the TXT record that is needed
  4. Create a CloudFormation stack with this template. Some interesting bits;
    • Tags in the AWS Tag Editor are case sensitive so ‘client’ and ‘Client’ are not equivilent
    • I think all my stacks will include the ‘CreationDateParameter’ parameter from now on which gets added as a tag to the Resource[s] that can accept them. This is part of the ‘timebombing’ of resources to make things more resilient. In theory I can also use AWS Config to find Resources that are not tagged and therefore presumably under CloudFormation control.
    • Same thing for the ‘client’ tag. Though still nto keen on that name or billing_client or such.
     <pre lang="json">{
       "AWSTemplateFormatVersion": "2010-09-09",
       "Parameters": {
         "ClientNameParameter": {
           "Type": "String",
           "Description": "Which client this domain is for"
         },
         "DomainNameParameter": {
           "Type": "String",
           "Description": "The domain to add a HostedZone for"
         },
         "GoogleSiteVerificationParameter": {
           "Type": "String",
           "Description": "The Google Site Verification TXT value"
         },
         "CreationDateParameter" : {
           "Description" : "Date",
           "Type" : "String",
           "Default" : "2017-08-27 00:00:00",
           "AllowedPattern" : "^\\d{4}(-\\d{2}){2} (\\d{2}:){2}\\d{2}$",
           "ConstraintDescription" : "Date and time of creation"
         }
       },
       "Resources": {
         "clienthostedzone": {
           "Type": "AWS::Route53::HostedZone",
           "Properties": {
             "Name": {"Fn::Join": [".", [{"Ref": "DomainNameParameter"}]]},
             "HostedZoneTags": [
               {
                 "Key": "client",
                 "Value": {"Ref": "ClientNameParameter"}
               },
               {
                 "Key": "CloudFormation",
                 "Value": { "Ref" : "CreationDateParameter" }
               }
             ]
           }
         },
         "dnsclienthostedzone": {
           "Type": "AWS::Route53::RecordSetGroup",
           "Properties": {
             "HostedZoneId": {
               "Ref": "clienthostedzone"
             },
             "RecordSets": [
               {
                 "Name": {"Fn::Join": [".", [{"Ref": "DomainNameParameter"}]]},
                 "Type": "TXT",
                 "TTL": "900",
                 "ResourceRecords": [
                   {"Fn::Sub": "\"google-site-verification=${GoogleSiteVerificationParameter}\""}
                 ]
               },
               {
                 "Name": {"Fn::Join": [".", [{"Ref": "DomainNameParameter"}]]},
                 "Type": "MX",
                 "TTL": "900",
                 "ResourceRecords": [
                   "1 ASPMX.L.GOOGLE.COM",
                   "5 ALT1.ASPMX.L.GOOGLE.COM",
                   "5 ALT2.ASPMX.L.GOOGLE.COM",
                   "10 ALT3.ASPMX.L.GOOGLE.COM",
                   "10 ALT4.ASPMX.L.GOOGLE.COM"
                 ]
               }
             ]
           }
         },
       }
     }
    
  5. Update the domain’s nameservers for the ones in our newly created Hosted Zone. I suspect this could be done via a Lambda backed custom resource, but that’s a couple steps too complicated for me right now. If I have to do this more than once every couple weeks it’ll be work the learning time.
  6. Validate the domain with Google.
  7. Manually create a certificate for ${DomainNameParameter} and *.${DomainNameParameter}. (For reals, this should be an automatic thing for domains registered in Route 53 and hosted within Route 53.)

And then I need to create an ALB for the domain and point it at the right service. But thats getting rather yak shave-y. The ALB needs to be added to the ASG for the service but those are not under CloudFormation control so I need to get them under control.