You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

200 lines
5.9 KiB

#!/usr/bin/env bash
VERSION="1.0"
PROG="$(basename "$0")"
QUIET=n
# shellcheck disable=SC2034
while getopts 'dhp:t:z:i:qv' opt; do
case $opt in
d) DEBUG="Y" ;;
p) AWS_CLI_PROFILE="$OPTARG" ;;
q) QUIET= ;;
v) echo "dns_route53 version $VERSION"; exit 0 ;;
z) ROUTE53_HOSTED_ZONE_NAME="$OPTARG" ;;
i) ROUTE53_HOSTED_ZONE_ID="$OPTARG" ;;
*)
cat <<EOF
Usage
$PROG [-dt -q] add name data [ttl]
$PROG [-dt -h -p "aws-profile-name" -q] del name data
Add or delete TXT records from Route53 Hosted Zone
You must have the AWS CLI installed and a profile configured for this script to work.
The IAM user that the profile uses requires the following action permissions in AWS:
- route53:ListHostedZones - Not necessary if zone ID is available to this script
- route53:ChangeResourceRecordSets
With getssl, this script is called from the dns_add_route53 and
dns_del_route53 wrapper scripts.
Arguments:
add - add the specified record to the domain
del - remove the specified record from the domain
name is the fully qualified record name to create the challenge for e.g. www.example.org. Note that trailing '.' is necessary. Also note that _acme-challenge. will automatically be prepended by this script
data is the record data, e.g. "myverificationtoken"
ttl is optional and will default to 120 if not specified
If it is necessary to turn on debugging externally, define
ROUTE53_DEBUG="y" (any non-null string will do).
For minimal trace output (to override -q), define ROUTE53_TRACE="y".
Options
-d Provide debugging output - all requests and responses
-h This help.
-i: The hosted zone ID
-p: The AWS CLI profile to use. Will use default if not specified
-q: Quiet - omit normal success messages
-z: The hosted zone name. Will be used to determine the zone ID if ID was not provided
All output, except for this help text, is to stderr.
Environment variables
ROUTE53_SCRIPT location of this script
ROUTE53_HOSTED_ZONE_NAME The name of the hosted zone name. If not specified, then the name will be determined from the record name provided to this script
ROUTE53_HOSTED_ZONE_ID The id of the hosted zone to be used instead of trying to automatically determine the ID
AWS_CLI_PROFILE the aws cli profile to use if not using default
BUGS
Report any issues to https://github.com/xyide/getssl/issues
EOF
exit 0
;;
esac
done
shift $((OPTIND-1))
if [ -z "$AWS_CLI_PROFILE" ]; then
echo "AWS_CLI_PROFILE not defined. Using default" >&2
AWS_CLI_PROFILE=default
fi
op="$1"
if ! [[ "$op" =~ ^(add|del)$ ]]; then
echo "Operation must be \"add\" or \"del\"" >&2
exit 3
fi
name="$2"
if [ -z "$name" ]; then
echo "'name' parameter is required, see -h" >&2
exit 3
fi
data="$3"
if [ -z "$data" ]; then
echo "'data' parameter is required, see -h" >&2
exit 3
fi
if [ "$op" = 'del' ]; then
ttl=120
elif [ -z "$5" ]; then
ttl="120"
elif ! [[ "$5" =~ ^[0-9]+$ ]]; then
echo "TTL $5 is not numeric" >&2
exit 3
elif [ "$5" -lt 120 ]; then
[ -n "$VERB" ] && \
echo "$5 is too small. Using TTL of 120 instead" >&2
ttl="120"
else
ttl="$5"
fi
# end processing parameters
[ -n "$DEBUG" ] && \
echo "$PROG: $op $name \"$data\" $ttl" >&2
# Determine what actual hosted zone to use.
HOSTED_ZONE_NAME=$ROUTE53_HOSTED_ZONE_NAME
HOSTED_ZONE_ID=$ROUTE53_HOSTED_ZONE_ID
RR_NAME="_acme-challenge.${name}"
RR_VALUE="${data}"
# Function to parse through the segments in the supplied name
# to determine the zone and its id
function determine_hosted_zone_name_and_id() {
TMP_NAME=$name
TMP_RR_NAME=
while [[ "$TMP_NAME" =~ ^([^.]+)\.([^.]+.*) ]]; do
if [ -n "${TMP_RR_NAME}" ]; then
TMP_RR_NAME="${TMP_RR_NAME}.";
fi
TMP_RR_NAME="${TMP_RR_NAME}${BASH_REMATCH[1]}"
testdomain="${BASH_REMATCH[2]}"
[ -n "$DEBUG" ] && echo "Testing hosted zone ${testdomain}"
TMP_NAME=$testdomain
if [[ ! "$TMP_NAME" =~ [^.]+\.[^.]+ ]]; then
[ -n "$DEBUG" ] && echo "No segments left"
exit 1
fi
TMP_ZONE_ID=$(aws --profile="${AWS_CLI_PROFILE}" route53 list-hosted-zones --query "HostedZones[?Name=='${testdomain}'].Id | [0]" | sed -e 's/^"//' -e 's/"$//')
if [ "${TMP_ZONE_ID}" != "null" ]; then
[ -n "$DEBUG" ] && echo "Found hosted zone ${testdomain}"
HOSTED_ZONE_NAME=${testdomain}
HOSTED_ZONE_ID=$TMP_ZONE_ID
break
fi
done
}
# If zone ID is specified, then use it to determine the hosted zone name
if [ -n "${HOSTED_ZONE_ID}" ]; then
HOSTED_ZONE_NAME=$(aws --profile="${AWS_CLI_PROFILE}" route53 list-hosted-zones --query "HostedZones[?Id=='${ZONE_ID}'].Name | [0]" | sed -e 's/^"//' -e 's/"$//')
# If zone name is specified, then use it to get the zone id
elif [ -n "${HOSTED_ZONE_NAME}" ]; then
HOSTED_ZONE_ID=$(aws --profile="${AWS_CLI_PROFILE}" route53 list-hosted-zones --query "HostedZones[?Name=='${HOSTED_ZONE_NAME}'].Id | [0]" | sed -e 's/^"//' -e 's/"$//')
else
determine_hosted_zone_name_and_id
fi
if [ -z "${HOSTED_ZONE_ID}" ]; then
echo "Hosted zone id not specified or determined" >&2
exit 3
fi
if [ "$op" = "add" ]; then
ACTION="UPSERT"
elif [ "$op" = "del" ]; then
ACTION="DELETE"
else
echo "Unsupported Operation: $op" >&2
fi
CHANGE_BATCH='
{
"Comment": "GetSSL LetsEncrypt DNS Challenge",
"Changes": [{
"Action" : "'"$ACTION"'",
"ResourceRecordSet" : {
"Name" : "'"$RR_NAME"'",
"Type" : "TXT",
"TTL" : '${ttl}',
"ResourceRecords" : [{
"Value" : "\"'$RR_VALUE'\""
}]
}
}]
}
'
[ -n "$DEBUG" ] && echo "${CHANGE_BATCH}" >&2
aws \
--profile="${AWS_CLI_PROFILE}" \
route53 \
change-resource-record-sets \
--hosted-zone-id="${HOSTED_ZONE_ID}" \
--change-batch "${CHANGE_BATCH}"
exit $?