avatarTeri Radichel

Summarize

Update NS Records for a Domain Name on AWS

ACM.243 Matching name servers of a domain to an AWS Route 53 hosted zone

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

⚙️ Check out my series on Automating Cybersecurity Metrics | Code.

🔒 Related Stories: Application Security | AWS Security | DNS

💻 Free Content on Jobs in Cybersecurity | ✉️ Sign up for the Email List

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In the last post I set up an AWS CLI profile that is allowed to update NS records on a domain name registered on AWS through Route 53 Domains.

Now that we have a role profile in our AWS CLI configuration, we can use that to update the NS records on a domain so it will work with an AWS static website hosted in S3 and an AWS TLS certificate set up in AWS Certificate Manager.

Recall that we created a Route 53 hosted zone in our static website AWS account here. When we did that the hosted zone got assigned a set of names servers.

What we need to do now is query those name servers and update the NS records for the primary domain to match. There is a lot of additional content I could add in regards to NS records but I’m keeping this simple for now.

Our static website deployment script so far

Now coming back to this after a while I can pick up where I left off on my deployment script. This is a POC script not in any final form. I’ve got some things hard coded for my environment at the moment as you can see. I’ll fix that eventually. But at the end the last step we did was to get the hosted zone ID for the hosted zone we created.

Now I have this in some old notes for a related script as to what we need to do next:

domain=[domain for which we are creating the hosted zone]
[deploy hosted zone]
hostedzone=[get hosted zone id]
aws route53 list-resource-record-set --hosted-zone-id $hostedzone | grep -vhostmaster” | grep Value | cut -d “:” -f2 | seds/\”//g’ | seds/ //g’ > sets.txt
echo "DO THIS BEFORE PROCEEDING."
echo "Copy the NS records below and create an NS record on the domain in the account where it is located for "$domain

In other words, I was printing out the hosted zone records with the above command and manually updating the records on my domain because I didn’t want to grant permissions to that account to the same user performing other automation. But we’ve somewhat solved that now with a separate role profile that has limited permissions. The role can only update NS records.

The other thing is, if your domain name is hosted externally, you would need to capture those name servers and update them in some other external system so you might follow the above process, unless you can automate updating the other system with the name servers.

For example, if you registered your domain name at Google Domains (soon to be part of Square Space) and you created a hosted zone on AWS, you would need to take those NS records and update your domain at Google Domains with those name server records.

But, we’re going to automate the process of updating the NS records on AWS so this presumes you’ve registered your domain with Route 53 domains.

Run the query to view the name servers associated with the hosted zone

The first thing I’m going to do is run this command and take a look at the output format. I can add this command to the end of my script but first let’s just take a look at the output of this command.

aws route53 list-resource-record-sets --hosted-zone-id $hostedzone --profile $profile | grep -v "hostmaster" | grep Value | cut -d ":" -f2 | sed 's/\"//g' | sed 's/ //g' 

If you’re wondering what the sed commands are doing I have some information about sed here. It is a pretty handy tool for replacing characters or substrings in strings of files.

To run it I need to get the hosted zone ID which I can obtain with the last line of my script above.

Along the way I had to update my script for refreshing credentials associated with my CLI profile. Recall that I am using a cross account role that gets temporary credentials and associates them with an AWS CLI Profile. By now whatever credentials I was using the last time I ran this script have definitely expired. So I’m using my refresh script to update the credentials associated with the profile. Somewhere along the way, I simplified the create_cross_account_role_profile function to only require three parameters so I had to adjust this script accordingly.

Once I execute that script my credentials for the cross-account web admin role get refreshed and I can use that profile now to run my test script.

Because bash mangles things so badly on the command line on AWS EC2 as I wrote about here (the same things happen in CloudShell and similar problems on Ubuntu on AWS EC2):

I went ahead and created a short script to test getting the name servers:

That yields output in this format:

ns-x.awsdns-##.org.
ns-y.awsdns-##.co.uk.
ns-z.awsdns-##.net.
ns-a.awsdns-##.com.

Format of NS records for AWS CLI command

Since my domains already exist, registered manually, I can’t use CloudFormation for this update. I’ll need to use the AWS CLI. What format do I need to pass in the NS records? Let’s take a look:

What does the nameservers parameter expect?

GlueIps is a really strange parameter name if you ask me. It threw me for a loop momentarily. If it was this I would have instantly understood it:

Name=[domainame],NS=[NS1, NS2, NS3, NS4]

But it’s not. It’s GlueIps. And I still go it wrong because I was reading too fast as you will see in a minute. Whatever.

So we have to convert our NS records to a comma separated string.

To solve that problem we can use this nifty paste command:

paste -d -f file

But instead of a file we’ll pipe it onto the end of our command:

aws route53  list-resource-record-sets --hosted-zone-id $hostedzoneid --profile $rolename | grep "ns-" | grep -v "hostmaster" | cut -d ":" -f2 | sed 's/ //g' | sed 's/"//g' | paste -d, -s

That gives our NS records as a comma separated string.

Add the commands to update the NS records to the deploy script

I add that last line above to my deploy script to get the list of NS records.

Now the thing is, I need to make sure I update the subdomain records, not the primary domain. In the past I went to the console and updated the name servers of the parent domain to the new name servers to get the parent domain to get served up from a different account.

If I do that now then I would end up breaking the primary production website. I only want to add NS records for the subdomain. So when you look in the AWS Console at the domain NS records there’s no option to add NS records for a subdomain to the domain registered with Route 53 domains. You can only update the name servers for the primary domain.

