This is really a reply to hendry's comment that it would be nice to see an example of this kind of script, apparently I need more karma or something to add a comment.
I've just had to make this work so I can set the hostname of an EC2 instance and create a DNS record so I can then run rabbitmq on ECS on top of this using the host networking mode (which means the ECS task has the same networking and hostname as the underlying EC2 instance) so I can preserve the rabbitmq hostname through reboots of the underlying infra (and set kernel parameters which aren't show below)
This is my script, it works for me (I say that, but it's not fully tested yet. I'll report back)
#!/bin/bash
# A script to be copied into the user data of the EC2 instances to UPSERT the CNAME
set -euf -o pipefail
# We first need to install some software and update everything.
yum update -y
yum install jq -y
yum install unzip -y
# install the AWS cli which requires checking against a key.
# https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-linux.html
cat > /tmp/aws-public-key << EOF
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBF2Cr7UBEADJZHcgusOJl7ENSyumXh85z0TRV0xJorM2B/JL0kHOyigQluUG
ZMLhENaG0bYatdrKP+3H91lvK050pXwnO/R7fB/FSTouki4ciIx5OuLlnJZIxSzx
PqGl0mkxImLNbGWoi6Lto0LYxqHN2iQtzlwTVmq9733zd3XfcXrZ3+LblHAgEt5G
TfNxEKJ8soPLyWmwDH6HWCnjZ/aIQRBTIQ05uVeEoYxSh6wOai7ss/KveoSNBbYz
gbdzoqI2Y8cgH2nbfgp3DSasaLZEdCSsIsK1u05CinE7k2qZ7KgKAUIcT/cR/grk
C6VwsnDU0OUCideXcQ8WeHutqvgZH1JgKDbznoIzeQHJD238GEu+eKhRHcz8/jeG
94zkcgJOz3KbZGYMiTh277Fvj9zzvZsbMBCedV1BTg3TqgvdX4bdkhf5cH+7NtWO
lrFj6UwAsGukBTAOxC0l/dnSmZhJ7Z1KmEWilro/gOrjtOxqRQutlIqG22TaqoPG
fYVN+en3Zwbt97kcgZDwqbuykNt64oZWc4XKCa3mprEGC3IbJTBFqglXmZ7l9ywG
EEUJYOlb2XrSuPWml39beWdKM8kzr1OjnlOm6+lpTRCBfo0wa9F8YZRhHPAkwKkX
XDeOGpWRj4ohOx0d2GWkyV5xyN14p2tQOCdOODmz80yUTgRpPVQUtOEhXQARAQAB
tCFBV1MgQ0xJIFRlYW0gPGF3cy1jbGlAYW1hem9uLmNvbT6JAlQEEwEIAD4WIQT7
Xbd/1cEYuAURraimMQrMRnJHXAUCXYKvtQIbAwUJB4TOAAULCQgHAgYVCgkICwIE
FgIDAQIeAQIXgAAKCRCmMQrMRnJHXJIXEAChLUIkg80uPUkGjE3jejvQSA1aWuAM
yzy6fdpdlRUz6M6nmsUhOExjVIvibEJpzK5mhuSZ4lb0vJ2ZUPgCv4zs2nBd7BGJ
MxKiWgBReGvTdqZ0SzyYH4PYCJSE732x/Fw9hfnh1dMTXNcrQXzwOmmFNNegG0Ox
au+VnpcR5Kz3smiTrIwZbRudo1ijhCYPQ7t5CMp9kjC6bObvy1hSIg2xNbMAN/Do
ikebAl36uA6Y/Uczjj3GxZW4ZWeFirMidKbtqvUz2y0UFszobjiBSqZZHCreC34B
hw9bFNpuWC/0SrXgohdsc6vK50pDGdV5kM2qo9tMQ/izsAwTh/d/GzZv8H4lV9eO
tEis+EpR497PaxKKh9tJf0N6Q1YLRHof5xePZtOIlS3gfvsH5hXA3HJ9yIxb8T0H
QYmVr3aIUes20i6meI3fuV36VFupwfrTKaL7VXnsrK2fq5cRvyJLNzXucg0WAjPF
RrAGLzY7nP1xeg1a0aeP+pdsqjqlPJom8OCWc1+6DWbg0jsC74WoesAqgBItODMB
rsal1y/q+bPzpsnWjzHV8+1/EtZmSc8ZUGSJOPkfC7hObnfkl18h+1QtKTjZme4d
H17gsBJr+opwJw/Zio2LMjQBOqlm3K1A4zFTh7wBC7He6KPQea1p2XAMgtvATtNe
YLZATHZKTJyiqA==
=vYOk
-----END PGP PUBLIC KEY BLOCK-----
EOF
gpg --import /tmp/aws-public-key
# Download the latest x86 cli zip
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "/tmp/awscliv2.zip"
# and the Signature
curl -o "/tmp/awscliv2.sig" "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip.sig"
# and verify
gpg --verify /tmp/awscliv2.sig /tmp/awscliv2.zip
# unzip install and test
cd /tmp
unzip /tmp/awscliv2.zip
./aws/install
aws --version
# The hostname should be set to the right thing, but may need a while to come up
# so set up a retry loop
Hostname='foo' # Initialise this outside the loop
MatchTest='.internal' # facile test we have a valid AWS .internal fqdn
Zone='Z0###1XAOQT59R52D' # Test
for i in {1..7}
do
Hostname=$(hostname -f)
[[ "$Hostname" == *"$MatchTest" ]] && break || sleep 3
done
echo "Hostname: $Hostname"
if ! [[ "$Hostname" == *"$MatchTest" ]]
then
echo "Hostname: $Hostname doesn't match $MatchTest" && exit 1
fi
echo "Hostname: $Hostname"
# so now we need to UPSERT the CNAME
# this next variable needs to be correctly set for each one of the launch templates.
# i.e. rabbita, rabbitb or rabbitc
cnhost='rabbitx'
comment="Updating CNAME record for the underlying EC2 instance for Test-$cnhost"
action='UPSERT'
name="$cnhost.test"
record='CNAME'
ttl=60
jsonCNAME=$( jq -n \
--arg value "$Hostname" \
--arg comment "$comment" \
--arg name "$name" \
--arg action "$action" \
--arg record "$record" \
--arg ttl "$ttl" \
'{Comment: $comment,
Changes: [
{
Action: $action,
ResourceRecordSet: {
Name: $name,
Type: $record,
TTL: $ttl|tonumber,
ResourceRecords: [
{
Value: $value
}
],
}
}
]
}')
echo "JSON: $jsonCNAME"
aws route53 change-resource-record-sets --hosted-zone-id $Zone --change-batch <<< echo "$jsonCNAME"
# So that's the CNAME set up so now we need to set the hostname to match it
hostname "$cnhost.test"
To successfully run this the role the EC2 instances start with needs access to route53 to insert records into the private ZONE 'test' this is a security issue and should be mitigated in some way.
One of the caveats I learned whilst writing this is that when this script runs not all the ENV is set as you would expect. In particular HOME is not set, and thus you need to be explicit about paths. I chose to use /tmp but I guess /root might be preferable to some.
The loop round the hostname -f and the test to see it matches what we expect may well be redundant.