Skip to content

Instantly share code, notes, and snippets.

@badboybeyer
Forked from ELLIOTTCABLE/.gitignore
Last active November 5, 2022 11:36
Show Gist options
  • Save badboybeyer/d2b8bf5bd5ef18ffd4b76e8b9986f925 to your computer and use it in GitHub Desktop.
Save badboybeyer/d2b8bf5bd5ef18ffd4b76e8b9986f925 to your computer and use it in GitHub Desktop.
BASH Script to keep Route53 updated with your current external IP address

update-route53.sh

Purpose

To provide dyndns updates to a route53 record programatically

Setup

Install the dependencies:

  • sipcalc
  • dig
  • jq
  • awscli

On debian:

sudo apt-get install sipcalc jq awscli dnsutils

Configure aws:

aws configure

or:

aws configure --profile mydnsprofile

configure a cron job or systemd timer to execute update-route53.sh on a regular interval with the params you desire.

[[source]]
verify_ssl = true
name = "pypi"
url = "https://pypi.org/simple"
[packages]
awscli = "*"
[dev-packages]
[requires]
python_version = "3.5"
{
"_meta": {
"hash": {
"sha256": "a201ff737d34f8ab732fa371c6207d5dfeacf3c06bfe473a48b72457e58c4d93"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.5"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"awscli": {
"hashes": [
"sha256:926a9b7f000fb3087edd04ed835efed7a95c2bf63c75f05df4b9dfe918cd41ee",
"sha256:d55f4678f6e1c65a11583ac31d66794ae2574a10cd262d82c851fbed1f42b72b"
],
"index": "pypi",
"version": "==1.16.25"
},
"botocore": {
"hashes": [
"sha256:c46db774494c741e63d79bde7af4acfcbf0815671db7af6857b580270fe116d2",
"sha256:f22b99ad4717800faaf3e1710d8fe6ca113db64ae04ee2518e3305a1bf14da2a"
],
"version": "==1.12.15"
},
"colorama": {
"hashes": [
"sha256:463f8483208e921368c9f306094eb6f725c6ca42b0f97e313cb5d5512459feda",
"sha256:48eb22f4f8461b1df5734a074b57042430fb06e1d61bd1e11b078c0fe6d7a1f1"
],
"version": "==0.3.9"
},
"docutils": {
"hashes": [
"sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
"sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274",
"sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6"
],
"version": "==0.14"
},
"jmespath": {
"hashes": [
"sha256:6a81d4c9aa62caf061cb517b4d9ad1dd300374cd4706997aff9cd6aedd61fc64",
"sha256:f11b4461f425740a1d908e9a3f7365c3d2e569f6ca68a2ff8bc5bcd9676edd63"
],
"version": "==0.9.3"
},
"pyasn1": {
"hashes": [
"sha256:b9d3abc5031e61927c82d4d96c1cec1e55676c1a991623cfed28faea73cdd7ca",
"sha256:f58f2a3d12fd754aa123e9fa74fb7345333000a035f3921dbdaa08597aa53137"
],
"version": "==0.4.4"
},
"python-dateutil": {
"hashes": [
"sha256:1adb80e7a782c12e52ef9a8182bebeb73f1d7e24e374397af06fb4956c8dc5c0",
"sha256:e27001de32f627c22380a688bcc43ce83504a7bc5da472209b4c70f02829f0b8"
],
"markers": "python_version >= '2.7'",
"version": "==2.7.3"
},
"pyyaml": {
"hashes": [
"sha256:3d7da3009c0f3e783b2c873687652d83b1bbfd5c88e9813fb7e5b03c0dd3108b",
"sha256:3ef3092145e9b70e3ddd2c7ad59bdd0252a94dfe3949721633e41344de00a6bf",
"sha256:40c71b8e076d0550b2e6380bada1f1cd1017b882f7e16f09a65be98e017f211a",
"sha256:558dd60b890ba8fd982e05941927a3911dc409a63dcb8b634feaa0cda69330d3",
"sha256:a7c28b45d9f99102fa092bb213aa12e0aaf9a6a1f5e395d36166639c1f96c3a1",
"sha256:aa7dd4a6a427aed7df6fb7f08a580d68d9b118d90310374716ae90b710280af1",
"sha256:bc558586e6045763782014934bfaf39d48b8ae85a2713117d16c39864085c613",
"sha256:d46d7982b62e0729ad0175a9bc7e10a566fc07b224d2c79fafb5e032727eaa04",
"sha256:d5eef459e30b09f5a098b9cea68bebfeb268697f78d647bd255a085371ac7f3f",
"sha256:e01d3203230e1786cd91ccfdc8f8454c8069c91bee3962ad93b87a4b2860f537",
"sha256:e170a9e6fcfd19021dd29845af83bb79236068bf5fd4df3327c1be18182b2531"
],
"version": "==3.13"
},
"rsa": {
"hashes": [
"sha256:25df4e10c263fb88b5ace923dd84bf9aa7f5019687b5e55382ffcdb8bede9db5",
"sha256:43f682fea81c452c98d09fc316aae12de6d30c4b5c84226642cf8f8fd1c93abd"
],
"version": "==3.4.2"
},
"s3transfer": {
"hashes": [
"sha256:90dc18e028989c609146e241ea153250be451e05ecc0c2832565231dacdf59c1",
"sha256:c7a9ec356982d5e9ab2d4b46391a7d6a950e2b04c472419f5fdec70cc0ada72f"
],
"version": "==0.1.13"
},
"six": {
"hashes": [
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
],
"version": "==1.11.0"
},
"urllib3": {
"hashes": [
"sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf",
"sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5"
],
"markers": "python_version != '3.3.*' and python_version >= '2.6' and python_version != '3.2.*' and python_version != '3.0.*' and python_version != '3.1.*' and python_version < '4'",
"version": "==1.23"
}
},
"develop": {}
}
#!/bin/bash
set -e
usage=$(cat <<"EOF"
Usage:
./update-route53.sh [--help] --record=<record_set_name>
[--ttl=<ttl_seconds>] [--type=<record_type>]
--zone=<zone_id>
Update an AWS Route 53 record with your external IP address.
OPTIONS
--help
Show this output
--record=<record_set_name>
The name of the record set to update (e.g., hello.example.com).
--ttl=<ttl_seconds>
The TTL (in seconds) to set on the DNS record. Defaults to 300.
--type=<record_type>
The type of the record set to be updated (e.g., A, AAAA). Defaults to A.
--zone=<zone_id>
The zone id of the domain to be updated (e.g., ABCD12EFGH3IJ).
--profile=<profile_name>
The name of the `awscli` profile to use, if any (e.g., testing).
(See: https://github.com/aws/aws-cli#getting-started)
e.x.: aws configure --profile <profile_name>
--local=<if>
Use the first local ip address from the if interface.
For IPv6, use the SLAAC address.
EOF
)
SHOW_HELP=0
ZONEID=""
RECORDSET=""
PROFILE=""
PROFILEFLAG=""
LOCAL=""
TYPE="A"
TTL=300
COMMENT="Auto updating @ `date`"
while [ $# -gt 0 ]; do
case "$1" in
--help)
SHOW_HELP=1
;;
--record=*)
RECORDSET="${1#*=}"
;;
--ttl=*)
TTL="${1#*=}"
;;
--type=*)
TYPE="${1#*=}"
;;
--zone=*)
ZONEID="${1#*=}"
;;
--profile=*)
PROFILE="${1#*=}"
;;
--local=*)
LOCAL="${1#*=}"
;;
*)
SHOW_HELP=1
esac
shift
done
if [ -z "$RECORDSET" -o -z "$ZONEID" ]; then
SHOW_HELP=1
fi
if [ $SHOW_HELP -eq 1 ]; then
echo "$usage"
exit 0
fi
if [ -n "$PROFILE" ]; then
PROFILEFLAG="--profile $PROFILE"
fi
if [ "$TYPE" == "A" ]; then
if [ -n "$LOCAL" ]; then
# this is probably not portable
IP=$(ifconfig eth1 | awk '$1=="inet"{print $2}' | head -n1)
else
# Get the external IP address from OpenDNS
# (more reliable than other providers)
IP=$(dig +short myip.opendns.com @resolver1.opendns.com)
fi
else
# AAAA - ipv6
if [ -n "$LOCAL" ]; then
# this is probably not portable
IP=$(ifconfig eth1 | \
awk '$1=="inet6"{print $2}' | \
awk -F: '$1~/[fF][eE]80/{print $0}' | \
head -n1)
else
# Get the IPv6 address from OpenDNS
IP=$(dig +short -6 myip.opendns.com aaaa @resolver1.ipv6-sandbox.opendns.com)
fi
fi
# Get the current ip address on AWS
# Requires jq to parse JSON output
AWSIP="$(
pipenv run aws $PROFILEFLAG route53 list-resource-record-sets \
--hosted-zone-id "$ZONEID" --start-record-name "$RECORDSET" \
--start-record-type "$TYPE" --max-items 1 \
--output json | jq -r \ '.ResourceRecordSets[].ResourceRecords[].Value'
)"
# Get current dir
# (from http://stackoverflow.com/a/246128/920350)
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
LOGFILE="$DIR/update-route53.log"
# Requires sipcalc to check ip is valid
if sipcalc "$IP" | grep -q ERR; then
echo "Invalid IP address: $IP" >> "$LOGFILE"
exit 1
fi
#compare local IP to dns of recordset
if [ "$IP" == "$AWSIP" ]; then
# code if found
# echo "IP is still $IP. Exiting" >> "$LOGFILE"
exit 0
else
echo "IP has changed to $IP" >> "$LOGFILE"
# Fill a temp file with valid JSON
TMPFILE=$(mktemp /tmp/temporary-file.XXXXXXXX)
trap "rm $TMPFILE;" exit
cat > ${TMPFILE} << EOF
{
"Comment":"$COMMENT",
"Changes":[
{
"Action":"UPSERT",
"ResourceRecordSet":{
"ResourceRecords":[
{
"Value":"$IP"
}
],
"Name":"$RECORDSET",
"Type":"$TYPE",
"TTL":$TTL
}
}
]
}
EOF
# Update the Hosted Zone record
pipenv run aws $PROFILEFLAG route53 change-resource-record-sets \
--hosted-zone-id $ZONEID \
--change-batch file://"$TMPFILE" \
--query '[ChangeInfo.Comment, ChangeInfo.Id, ChangeInfo.Status, ChangeInfo.SubmittedAt]' \
--output text >> "$LOGFILE"
echo "" >> "$LOGFILE"
fi
@badboybeyer
Copy link
Author

Added support for ipv6 and using ifconfig to query the address from a local if. Added a dependency for sipcalc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment