diff --git a/dns_scripts/Route53-README.md b/dns_scripts/Route53-README.md new file mode 100644 index 0000000..b078a78 --- /dev/null +++ b/dns_scripts/Route53-README.md @@ -0,0 +1,37 @@ +# Using Route53 BASH scripts for LetsEncrypt domain validation. + +## Quick guide to setting up getssl for domain validation of Route53 DNS domains. + +There a few prerequisites to using getssl with Route53 DNS: + +1. You will need to set up an IAM user with the necessary permissions to modify resource records in the hosted zone. + + - route53:ListHostedZones + - route53:ChangeResourceRecordSets + +1. You will need the AWS CLI Client installed on your machine. + +1. You will need to configure the client for the IAM user that has permission to modify the resource records. + +With those in hand, the installation procedure is: + +1. Open your config file (the global file in ~/.getssl/getssl.cfg + or the per-account file in ~/.getssl/example.net/getssl.cfg) + +1. Set the following options: + + - VALIDATE_VIA_DNS="true" + - DNS_ADD_COMMAND="/usr/share/getssl/dns_scripts/dns_add_route53" + - DNS_DEL_COMMAND="/usr/share/getssl/dns_scripts/dns_del_route53" + + The AWS CLI profile to use (will use _default_ if not specified) + + - export AWS*CLI_PROFILE="\_profile name*" + +1. Set any other options that you wish (per the standard + directions.) Use the test CA to make sure that + everything is setup correctly. + +That's it. getssl example.net will now validate with DNS. + +There are additional options, which are documented in `dns_route53 -h` diff --git a/dns_scripts/dns_add_route53 b/dns_scripts/dns_add_route53 new file mode 100755 index 0000000..88e3f0b --- /dev/null +++ b/dns_scripts/dns_add_route53 @@ -0,0 +1,18 @@ +#!/bin/bash + +# Add token to Route53 dns using dns_route53 bash version + +fulldomain="$1" +token="$2" + +[ -z "$ROUTE53_SCRIPT" ] && ROUTE53_SCRIPT="/usr/share/getssl/dns_scripts/dns_route53" +[[ "$ROUTE53_SCRIPT" =~ ^~ ]] && \ + eval 'ROUTE53_SCRIPT=`readlink -nf ' $ROUTE53_SCRIPT '`' + +if [ ! -x "$ROUTE53_SCRIPT" ]; then + echo "$ROUTE53_SCRIPT: not found. Please install, softlink or set ROUTE53_SCRIPT to its full path" + echo "See ROUTE53-README.txt for complete instructions." + exit 3 +fi + +$ROUTE53_SCRIPT -q add "${fulldomain}." "${token}" diff --git a/dns_scripts/dns_del_route53 b/dns_scripts/dns_del_route53 new file mode 100755 index 0000000..79a0570 --- /dev/null +++ b/dns_scripts/dns_del_route53 @@ -0,0 +1,18 @@ +#!/bin/bash + +# Delete token from Route53 dns using dns_route53 bash version + +fulldomain="$1" +token="$2" + +[ -z "$ROUTE53_SCRIPT" ] && ROUTE53_SCRIPT="/usr/share/getssl/dns_scripts/dns_route53" +[[ "$ROUTE53_SCRIPT" =~ ^~ ]] && \ + eval 'ROUTE53_SCRIPT=`readlink -nf ' $ROUTE53_SCRIPT '`' + +if [ ! -x "$ROUTE53_SCRIPT" ]; then + echo "$ROUTE53_SCRIPT: not found. Please install, softlink or set ROUTE53_SCRIPT to its full path" + echo "See ROUTE53-README.txt for complete instructions." + exit 3 +fi + +$ROUTE53_SCRIPT -q del "${fulldomain}." "${token}" diff --git a/dns_scripts/dns_route53 b/dns_scripts/dns_route53 new file mode 100644 index 0000000..5f1aaab --- /dev/null +++ b/dns_scripts/dns_route53 @@ -0,0 +1,199 @@ +#!/usr/bin/env bash +VERSION="1.0" +PROG="$(basename "$0")" + +QUIET=n + +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 <&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 $? \ No newline at end of file