diff --git a/.gitattributes b/.gitattributes index 217326a..7653b18 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,11 @@ +# Files not to include in .zip/.tar.gz archives +# +.git* export-ignore + # Handle line endings automatically for files detected as text # and leave all files detected as binary untouched. * text=auto # Make all text files lf formatted * text eol=lf + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8317ebf --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*~ +*# +*.swp +*.tmp +*.bak +*.tdy +*.tar.gz +*.orig +JSON.sh diff --git a/Makefile b/Makefile index 4f16126..d88e22c 100644 --- a/Makefile +++ b/Makefile @@ -19,10 +19,9 @@ ifneq ($(strip $(DESTDIR)),) mkdir -p $(DESTDIR) endif - install -Dm755 getssl $(DESTDIR)/usr/bin/getssl - - install -dm755 $(DESTDIR)/usr/share/getssl - cp -r *_scripts $(DESTDIR)/usr/share/getssl + install -Dvm755 getssl $(DESTDIR)/usr/bin/getssl + install -dvm755 $(DESTDIR)/usr/share/getssl + for dir in *_scripts; do install -dv $(DESTDIR)/usr/share/getssl/$$dir; install -pv $$dir/* $(DESTDIR)/usr/share/getssl/$$dir/; done .PHONY: install diff --git a/README.md b/README.md index cad2775..454a388 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,24 @@ -# getssl +# getssl ![Run all tests](https://github.com/srvrco/getssl/workflows/Run%20all%20tests/badge.svg) ![shellcheck](https://github.com/srvrco/getssl/workflows/shellcheck/badge.svg) Obtain SSL certificates from the letsencrypt.org ACME server. Suitable for automating the process on remote servers. -## Table of Contents - +## Table of Contents - [Features](#features) - [Installation](#installation) - [Overview](#overview) - [Getting started](#getting-started) +- [Detailed guide to getting started with more examples](#detailed-guide-to-getting-started-with-more-examples) +- [Wildcard certificates](#wildcard-certificates) - [Automating updates](#automating-updates) - [Structure](#structure) - [Server-Types](#server-types) - [Revoke a certificate](#revoke-a-certificate) - [Elliptic curve keys](#elliptic-curve-keys) +- [Preferred Chain](#preferred-chain) +- [Include Root certificate in full chain](#include-root-certificate-in-full-chain) - [Issues / problems / help](#issues--problems--help) ## Features @@ -85,25 +88,28 @@ desktop computer, or even a virtualbox) and add the checks, and certificates to a remote server ( providing you have a ssh with key, sftp or ftp access to the remote server). -```getssl -getssl ver. 2.02 +```getssl -h +getssl ver. 2.36 Obtain SSL certificates from the letsencrypt.org ACME server -Usage: getssl [-h|--help] [-d|--debug] [-c|--create] [-f|--force] [-a|--all] [-q|--quiet] [-Q|--mute] [-u|--upgrade] [-k|--keep #] [-U|--nocheck] [-r|--revoke cert key] [-w working_dir] domain +Usage: getssl [-h|--help] [-d|--debug] [-c|--create] [-f|--force] [-a|--all] [-q|--quiet] [-Q|--mute] [-u|--upgrade] [-k|--keep #] [-U|--nocheck] [-r|--revoke cert key] [-w working_dir] [--preferred-chain chain] domain Options: -a, --all Check all certificates - -d, --debug Outputs debug information + -d, --debug Output debug information -c, --create Create default config files -f, --force Force renewal of cert (overrides expiry checks) -h, --help Display this help message and exit + -i, --install Install certificates and reload service -q, --quiet Quiet mode (only outputs on error, success of new cert, or getssl was upgraded) - -Q, --mute Like -q, but mutes notification about successful upgrade + -Q, --mute Like -q, but also mute notification about successful upgrade -r, --revoke "cert" "key" [CA_server] Revoke a certificate (the cert and key are required) -u, --upgrade Upgrade getssl if a more recent version is available - can be used with or without domain(s) - -k, --keep "#" Maximum amount of old getssl versions to keep when upgrading + -k, --keep "#" Maximum number of old getssl versions to keep when upgrading -U, --nocheck Do not check if a more recent version is available + -v --version Display current version of getssl -w working_dir "Working directory" + --preferred-chain "chain" Use an alternate chain for the certificate ``` ## Getting started @@ -163,9 +169,39 @@ Change the server in your config file to get a fully valid certificate. dns. The certificate can be used (and checked with getssl) on alternate ports. +## Detailed guide to getting started with more examples + +[Guide to getting a certificate for example.com and www.example.com](https://github.com/srvrco/getssl/wiki/Guide-to-getting-a-certificate-for-example.com-and-www.example.com) + +## Wildcard certificates + +`getssl` supports creating wildcard certificates, i.e. _*.example.com_ which allows a single certificate to be used for any domain under *example.com*, e.g. *www.example.com*, *mail.example.com*. These must be validated using the dns-01 method. + +A *partial* example `getssl.cfg` file is: + +```sh +VALIDATE_VIA_DNS=true +export CPANEL_USERNAME='' +export CPANEL_URL='https://www.cpanel.host:2083' +export CPANEL_APITOKEN='1ABC2DEF3GHI4JKL5MNO6PQR7STU8VWX9YZA' +DNS_ADD_COMMAND=/home/root/getssl/dns_scripts/dns_add_cpanel +DNS_DEL_COMMAND=/home/root/getssl/dns_scripts/dns_del_cpanel +``` + +Create the wildcard certificate (need to use quotes to prevent globbing): + +```sh +getssl "*.example.domain" +``` + +You can renew the certificate using `getssl -a` to renew all configured certificates. + +You can also specify additional domains in the `SANS` line, e.g. `SANS="www.test.example.com"`. +This cannot contain any of the domains which would be covered by the wildcard certificate. + ## Automating updates -I use the following cron +I use the following **cron** job ```cron 23 5 * * * /root/scripts/getssl -u -a -q @@ -341,7 +377,7 @@ Usage: `getssl -r path/to/cert path/to/key [CA_server]` You need to specify both the certificate you want to revoke, and the account or private domain key which was used to sign / obtain the original certificate. The `CA_server` is an optional parameter and -defaults to Let's Encrypt ("") as +defaults to Let's Encrypt ("") as that is currently the only Certificate Authority using the ACME protocol. @@ -353,6 +389,34 @@ key (different of course, don't use the same key for both). prime256v1 secp521r1 (NIST P-521) is included in the code, but not currently supported by Let's Encrypt). +## Preferred Chain + +If a CA offers multiple chains then it is possible to select which chain +is used by using the `PREFERRED_CHAIN` variable in `getssl.cfg` or specifying + `--preferred-chain` in the call to `getssl` + +This uses wildcard matching so requesting "X1" returns the first certificate +returned by the CA which contains the text "X1", Note you may need to escape +any characters which special characters, e.g. +` PREFERRED_CHAIN="\(STAGING\) Doctored Durian Root CA X3"` + +* Staging options are: "(STAGING) Doctored Durian Root CA X3" and "(STAGING) Pretend Pear X1" +* Production options are: "ISRG Root X1" and "ISRG Root X2" + +## Include Root certificate in full chain + +Some servers, including those that use Java keystores, will not accept a server certificate if it cannot valid the full chain of signers. + +Specifically, Nutanix Prism (Element and Central) will not accept the `fullchain.crt` until the root CA's certificate has been appended to it manually. + +If your application requires the full chain, i.e. including the +root certificate of the CA, then this can be included in the `fullchain.crt` file by +adding the following line to `getssl.cfg` + +```sh +FULL_CHAIN_INCLUDE_ROOT="true" +``` + ## Issues / problems / help If you have any issues, please log them at diff --git a/dns_scripts/00GoDaddy-README.txt b/dns_scripts/00GoDaddy-README.txt new file mode 100644 index 0000000..9973556 --- /dev/null +++ b/dns_scripts/00GoDaddy-README.txt @@ -0,0 +1,63 @@ +Using GoDaddy DNS for LetsEncrypt domain validation. + +Quick guide to setting up getssl for domain validation of +GoDaddy DNS domains. + +There are two prerequisites to using getssl with GoDaddy DNS: + +1) Obtain an API access key from developer.godaddy.com + At first sign-up, you will be required to take a "test" key. + This is NOT what you need. Accept it, then get a "Production" + key. At this writing, there is no charge - but you must have + a GoDaddy customer account. + + You must get the API key for the account which owns the domain + that you want to get certificates for. If the domains that you + manage are owned by more than one account, get a key for each. + + The access key consists of a "Key" and a "Secret". You need + both. + +2) Obtain JSON.sh - https://github.com/dominictarr/JSON.sh + +With those in hand, the installation procedure is: + +1) Put JSON.sh in the getssl DNS scripts directory + Default: /usr/share/getssl/dns_scripts + +2) Open your config file (the global file in ~/.getssl/getssl.cfg + or the per-account file in ~/.getssl/example.net/getssl.cfg + +3) Set the following options: + VALIDATE_VIA_DNS="true" + DNS_ADD_COMMAND="/usr/share/getssl/dns_scripts/dns_add_godaddy" + DNS_DEL_COMMAND="/usr/share/getssl/dns_scripts/dns_del_godaddy" + # The API key for your account/this domain + export GODADDY_KEY="..." GODADDY_SECRET="..." + # The base domain name(s) in which the challege records are stored + # E.g. if www.example.net is in the example.net zone: + export GODADDY_BASE="example.com example.net" + + 4) 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. + +To trace record additions and removals, run getssl as +GODADDY_TRACE=Y getssl example.net + +There are additional options, which are documented in the +*godaddy" files and dns_godaddy -h. + +Copyright (C) 2017, 2018 Timothe Litt litt at acm _dot org + +This sofware may be freely used providing this notice is included with +all copies. The name of the author may not be used to endorse +any other product or derivative work. No warranty is provided +and the user assumes all responsibility for use of this software. + +Report any issues to https://github.com/tlhackque/getssl/issues. + +Enjoy. + diff --git a/dns_scripts/dns_add_cpanel b/dns_scripts/dns_add_cpanel new file mode 100644 index 0000000..24a1ca8 --- /dev/null +++ b/dns_scripts/dns_add_cpanel @@ -0,0 +1,76 @@ +#!/usr/bin/env bash + +# Need to add your email address and API key to cpanel below or set as env variables +user=${CPANEL_USERNAME:-''} +password=${CPANEL_PASSWORD:-''} +url=${CPANEL_URL:-''} # e.g. https://www.cpanel-host.test:2083 +apitoken=${CPANEL_APITOKEN:-''} + +fulldomain="${1}" +token="${2}" + +# Check initial parameters +if [[ -z "$fulldomain" ]]; then + echo "DNS script requires full domain name as first parameter" + exit 1 +fi +if [[ -z "$token" ]]; then + echo "DNS script requires challenge token as second parameter" + exit 1 +fi +if [[ -z "$user" ]]; then + echo "CPANEL_USERNAME (username) parameter not set" + exit 1 +fi +if [[ -z "$apitoken" ]] && [[ -z "$password" ]]; then + echo "Must set either CPANEL_APITOKEN or CPANEL_PASSWORD in dns script, environment variable or getssl.cfg" + exit 1 +fi +if [[ -z "$url" ]]; then + echo "CPANEL_URL (url) parameter not set" + exit 1 +fi + +# Setup +request_func="${url}/json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit" +if [[ -n $apitoken ]]; then + curl_params=( -H "Authorization: cpanel $user:$apitoken" ) +else + auth_string=$(echo -ne "$user:$password" | base64 --wrap 0) + curl_params=( -H "Authorization: Basic $auth_string" ) +fi + +# Check if domain is a CNAME +res=$(dig CNAME "$fulldomain") +domain=$(echo "$res"| awk '$4 ~ "CNAME" {print $5}' |sed 's/\.$//g') +if [[ -n "$domain" ]]; then + name=".${fulldomain%.$domain}" +else + domain=$fulldomain + name="" +fi + +# Check to see if challenge dns entry already exists (update or delete?) +request_params="&cpanel_jsonapi_func=fetchzone_records&domain=${domain}&type=TXT&name=_acme-challenge.${fulldomain}." +resp=$(curl --silent "${curl_params[@]}" "$request_func$request_params") +if [[ "$resp" = *\"error\":* ]]; then + echo -n "cpanel fetchzone records failed: " + echo "$resp" | awk -F"error" '{ print $2 }' | awk -F\" '{ print $3 }' + exit 1 +fi + +# If no existing record, create a new TXT record, otherwise edit the existing record +if [[ "$resp" == *\"data\":[]* ]]; then + request_params="&cpanel_jsonapi_func=add_zone_record&domain=$domain&type=TXT&name=_acme-challenge$name&txtdata=$token" +else + # shellcheck disable=SC2001 + line=$(echo "$resp" | sed -e 's/.*line":\([0-9]*\),.*/\1/') + request_params="&cpanel_jsonapi_func=edit_zone_record&domain=$domain&type=TXT&name=_acme-challenge$name&txtdata=${token}&line=${line}" +fi +resp=$(curl --silent "${curl_params[@]}" "$request_func$request_params") + +if [[ "$resp" = *\"status\":0* ]]; then + echo -n "cpanel edit zone record failed: " + echo "$resp" | awk -F"statusmsg" '{ print $2 }' | awk -F\" '{ print $3 }' + exit 1 +fi diff --git a/dns_scripts/dns_add_del_aliyun.sh b/dns_scripts/dns_add_del_aliyun.sh new file mode 100644 index 0000000..d6d9461 --- /dev/null +++ b/dns_scripts/dns_add_del_aliyun.sh @@ -0,0 +1,185 @@ +#!/bin/bash +#https://blog.aymar.cn +#https://protocol.aymar.cn +PROGNAME=${0##*/} +VERSION="2021年3月22日 16:07:05" +Ali_API="https://dns.aliyuncs.com/" +_timestamp=$(date -u +"%Y-%m-%dT%H%%3A%M%%3A%SZ") +__debug="0" +__delete="0" + +#Wildcard certificates +#A partial example getssl.cfg file is: +#VALIDATE_VIA_DNS=true +#DNS_ADD_COMMAND=/root/.getssl/dns_add_del_aliyun.sh +#DNS_DEL_COMMAND=/root/.getssl/dns_add_del_aliyun.sh + +# either configure KeyId & KeySecret here or export environment variables in getssl.cfg +AccessKeyId=${ALI_KeyId:-''} +AccessKeySecret=${ALI_KeySecret:-''} + +usage() { # print out the program usage + echo "Usage: $PROGNAME [-a|--add ] [-d|--delete ] [-s|--search ] [-h|--help] [-t|--type] "\ + "[-q|--quiet] [-c|--check] [-S|--status] [-l|--lock #] [-T|--ttl] [-u|--update] [-w|--weight] [-L|--Line]" +} + +help_message() { # print out the help message + cat <<- _EOF_ + $PROGNAME Version. $VERSION + $(usage) + + Options: + -a, --add Add Domain Record 域名 ip (默认类型TXT) + -d, --delete Delete Domain Record 域名 (默认类型TXT) + -s, --search Search Domain Record 域名 + -t, --type Record Type 类型(A、MX、CNAME、TXT、REDIRECT_URL、FORWORD_URL、NS、AAAA、SRV) + _EOF_ +} + +_arg_check(){ + [ -z "$1" ] || _arg_count=$1 + shift + [ ${#} -lt $_arg_count ] && help_message && exit 1 || (echo $2 | grep "^-") && help_message && exit 1 + #If the number of arguments <$_ARG_COUNT print help and exit, and if the second argument begins with “-” print help and exit + return 0 +} + +#[ ${#} -lt 2 ] && help_message && exit 1 #Same as below +#[ -z "$2" ] && help_message && exit 1 #Same as below +_arg_check 2 $@ + +_debug (){ + if [ "$__debug" -eq 1 ]; then + echo -e "\033[1;31m # debug: $(date "+%m %d %T") | Func: ${FUNCNAME[@]} | Line:${BASH_LINENO[@]} \033[0m" "\n $@ " #"Current FUNCNAME ${FUNCNAME} #$LINENO " #"$(($RANDOM%10))" + fi + return 0 +} + +_requires() { + _cmds='' # Check if the commands exists + if [[ "$#" -gt 0 ]]; then + for i in "$@"; do + if eval type type >/dev/null 2>&1; then + eval type "$i" >/dev/null 2>&1 + elif command >/dev/null 2>&1; then + command -v "$i" >/dev/null 2>&1 + else + which "$i" >/dev/null 2>&1 + fi + #[ "$?" -eq 0 ] && _debug "checking for $i exists = ok" || _cmds=$_cmds"$i: " + #shellcheck disable=SC2181 + if [ "$?" -eq 0 ]; then + #_debug "checking for $i exists = ok" + continue + else + _cmds=$_cmds"$i: " + fi + done + else + echo "Usage: _requires [command] " + return 1 + fi + [ -n "$_cmds" ] && { echo -e "\033[1;31m $_cmds command not found \033[0m" && return 1 ;} || return 0 +} + +_requires openssl + +#shellcheck disable=SC2120 +_hex_dump() { #ascii hex + local _str='' + [ $# -gt 0 ] && _str=$@ || read _str + local _str_len=${#_str} + local i=1 + while [ "$i" -le "$_str_len" ]; do + local _str_c="$(printf "%s" "$_str" | cut -c "$i")" + printf " %02x" "'$_str_c" + i=$(($i + 1)) + done + #printf "%s" " 0a" +} + +_urlencode() { + local length="${#1}" + local i='' + for i in $(awk "BEGIN { for ( i=0; i<$length; i++ ) print i }") + do + #local _strc="$(printf "%s" "$1" | cut -c "$i")" #i=1; i<=$length; i++ + local _strc="${1:$i:1}" + case $_strc in [a-zA-Z0-9.~_-]) printf "%s" "$_strc" ;; *) printf "%%%02X" "'$_strc" ;; + esac + done +} + +_signature(){ + signature='' + _hexkey=$(printf "%s" "$AccessKeySecret&" | _hex_dump |sed 's/ //g') + #signature=$(printf "%s" "GET&%2F&$(_urlencode "$query")" | openssl dgst -sha1 -hmac $(printf "%s" "$AccessKeySecret&" | _hex_dump |sed 's/ //g'| xxd -r -p ) -binary | openssl base64 -e) + signature=$(printf "%s" "GET&%2F&$(_urlencode "$query")" | openssl dgst -sha1 -mac HMAC -macopt "hexkey:$_hexkey" -binary | openssl base64 -e) + signature=$(_urlencode "$signature") +} + +_query() { + [ -n "$__type" ] && { [[ "$_Action" = "AddDomainRecord" ]] && _Type="$__type" || { [ "$_Action" = "DescribeDomainRecords" ] && _TypeKeyWord="$__type"; } ; } + query='' + [ -n $AccessKeyId ] && query=$query'AccessKeyId='$AccessKeyId + query=$query'&Action='"$1" + [ -z $_DomainNames ] || query=$query'&DomainName='$_DomainNames + query=$query'&Format=json' + [ -z $_RR ] || query=$query'&RR='$_RR + [ -z $_RRKeyWord ] || query=$query'&RRKeyWord='$_RRKeyWord + [ -z $_RecordId ] || query=$query'&RecordId='$_RecordId + query=$query'&SignatureMethod=HMAC-SHA1' + query=$query"&SignatureNonce=$(date +"%s%N")" + query=$query'&SignatureVersion=1.0' + query=$query'&Timestamp='$_timestamp + [ -z $_Type ] || query=$query'&Type='$_Type + [ -z $_TypeKeyWord ] || query=$query'&TypeKeyWord='$_TypeKeyWord + [ -z $_Value ] || query=$query'&Value='$_Value + [ -z $_ValueKeyWord ] || query=$query'&ValueKeyWord='$_ValueKeyWord + query=$query'&Version=2015-01-09' + #_debug "$query" + _signature + return 0 +} + +_Get_RecordIds(){ + _Action="DescribeDomainRecords" + _query $_Action $_DomainNames + url="${Ali_API}?${query}&Signature=${signature}" + _debug $url + _RecordIds=$(curl -k -s $url | grep -Po 'RecordId[": "]+\K[^"]+') && __delete="1" #RecordId requisite + _debug $_RecordIds + return 0 +} + +__type='TXT' +_DomainNames=$(printf "%s" $1| awk -F"." '{if(NF>=2){print $(NF-1)"."$NF}}') #awk -F\. '{print $(NF-1) FS $NF}') #requisite +_RRKeyWord="_acme-challenge" + +_Get_RecordIds + +_RRKeyWord='' +_TypeKeyWord='' +_ValueKeyWord='' + +if [ "$__delete" = "1" ];then + _Action="DeleteDomainRecord" #Action requisite + _DomainNames='' + for _RecordId in ${_RecordIds[@]} #Delete multiple txt domain record + do + _debug "_RecordId" $_RecordId + _query $_Action $_RecordId + url="${Ali_API}?${query}&Signature=${signature}" + _debug $url + curl -k -s $url && ( echo -e "\n\033[1;32m Aliyun DNS record _acme-challenge.$1 has been deleted \033[0m") + done +else + _Action="AddDomainRecord" #requisite + _RR=$(printf "_acme-challenge.%s" $1| awk -F'.' '{if(NF>2){gsub("."$(NF-1)"."$NF,"");print}}') #requisite + _Value=$2 #requisite + _query $_Action $_DomainNames + url="${Ali_API}?${query}&Signature=${signature}" + _debug $url + curl -k -s $url && (echo -e "\n\033[1;32m Start Checking aliyun DNS record _acme-challenge.$1 \033[0m") + exit 0 +fi diff --git a/dns_scripts/dns_add_godaddy b/dns_scripts/dns_add_godaddy index dfd3b3b..f9be745 100755 --- a/dns_scripts/dns_add_godaddy +++ b/dns_scripts/dns_add_godaddy @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (2017) Timothe Litt litt at acm _dot org +# Copyright (C) 2017, 2018 Timothe Litt litt at acm _dot org # Add token to GoDaddy dns using dns_godaddy @@ -36,5 +36,6 @@ fi export GODADDY_KEY export GODADDY_SECRET +export GODADDY_BASE $GODADDY_SCRIPT -q add "${fulldomain}" "_acme-challenge.${fulldomain}." "${token}" diff --git a/dns_scripts/dns_add_nsupdate b/dns_scripts/dns_add_nsupdate index 98f5e7f..2680d81 100755 --- a/dns_scripts/dns_add_nsupdate +++ b/dns_scripts/dns_add_nsupdate @@ -21,8 +21,9 @@ if [ -n "${DNS_NSUPDATE_KEYFILE}" ]; then options="-k ${DNS_NSUPDATE_KEYFILE}" fi +cmd= if [ -n "${DNS_SERVER}" ]; then - cmd+="server ${DNS_SERVER}\n" + cmd+="server ${DNS_SERVER}\n" fi cmd+="update add ${DNS_ZONE:-"_acme-challenge.${fulldomain}."} 300 in TXT \"${token}\"\n" diff --git a/dns_scripts/dns_del_cpanel b/dns_scripts/dns_del_cpanel new file mode 100644 index 0000000..922151a --- /dev/null +++ b/dns_scripts/dns_del_cpanel @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +# Need to add your email address and API key to cpanel below or set as env variables +user=${CPANEL_USERNAME:-''} +password=${CPANEL_PASSWORD:-''} +url=${CPANEL_URL:-''} # e.g. https://www.cpanel-host.test:2083 +apitoken=${CPANEL_APITOKEN:-''} + +fulldomain="${1}" + +# Check initial parameters +if [[ -z "$fulldomain" ]]; then + echo "DNS script requires full domain name as first parameter" + exit 1 +fi +if [[ -z "$user" ]]; then + echo "CPANEL_USERNAME (username) parameter not set" + exit 1 +fi +if [[ -z "$apitoken" ]] && [[ -z "$password" ]]; then + echo "Must set either CPANEL_APITOKEN or CPANEL_PASSWORD in dns script, environment variable or getssl.cfg" + exit 1 +fi +if [[ -z "$url" ]]; then + echo "CPANEL_URL (url) parameter not set" + exit 1 +fi + +# Setup +request_func="${url}/json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit" +if [[ -n $apitoken ]]; then + curl_params=( -H "Authorization: cpanel $user:$apitoken" ) +else + auth_string=$(echo -ne "$user:$password" | base64 --wrap 0) + curl_params=( -H "Authorization: Basic $auth_string" ) +fi + +# Check if domain is a CNAME +res=$(dig CNAME "$fulldomain") +domain=$(echo "$res"| awk '$4 ~ "CNAME" {print $5}' |sed 's/\.$//g') +if [[ -n "$domain" ]]; then + name=".${fulldomain%.$domain}" +else + domain=$fulldomain + name="" +fi + +# Find line number of existing record +request_params="&cpanel_jsonapi_func=fetchzone_records&domain=${domain}&type=TXT&name=_acme-challenge.${fulldomain}." +resp=$(curl --silent "${curl_params[@]}" "$request_func$request_params") +if [[ "$resp" = *\"error\":* ]]; then + echo -n "cpanel fetchzone records failed: " + echo "$resp" | awk -F"error" '{ print $2 }' | awk -F\" '{ print $3 }' + exit 1 +fi + +# shellcheck disable=SC2001 +line=$(echo "$resp" | sed -e 's/.*line":\([0-9]*\),.*/\1/') +if [[ "$line" != "" ]]; then + # Delete the challenge token + request_params="&cpanel_jsonapi_func=remove_zone_record&domain=$domain&type=TXT&name=_acme-challenge$name&line=$line" + resp=$(curl --silent "${curl_params[@]}" "$request_func$request_params") +fi + +if [[ "$resp" = *\"status\":0* ]]; then + echo -n "cpanel remove zone record failed: " + echo "$resp" | awk -F"statusmsg" '{ print $2 }' | awk -F\" '{ print $3 }' + exit 1 +fi diff --git a/dns_scripts/dns_del_godaddy b/dns_scripts/dns_del_godaddy index 1f17c35..4a3228f 100755 --- a/dns_scripts/dns_del_godaddy +++ b/dns_scripts/dns_del_godaddy @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (2017) Timothe Litt litt at acm _dot org +# Copyright (C) 2017,2018 Timothe Litt litt at acm _dot org # Remove token from GoDaddy dns using dns_godaddy @@ -24,7 +24,7 @@ token="$2" [ -z "$GODADDY_SCRIPT" ] && GODADDY_SCRIPT="/usr/share/getssl/dns_scripts/dns_godaddy" [[ "$GODADDY_SCRIPT" =~ ^~ ]] && \ - eval 'GODADDY_SCRIPT=`readlink -nf ' "$GODADDY_SCRIPT" '`' + eval 'GODADDY_SCRIPT=`readlink -nf ' $GODADDY_SCRIPT '`' if ! [ -x "$GODADDY_SCRIPT" ]; then echo "$GODADDY_SCRIPT: not found. Please install, softlink or set GODADDY_SCRIPT to its full path" @@ -34,5 +34,6 @@ fi export GODADDY_KEY export GODADDY_SECRET +export GODADDY_BASE $GODADDY_SCRIPT -q del "${fulldomain}" "_acme-challenge.${fulldomain}." "${token}" diff --git a/dns_scripts/dns_del_nsupdate b/dns_scripts/dns_del_nsupdate index c0432b6..fc5a254 100755 --- a/dns_scripts/dns_del_nsupdate +++ b/dns_scripts/dns_del_nsupdate @@ -21,8 +21,9 @@ if [ -n "${DNS_NSUPDATE_KEYFILE}" ]; then options="-k ${DNS_NSUPDATE_KEYFILE}" fi +cmd= if [ -n "${DNS_SERVER}" ]; then - cmd+="server ${DNS_SERVER}\n" + cmd+="server ${DNS_SERVER}\n" fi cmd+="update delete ${DNS_ZONE:-"_acme-challenge.${fulldomain}."} 300 in TXT \"${token}\"\n" diff --git a/dns_scripts/dns_godaddy b/dns_scripts/dns_godaddy old mode 100644 new mode 100755 index 4443bd4..0d41e6a --- a/dns_scripts/dns_godaddy +++ b/dns_scripts/dns_godaddy @@ -1,8 +1,8 @@ #!/bin/bash -# Copyright (2017) Timothe Litt litt at acm _dot org +# Copyright (C) 2017,2018 Timothe Litt litt at acm _dot org -VERSION="1.0.1" +VERSION="1.0.3" PROG="`basename $0`" # This script is used to update TXT records in GoDaddy DNS server @@ -31,6 +31,7 @@ DEBUG="$GODADDY_DEBUG" while getopts 'dhj:k:s:t:qv' opt; do case $opt in + b) GODADDY_BASE="$OPTARG" ;; d) DEBUG="Y" ;; j) JSON="$OPTARG" ;; k) GODADDY_KEY="$OPTARG" ;; @@ -72,6 +73,9 @@ Arguments: For minimal trace output (to override -q), define GODADDY_TRACE="y". Options + -b Domain name(s) in which challenge records are stored + E.g. often, www.example.net is stored in example.net. + Default from GODADDY_BASE -d Provide debugging output - all requests and responses -h This help. -j: Location of JSON.sh Default `dirname $0`/JSON.sh, or @@ -84,6 +88,7 @@ Options All output, except for this help text, is to stderr. Environment variables + GODADDY_BASE Domain name(s) in which challenge records are stored GODADDY_JSON location of the JSOH.sh script GODADDY_KEY default API key GODADDY_SCRIPT location of this script, default location of JSON.sh @@ -92,7 +97,7 @@ Environment variables GODADDY_TFILE appends protocol trace to file. Overrides -t BUGS - Due to a limitation of the gOdADDY API, deleting the last TXT record + Due to a limitation of the GoDaddy API, deleting the last TXT record would be too risky for my taste. So in that case, I replace it with _dummy.record_.domain. TXT "Ihis record is not used". This record is not automatically deleted by this script, though it's perfectly OK to @@ -207,9 +212,25 @@ if [ "$op" = "add" ]; then while [[ "$domain" =~ [^.]+\.[^.]+ ]]; do - url="$API/$domain/records/TXT/$name" + reqname="$name" + # The API doesn't trim the base domain from the name (it used to) + # If specified, remove any listed base. + if [ -n "$GODADDY_BASE" ]; then + for GDB in $GODADDY_BASE; do + gdb="`echo "$GDB" | sed -e's/\\.$//;s/\\./\\\\./g;'`" + gdb="^(.+)\\.$gdb\\.?$" + if [[ "$name" =~ $gdb ]]; then + reqname="${BASH_REMATCH[1]}" + break; + fi + done + else + eval 'reqname="$''{name%'"'.$domain.'}"'"' + fi + + url="$API/$domain/records/TXT/$reqname" - request='{"data":"'$data'","ttl":'$ttl'}' + request='[{"data":"'$data'","ttl":'$ttl'}]' [ -n "$DEBUG" ] && cat >&2 <&2 exit 1 # Intent was to change DNS, so this is an error diff --git a/dns_scripts/dns_route53.py b/dns_scripts/dns_route53.py index f2011bf..6b88b37 100755 --- a/dns_scripts/dns_route53.py +++ b/dns_scripts/dns_route53.py @@ -70,7 +70,7 @@ if action == 'UPSERT': try: my_resolver = dns.resolver.Resolver(configure=False) my_resolver.nameservers = ['8.8.8.8', '8.8.4.4'] - results = my_resolver.query(challenge_fqdn, 'TXT') + results = my_resolver.resolve(challenge_fqdn, 'TXT') data = str(results.response.answer[0][0]).strip('\"') if data == challenge: print("found {f} entry".format(f=challenge_fqdn)) diff --git a/test/17-test-spaces-in-sans-dns01.bats b/test/17-test-spaces-in-sans-dns01.bats index 9f3b3dc..9d425af 100644 --- a/test/17-test-spaces-in-sans-dns01.bats +++ b/test/17-test-spaces-in-sans-dns01.bats @@ -50,11 +50,6 @@ setup() { CONFIG_FILE="getssl-dns01-spaces-sans-and-ignore-dir-domain.cfg" setup_environment - # Add hosts to DNS (also need to be added as aliases in docker-compose.yml) - for prefix in a b c; do - curl --silent -X POST -d '{"host":"'$prefix.$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a - done - init_getssl create_certificate assert_success @@ -70,10 +65,6 @@ setup() { assert_success check_output_for_errors cleanup_environment - - for prefix in a b c; do - curl --silent -X POST -d '{"host":"'$prefix.$GETSSL_HOST'"}' http://10.30.50.3:8055/clear-a - done } @@ -84,13 +75,13 @@ setup() { CONFIG_FILE="getssl-dns01-spaces-and-commas-sans.cfg" setup_environment - # Add hosts to DNS (also need to be added as aliases in docker-compose.yml) - for prefix in a b c; do - curl --silent -X POST -d '{"host":"'$prefix.$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a - done - init_getssl create_certificate assert_success check_output_for_errors + cleanup_environment + + for prefix in a b c; do + curl --silent -X POST -d '{"host":"'$prefix.$GETSSL_HOST'"}' http://10.30.50.3:8055/clear-a + done } diff --git a/test/17-test-spaces-in-sans-http01.bats b/test/17-test-spaces-in-sans-http01.bats index fab530f..1730e99 100644 --- a/test/17-test-spaces-in-sans-http01.bats +++ b/test/17-test-spaces-in-sans-http01.bats @@ -50,11 +50,6 @@ setup() { CONFIG_FILE="getssl-http01-spaces-sans-and-ignore-dir-domain.cfg" setup_environment - # Add hosts to DNS (also need to be added as aliases in docker-compose.yml) - for prefix in a b c; do - curl --silent -X POST -d '{"host":"'$prefix.$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a - done - init_getssl create_certificate assert_success @@ -70,10 +65,6 @@ setup() { assert_success check_output_for_errors cleanup_environment - - for prefix in a b c; do - curl --silent -X POST -d '{"host":"'$prefix.$GETSSL_HOST'"}' http://10.30.50.3:8055/clear-a - done } @@ -84,13 +75,13 @@ setup() { CONFIG_FILE="getssl-http01-spaces-and-commas-sans.cfg" setup_environment - # Add hosts to DNS (also need to be added as aliases in docker-compose.yml) - for prefix in a b c; do - curl --silent -X POST -d '{"host":"'$prefix.$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a - done - init_getssl create_certificate assert_success check_output_for_errors + cleanup_environment + + for prefix in a b c; do + curl --silent -X POST -d '{"host":"'$prefix.$GETSSL_HOST'"}' http://10.30.50.3:8055/clear-a + done } diff --git a/test/18-retry-dns-add.bats b/test/18-retry-dns-add.bats index 3a79880..25318de 100644 --- a/test/18-retry-dns-add.bats +++ b/test/18-retry-dns-add.bats @@ -30,8 +30,9 @@ DNS_EXTRA_WAIT=0 CHECK_ALL_AUTH_DNS="false" CHECK_PUBLIC_DNS_SERVER="false" DNS_WAIT_RETRY_ADD="true" +_RUNNING_TEST=1 EOF - create_certificate -d + create_certificate assert_failure - assert_line --partial "Retrying adding dns via command" + assert_line --partial "Retrying adding DNS via command" } diff --git a/test/35-preferred-chain.bats b/test/35-preferred-chain.bats index 4389d3b..9c3fc6b 100644 --- a/test/35-preferred-chain.bats +++ b/test/35-preferred-chain.bats @@ -15,10 +15,12 @@ setup() { @test "Use PREFERRED_CHAIN to select an alternate root" { if [ -n "$STAGING" ]; then - PREFERRED_CHAIN="Fake LE Root X2" + PREFERRED_CHAIN="\(STAGING\) Pretend Pear X1" + CHECK_CHAIN="(STAGING) Pretend Pear X1" else - PREFERRED_CHAIN=$(curl --silent https://pebble:15000/roots/2 | openssl x509 -text -noout | grep "Issuer:" | cut -d= -f2) + PREFERRED_CHAIN=$(curl --silent https://pebble:15000/roots/2 | openssl x509 -text -noout | grep "Issuer:" | awk -F"CN *= *" '{ print $2 }') PREFERRED_CHAIN="${PREFERRED_CHAIN# }" # remove leading whitespace + CHECK_CHAIN=$PREFERRED_CHAIN fi CONFIG_FILE="getssl-dns01.cfg" @@ -33,18 +35,25 @@ EOF assert_success check_output_for_errors - issuer=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.crt" | openssl pkcs7 -print_certs -text -noout | grep Issuer: | tail -1 | cut -d= -f2) + issuer=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.crt" | openssl pkcs7 -print_certs -text -noout | grep Issuer: | tail -1 | awk -F"CN=" '{ print $2 }') # verify certificate is issued by preferred chain root - [ "$PREFERRED_CHAIN" = "$issuer" ] + if [[ "${CHECK_CHAIN}" != "$issuer" ]]; then + echo "# PREFERRED_CHAIN=$PREFERRED_CHAIN" + echo "# issuer=$issuer" + fi + + [ "${CHECK_CHAIN}" = "$issuer" ] } @test "Use PREFERRED_CHAIN to select the default root" { if [ -n "$STAGING" ]; then - PREFERRED_CHAIN="Fake LE Root X1" + PREFERRED_CHAIN="\(STAGING\) Doctored Durian Root CA X3" + CHECK_CHAIN="(STAGING) Doctored Durian Root CA X3" else - PREFERRED_CHAIN=$(curl --silent https://pebble:15000/roots/0 | openssl x509 -text -noout | grep Issuer: | cut -d= -f2 ) + PREFERRED_CHAIN=$(curl --silent https://pebble:15000/roots/0 | openssl x509 -text -noout | grep Issuer: | awk -F"CN *= *" '{ print $2 }') PREFERRED_CHAIN="${PREFERRED_CHAIN# }" # remove leading whitespace + CHECK_CHAIN=$PREFERRED_CHAIN fi CONFIG_FILE="getssl-dns01.cfg" @@ -59,17 +68,21 @@ EOF assert_success check_output_for_errors - issuer=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.crt" | openssl pkcs7 -print_certs -text -noout | grep Issuer: | tail -1 | cut -d= -f2) + issuer=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.crt" | openssl pkcs7 -print_certs -text -noout | grep Issuer: | tail -1 | awk -F"CN=" '{ print $2 }') # verify certificate is issued by preferred chain root - [ "$PREFERRED_CHAIN" = "$issuer" ] + if [[ "${CHECK_CHAIN}" != "$issuer" ]]; then + echo "# PREFERRED_CHAIN=$PREFERRED_CHAIN" + echo "# issuer=$issuer" + fi + [ "${CHECK_CHAIN}" = "$issuer" ] } @test "Use PREFERRED_CHAIN to select an alternate root by suffix" { if [ -n "$STAGING" ]; then - FULL_PREFERRED_CHAIN="Fake LE Root X2" + FULL_PREFERRED_CHAIN="(STAGING) Pretend Pear X1" else - FULL_PREFERRED_CHAIN=$(curl --silent https://pebble:15000/roots/2 | openssl x509 -text -noout | grep "Issuer:" | cut -d= -f2) + FULL_PREFERRED_CHAIN=$(curl --silent https://pebble:15000/roots/2 | openssl x509 -text -noout | grep "Issuer:" | awk -F"CN *= *" '{ print $2 }') FULL_PREFERRED_CHAIN="${FULL_PREFERRED_CHAIN# }" # remove leading whitespace fi @@ -87,9 +100,12 @@ EOF assert_success check_output_for_errors - issuer=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.crt" | openssl pkcs7 -print_certs -text -noout | grep Issuer: | tail -1 | cut -d= -f2) + issuer=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.crt" | openssl pkcs7 -print_certs -text -noout | grep Issuer: | tail -1 | awk -F"CN=" '{ print $2 }') # verify certificate is issued by preferred chain root - echo "# ${issuer}" - echo "# ${FULL_PREFERRED_CHAIN}" - [ "$FULL_PREFERRED_CHAIN" = "$issuer" ] + if [[ "${FULL_PREFERRED_CHAIN}" != "$issuer" ]]; then + echo "# PREFERRED_CHAIN=$PREFERRED_CHAIN" + echo "# FULL_PREFERRED_CHAIN=$FULL_PREFERRED_CHAIN" + echo "# issuer=$issuer" + fi + [ "${FULL_PREFERRED_CHAIN}" = "$issuer" ] } diff --git a/test/36-full-chain-inc-root.bats b/test/36-full-chain-inc-root.bats new file mode 100644 index 0000000..5b29d0b --- /dev/null +++ b/test/36-full-chain-inc-root.bats @@ -0,0 +1,94 @@ +#! /usr/bin/env bats + +load '/bats-support/load.bash' +load '/bats-assert/load.bash' +load '/getssl/test/test_helper.bash' + + +# This is run for every test +setup() { + if [ -z "$STAGING" ]; then + export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt + fi +} + + +@test "Use FULL_CHAIN_INCLUDE_ROOT to include the root certificate in the fullchain" { + CONFIG_FILE="getssl-dns01.cfg" + setup_environment + init_getssl + + cat <<- EOF > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg +FULL_CHAIN_INCLUDE_ROOT="true" +EOF + + create_certificate + assert_success + check_output_for_errors + + if [ -n "$STAGING" ]; then + PREFERRED_CHAIN="(STAGING) Doctored Durian Root CA X3" + else + # pebble doesn't support CA Issuers so the fullchain.crt will just contain the certificate (code path means it won't contain the intermediate cert in this case) + # This is testing that requesting FULL_CHAIN_INCLUDE_ROOT doesn't fail if there is no CA Issuers in the certificate + PREFERRED_CHAIN=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.crt" | openssl pkcs7 -print_certs -text -noout | grep Subject: | tail -1 | awk -F"CN=" '{ print $2 }') + fi + + final_issuer=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.crt" | openssl pkcs7 -print_certs -text -noout | grep Subject: | tail -1 | awk -F"CN=" '{ print $2 }') + + # verify certificate includes the chain root + if [[ "${PREFERRED_CHAIN}" != "$final_issuer" ]]; then + echo "# PREFERRED_CHAIN=$PREFERRED_CHAIN" + echo "# final_issuer=$final_issuer" + fi + [ "${PREFERRED_CHAIN}" = "$final_issuer" ] +} + + +@test "Use FULL_CHAIN_INCLUDE_ROOT with dual certificates" { + if [ -n "$STAGING" ]; then + PREFERRED_CHAIN="(STAGING) Doctored Durian Root CA X3" + fi + + CONFIG_FILE="getssl-dns01.cfg" + setup_environment + init_getssl + + cat <<- EOF > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg +FULL_CHAIN_INCLUDE_ROOT="true" +DUAL_RSA_ECDSA="true" +ACCOUNT_KEY_TYPE="prime256v1" +PRIVATE_KEY_ALG="prime256v1" +CHECK_REMOTE="false" +EOF + + create_certificate + assert_success + check_output_for_errors + check_certificates + assert [ -e "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/chain.ec.crt" ] + assert [ -e "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.ec.crt" ] + assert [ -e "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.ec.crt" ] + + if [ -n "$STAGING" ]; then + PREFERRED_CHAIN="(STAGING) Doctored Durian Root CA X3" + else + # pebble doesn't support CA Issuers so the fullchain.crt will just contain the certificate (code path means it won't contain the intermediate cert in this case) + # This is testing that requesting FULL_CHAIN_INCLUDE_ROOT doesn't fail if there is no CA Issuers in the certificate + PREFERRED_CHAIN=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.crt" | openssl pkcs7 -print_certs -text -noout | grep Subject: | tail -1 | awk -F"CN=" '{ print $2 }') + fi + + # verify both rsa and ecdsa certificates include the chain root + final_issuer=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.crt" | openssl pkcs7 -print_certs -text -noout | grep Subject: | tail -1 | awk -F"CN=" '{ print $2 }') + if [[ "${PREFERRED_CHAIN}" != "$final_issuer" ]]; then + echo "# PREFERRED_CHAIN=$PREFERRED_CHAIN" + echo "# final_issuer=$final_issuer" + fi + [ "${PREFERRED_CHAIN}" = "$final_issuer" ] + ecdsa_final_issuer=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.ec.crt" | openssl pkcs7 -print_certs -text -noout | grep Subject: | tail -1 | awk -F"CN=" '{ print $2 }') + if [[ "$PREFERRED_CHAIN" != "$ecdsa_final_issuer" ]]; then + echo "# PREFERRED_CHAIN=$PREFERRED_CHAIN" + echo "# ecdsa_final_issuer=$ecdsa_final_issuer" + fi + [ "${PREFERRED_CHAIN}" = "$ecdsa_final_issuer" ] +} diff --git a/test/Dockerfile-alpine b/test/Dockerfile-alpine index 924950b..2c28f48 100644 --- a/test/Dockerfile-alpine +++ b/test/Dockerfile-alpine @@ -8,8 +8,7 @@ WORKDIR /root # Create nginx directories in standard places RUN mkdir /run/nginx -RUN mkdir /etc/nginx/pki -RUN mkdir /etc/nginx/pki/private +RUN mkdir -p /etc/nginx/pki/private # Setup ftp ENV VSFTPD_CONF=/etc/vsftpd.conf @@ -24,11 +23,11 @@ RUN chown -R ftpuser.www-data /var/www RUN chmod g+w -R /var/www # BATS (Bash Automated Testings) -RUN git clone https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 -RUN git clone https://github.com/bats-core/bats-support /bats-support -RUN git clone https://github.com/bats-core/bats-assert /bats-assert +RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 +RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support +RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert RUN /bats-core/install.sh /usr/local # Use supervisord to run nginx in the background COPY ./test/test-config/alpine-supervisord.conf /etc/supervisord.conf -CMD tail -f /dev/null +CMD [ "tail", "-f", "/dev/null" ] diff --git a/test/Dockerfile-centos6 b/test/Dockerfile-centos6 index a8d59b0..e16388f 100644 --- a/test/Dockerfile-centos6 +++ b/test/Dockerfile-centos6 @@ -30,8 +30,7 @@ RUN chown -R www-data.www-data /var/www RUN chmod g+w -R /var/www WORKDIR /root -RUN mkdir /etc/nginx/pki -RUN mkdir /etc/nginx/pki/private +RUN mkdir -p /etc/nginx/pki/private COPY ./test/test-config/nginx-ubuntu-no-ssl /etc/nginx/conf.d/default.conf # BATS (Bash Automated Testings) @@ -45,4 +44,4 @@ ENV CI=yes EXPOSE 80 443 # Run eternal loop - for testing -CMD tail -f /dev/null +CMD [ "tail", "-f", "/dev/null" ] diff --git a/test/Dockerfile-centos7 b/test/Dockerfile-centos7 index 8bf8fa9..794e0bd 100644 --- a/test/Dockerfile-centos7 +++ b/test/Dockerfile-centos7 @@ -8,8 +8,7 @@ RUN yum -y install ftp vsftpd RUN yum -y install openssh-server WORKDIR /root -RUN mkdir /etc/nginx/pki -RUN mkdir /etc/nginx/pki/private +RUN mkdir -p /etc/nginx/pki/private COPY ./test/test-config/nginx-ubuntu-no-ssl /etc/nginx/conf.d/default.conf COPY ./test/test-config/nginx-centos7.conf /etc/nginx/nginx.conf @@ -27,7 +26,7 @@ RUN chown -R www-data.www-data /var/www RUN chmod g+w -R /var/www # BATS (Bash Automated Testings) -RUN git clone https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 -RUN git clone https://github.com/bats-core/bats-support /bats-support -RUN git clone https://github.com/bats-core/bats-assert /bats-assert +RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 +RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support +RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert RUN /bats-core/install.sh /usr/local diff --git a/test/Dockerfile-centos7-duckdns b/test/Dockerfile-centos7-duckdns index 719c9de..bf85592 100644 --- a/test/Dockerfile-centos7-duckdns +++ b/test/Dockerfile-centos7-duckdns @@ -12,18 +12,17 @@ ENV dynamic_dns "dynu" ENV DUCKDNS_TOKEN 1d616aa9-b8e4-4bb4-b312-3289de82badb WORKDIR /root -RUN mkdir /etc/nginx/pki -RUN mkdir /etc/nginx/pki/private +RUN mkdir -p /etc/nginx/pki/private COPY ./test/test-config/nginx-ubuntu-no-ssl /etc/nginx/conf.d/default.conf COPY ./test/test-config/nginx-centos7.conf /etc/nginx/nginx.conf # BATS (Bash Automated Testings) -RUN git clone https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 -RUN git clone https://github.com/bats-core/bats-support /bats-support -RUN git clone https://github.com/bats-core/bats-assert /bats-assert +RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 +RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support +RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert RUN /bats-core/install.sh /usr/local EXPOSE 80 443 # Run eternal loop - for testing -CMD tail -f /dev/null +CMD [ "tail", "-f", "/dev/null" ] diff --git a/test/Dockerfile-centos8 b/test/Dockerfile-centos8 index 64f4381..210bd8e 100644 --- a/test/Dockerfile-centos8 +++ b/test/Dockerfile-centos8 @@ -10,8 +10,7 @@ RUN yum -y install ftp vsftpd RUN yum -y install openssh-server WORKDIR /root -RUN mkdir /etc/nginx/pki -RUN mkdir /etc/nginx/pki/private +RUN mkdir -p /etc/nginx/pki/private COPY ./test/test-config/nginx-ubuntu-no-ssl /etc/nginx/conf.d/default.conf COPY ./test/test-config/nginx-centos7.conf /etc/nginx/nginx.conf @@ -29,7 +28,7 @@ RUN chown -R www-data.www-data /var/www RUN chmod g+w -R /var/www # BATS (Bash Automated Testings) -RUN git clone https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 -RUN git clone https://github.com/bats-core/bats-support /bats-support -RUN git clone https://github.com/bats-core/bats-assert /bats-assert +RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 +RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support +RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert RUN /bats-core/install.sh /usr/local diff --git a/test/Dockerfile-debian b/test/Dockerfile-debian index fa74995..04e5232 100644 --- a/test/Dockerfile-debian +++ b/test/Dockerfile-debian @@ -9,8 +9,7 @@ RUN apt-get install -y ftp vsftpd RUN apt-get install -y openssh-server WORKDIR /root -RUN mkdir /etc/nginx/pki -RUN mkdir /etc/nginx/pki/private +RUN mkdir -p /etc/nginx/pki/private # Setup ftp ENV VSFTPD_CONF=/etc/vsftpd.conf @@ -24,10 +23,10 @@ RUN chown -R www-data.www-data /var/www RUN chmod g+w -R /var/www # BATS (Bash Automated Testings) -RUN git clone https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 -RUN git clone https://github.com/bats-core/bats-support /bats-support -RUN git clone https://github.com/bats-core/bats-assert /bats-assert +RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 +RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support +RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert RUN /bats-core/install.sh /usr/local # Run eternal loop - for testing -CMD tail -f /dev/null +CMD [ "tail", "-f", "/dev/null" ] diff --git a/test/Dockerfile-ubuntu b/test/Dockerfile-ubuntu index 68813f8..dd8338d 100644 --- a/test/Dockerfile-ubuntu +++ b/test/Dockerfile-ubuntu @@ -29,10 +29,10 @@ WORKDIR /root RUN touch /root/.rnd # BATS (Bash Automated Testings) -RUN git clone https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 -RUN git clone https://github.com/bats-core/bats-support /bats-support -RUN git clone https://github.com/bats-core/bats-assert /bats-assert +RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 +RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support +RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert RUN /bats-core/install.sh /usr/local # Run eternal loop - for testing -CMD tail -f /dev/null +CMD [ "tail", "-f", "/dev/null" ] diff --git a/test/Dockerfile-ubuntu-duckdns b/test/Dockerfile-ubuntu-duckdns index f4cf9e3..a07bb23 100644 --- a/test/Dockerfile-ubuntu-duckdns +++ b/test/Dockerfile-ubuntu-duckdns @@ -21,10 +21,10 @@ WORKDIR /root RUN touch /root/.rnd # BATS (Bash Automated Testings) -RUN git clone https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 -RUN git clone https://github.com/bats-core/bats-support /bats-support -RUN git clone https://github.com/bats-core/bats-assert /bats-assert +RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 +RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support +RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert RUN /bats-core/install.sh /usr/local # Run eternal loop - for testing -CMD tail -f /dev/null +CMD [ "tail", "-f", "/dev/null" ] diff --git a/test/Dockerfile-ubuntu16 b/test/Dockerfile-ubuntu16 index 184db87..00a4589 100644 --- a/test/Dockerfile-ubuntu16 +++ b/test/Dockerfile-ubuntu16 @@ -10,8 +10,7 @@ RUN apt-get install -y ftp vsftpd RUN apt-get install -y openssh-server WORKDIR /root -RUN mkdir /etc/nginx/pki -RUN mkdir /etc/nginx/pki/private +RUN mkdir -p /etc/nginx/pki/private COPY ./test/test-config/nginx-ubuntu-no-ssl /etc/nginx/sites-enabled/default # Setup ftp @@ -28,10 +27,10 @@ RUN chown -R www-data.www-data /var/www RUN chmod g+w -R /var/www # BATS (Bash Automated Testings) -RUN git clone https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 -RUN git clone https://github.com/bats-core/bats-support /bats-support -RUN git clone https://github.com/bats-core/bats-assert /bats-assert +RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 +RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support +RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert RUN /bats-core/install.sh /usr/local # Run eternal loop - for testing -CMD tail -f /dev/null +CMD [ "tail", "-f", "/dev/null" ] diff --git a/test/Dockerfile-ubuntu18 b/test/Dockerfile-ubuntu18 index ed1fae3..91a0429 100644 --- a/test/Dockerfile-ubuntu18 +++ b/test/Dockerfile-ubuntu18 @@ -10,8 +10,7 @@ RUN apt-get install -y ftp vsftpd RUN apt-get install -y openssh-server WORKDIR /root -RUN mkdir /etc/nginx/pki -RUN mkdir /etc/nginx/pki/private +RUN mkdir -p /etc/nginx/pki/private COPY ./test/test-config/nginx-ubuntu-no-ssl /etc/nginx/sites-enabled/default # Setup ftp @@ -31,12 +30,12 @@ RUN chmod g+w -R /var/www RUN touch /root/.rnd # BATS (Bash Automated Testings) -RUN git clone https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 -RUN git clone https://github.com/bats-core/bats-support /bats-support -RUN git clone https://github.com/bats-core/bats-assert /bats-assert +RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1 +RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support +RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert RUN /bats-core/install.sh /usr/local EXPOSE 80 443 # Run eternal loop - for testing -CMD tail -f /dev/null +CMD [ "tail", "-f", "/dev/null" ] diff --git a/test/test_helper.bash b/test/test_helper.bash index 11cdf44..48a8d4b 100644 --- a/test/test_helper.bash +++ b/test/test_helper.bash @@ -64,6 +64,8 @@ setup_environment() { fi if [ -z "$STAGING" ]; then + # Make sure that we have cleared any previous entries, otherwise get random dns failures + curl --silent -X POST -d '{"host":"'"$GETSSL_HOST"'"}' http://10.30.50.3:8055/clear-a curl --silent -X POST -d '{"host":"'"$GETSSL_HOST"'", "addresses":["'"$GETSSL_IP"'"]}' http://10.30.50.3:8055/add-a fi cp ${CODE_DIR}/test/test-config/nginx-ubuntu-no-ssl "${NGINX_CONFIG}" diff --git a/test/u1-test-get_auth_dns-dig.bats b/test/u1-test-get_auth_dns-dig.bats index 6e64e68..471732f 100644 --- a/test/u1-test-get_auth_dns-dig.bats +++ b/test/u1-test-get_auth_dns-dig.bats @@ -61,7 +61,7 @@ teardown() { # Assert that we've found the primary_ns server assert_output --regexp 'set primary_ns = ns[1-4]+\.duckdns\.org' # Assert that we had to use dig NS - assert_line --partial 'Using dig NS' + assert_line --regexp 'Using dig.* NS' # Check all Authoritive DNS servers are returned if requested CHECK_ALL_AUTH_DNS=true @@ -89,8 +89,8 @@ teardown() { assert_output --regexp 'set primary_ns = ns[1-4]+\.duckdns\.org' # Assert that we had to use dig NS - assert_line --partial 'Using dig SOA' - refute_line --partial 'Using dig NS' + assert_line --regexp 'Using dig.* SOA' + refute_line --regexp 'Using dig.* NS' # Check all Authoritive DNS servers are returned if requested CHECK_ALL_AUTH_DNS=true @@ -125,8 +125,8 @@ teardown() { assert_output --regexp 'set primary_ns = ns.*\.awsdns.*\.com' # Assert that we found a CNAME and use dig NS - assert_line --partial 'Using dig CNAME' - assert_line --partial 'Using dig NS' + assert_line --regexp 'Using dig.* CNAME' + assert_line --regexp 'Using dig.* NS' # Check all Authoritive DNS servers are returned if requested CHECK_ALL_AUTH_DNS=true @@ -168,8 +168,8 @@ teardown() { assert_output --regexp 'set primary_ns = ns[1-4]+\.duckdns\.org' # Assert that we found a CNAME but didn't use dig NS - assert_line --partial 'Using dig CNAME' - refute_line --partial 'Using dig NS' + assert_line --regexp 'Using dig.* CNAME' + refute_line --regexp 'Using dig.* NS' # Check all Authoritive DNS servers are returned if requested CHECK_ALL_AUTH_DNS=true diff --git a/test/u2-test-get_auth_dns-drill.bats b/test/u2-test-get_auth_dns-drill.bats index 33b2277..434a9b5 100644 --- a/test/u2-test-get_auth_dns-drill.bats +++ b/test/u2-test-get_auth_dns-drill.bats @@ -67,7 +67,7 @@ teardown() { # Assert that we've found the primary_ns server assert_output --regexp 'set primary_ns = ns[1-4]+\.duckdns\.org' # Assert that we had to use drill NS - assert_line --partial 'Using drill NS' + assert_line --regexp 'Using drill.* NS' # Check all Authoritive DNS servers are returned if requested CHECK_ALL_AUTH_DNS=true @@ -100,8 +100,8 @@ teardown() { assert_output --regexp 'set primary_ns = ns[1-4]+\.duckdns\.org' # Assert that we had to use drill NS - assert_line --partial 'Using drill SOA' - refute_line --partial 'Using drill NS' + assert_line --regexp 'Using drill.* SOA' + refute_line --regexp 'Using drill.* NS' # Check all Authoritive DNS servers are returned if requested CHECK_ALL_AUTH_DNS=true @@ -141,8 +141,8 @@ teardown() { assert_output --regexp 'set primary_ns = ns.*\.awsdns.*\.com' # Assert that we found a CNAME and use drill NS - assert_line --partial 'Using drill CNAME' - assert_line --partial 'Using drill NS' + assert_line --regexp 'Using drill.* CNAME' + assert_line --regexp 'Using drill.* NS' # Check all Authoritive DNS servers are returned if requested CHECK_ALL_AUTH_DNS=true @@ -192,8 +192,8 @@ teardown() { assert_output --regexp 'set primary_ns = ns[1-4]+\.duckdns\.org' # Assert that we found a CNAME but didn't use drill NS - assert_line --partial 'Using drill CNAME' - refute_line --partial 'Using drill NS' + assert_line --regexp 'Using drill.* CNAME' + refute_line --regexp 'Using drill.* NS' # Check all Authoritive DNS servers are returned if requested CHECK_ALL_AUTH_DNS=true diff --git a/test/u5-test-get_auth_dns-no-root-servers.bats b/test/u5-test-get_auth_dns-no-root-servers.bats index b88fd41..d218eb9 100644 --- a/test/u5-test-get_auth_dns-no-root-servers.bats +++ b/test/u5-test-get_auth_dns-no-root-servers.bats @@ -60,7 +60,7 @@ teardown() { # Assert that we've found the primary_ns server assert_output --regexp 'set primary_ns = ' # Assert that we had to use dig NS - assert_line --partial 'Using dig NS' + assert_line --regexp 'Using dig.* NS' # Check we didn't include any root servers refute_line --partial 'root-servers.net' @@ -89,7 +89,7 @@ teardown() { # Assert that we've found the primary_ns server assert_output --regexp 'set primary_ns = ' # Assert that we had to use dig SOA - assert_line --partial 'Using dig SOA' + assert_line --regexp 'Using dig.* SOA' # Check we didn't include any root servers refute_line --partial 'root-servers.net'