But it seems like if we pass the subdomain into the command above it should only update the subdomain, no? Well, let’s see what happens.

Luckily I’ve already copied and pasted and tested the code for moving the account from the DenyAll OU to the Domains OU. I just need to add the call there to update the NS records (which will ultimately go in my DNS functions along with the other DNS related commands.)

Here’s the command:

Except I don’t have the NS records in the proper format yet. Here’s an example on the AWS CLI documentation page which is helpful (thank you, thank you as this was not clear from the documentation above at first):

Here’s where I notice something else. The name servers above do not have commands between them but are in a different format and the GlueIps is not present. What is GlueIps? Maybe you read more carefully above than I did :)

Glue IP address of a name server entry. Glue IP addresses are required only when the name of the name server is a subdomain of the domain. For example, if your domain is example.com and the name server for the domain is ns.example.com, you need to specify the IP address for ns.example.com.

Alright so we don’t need those GlueIPs after all but we have to reformat the output of our NS records to remove the comma and add “Name=” in front of each name server with a space between. Back to our test script.

aws route53  list-resource-record-sets --hosted-zone-id $hostedzoneid --profile $rolename | grep "ns-" | grep -v "hostmaster" | cut -d ":" -f2 | sed 's/ //g' | sed 's/"//g' | sed 's/^/Name=/g' | paste -d " " -s

That seems to give me the neccessary output. Revise the deploy script to use that command.

The next problem I run into is that I didn’t add sts:assumerole to my SCP for the domains OU. I had tested my ns_domains profile in a sandbox environment. I forgot that I had simplified the SCP and in so doing made a mistake. It looks like this at the moment, enforcing MFA on every action:

However, after fixing that I get the following error. I presume this is because the function that updates the domain name isn’t expecting a subdomain and the main part of the domain (rainierrhododendrons) gets pushed in as the TLD (instead of .com).

An error occurred (UnsupportedTLD) when calling the UpdateDomainNameservers operation: rainierrhododendrons.com tld is not supported

So great (sarcasm). I expected that subdomains need to be handled differently and the documentation tells you how to handle a subdomain hosted at another provider but not a subdomain hosted on AWS.

And then it hits me. We need to update the NS records in the hosted zone of the parent domain. In other words, wherever I’m hosting the primary hosted zone for rainierrhododendrons.com, I need to add a record for the subdomain — dev.rainierrhododendrons.com.

Yes, I knew that. It was in the code I’m revamping for this framework which I referenced above. 😆 I just forgot. Duh.

Well that’s just dandy because we have to have that hosted zone in the account where the static S3 production website is hosted for that to work. So I have to modify the hosted zone for the site I’m trying to test moving before I move it so I don’t break anything. Super.

If you look at that hosted zone (this is a different domain, same concept) I can only add a new NS record if I add a subdomain. Then I can update the subdomain NS records to match the hosted zone in the other account. Otherwise you can’t add a new set of NS records as there are already some associated with the domain. Updating the production domain NS records will cause things to fail if you don’t know what you are doing.

And now it is all coming back to me — I use to host a few different subdomains for my class portal. Right.

The other thing is, if I need to update the primary NS records for the top level domain if it’s hosted in an alternate account than the one where the domain is registered, then I have to use two separate commands to update NS records depending on what type of domain I’m using — the top level domain servers or the subdomain name servers.

The bottom line is that I was using a subdomain so I wouldn’t impact the primary domain and that was pretty much pointless due to the way this is designed. You have to edit a production web site hosted zone to get a subdomain to work. And the hosted zone has to be in the account where the S3 bucket is if it’s used for a static website. I’m sure there’s some sort of underlying reason due to the zone records but I’d rather add the NS records to the domain in the domains account to avoid messing up a production domain.

So, I’m back to my suggestion of using a completely separate domain, not a subdomain, for dev, QA, and Staging sites to avoid having to update production hosted zones if you need to add a subdomain or make changes.

Well this was all very interesting. I need to set up the ns_domains user to access the production web hosted zone records in order to make this change.

I also need to use a different command to update the NS records for a subdomain in the primary hosted zone. I might as well finish what I started even though I just recommended a different approach.

I’ll save those changes for the next post.

Follow for updates.

Teri Radichel | © 2nd Sight Lab 2023

About Teri Radichel:
~~~~~~~~~~~~~~~~~~~~
⭐️ Author: Cybersecurity Books
⭐️ Presentations: Presentations by Teri Radichel
⭐️ Recognition: SANS Award, AWS Security Hero, IANS Faculty
⭐️ Certifications: SANS ~ GSE 240
⭐️ Education: BA Business, Master of Software Engineering, Master of Infosec
⭐️ Company: Penetration Tests, Assessments, Phone Consulting ~ 2nd Sight Lab
Need Help With Cybersecurity, Cloud, or Application Security?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
🔒 Request a penetration test or security assessment
🔒 Schedule a consulting call
🔒 Cybersecurity Speaker for Presentation
Follow for more stories like this:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
❤️ Sign Up my Medium Email List
❤️ Twitter: @teriradichel
❤️ LinkedIn: https://www.linkedin.com/in/teriradichel
❤️ Mastodon: @teriradichel@infosec.exchange
❤️ Facebook: 2nd Sight Lab
❤️ YouTube: @2ndsightlab
AWS
Route 53
Hosted Zone
Name Servers
Domain Name
Recommended from ReadMedium