From 989651c23be6f8fbf2d507aaae76ec5c774f2644 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sat, 4 Feb 2017 23:17:24 -0500 Subject: [PATCH 01/35] Initial version --- deploy/sshdeploy.sh | 128 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 deploy/sshdeploy.sh diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh new file mode 100644 index 00000000..d33aad7a --- /dev/null +++ b/deploy/sshdeploy.sh @@ -0,0 +1,128 @@ +#!/usr/bin/env sh + +#Here is a script to deploy certificates to remote server by ssh +#This file name is "sshdeploy.sh" +#So, here must be a method sshdeploy_deploy() +#Which will be called by acme.sh to deploy the cert +#returns 0 means success, otherwise error. + +# The following variables exported from environment will be used. +# If not set then values previously saved in domain.conf file are used. +# +# export ACME_DEPLOY_SSH_URL="admin@qnap" +# export ACME_DEPLOY_SSH_SERVICE_STOP="/etc/init.d/stunnel.sh stop" +# export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" +# export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" +# export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" +# export ACME_DEPLOY_SSH_FULLCHAIN="" +# export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" +# export ACME_DEPLOY_SSH_SERVICE_START="/etc/init.d/stunnel.sh stop" + +. "$DOMAIN_CONF" + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +sshdeploy_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + _cmdstr="{" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if [ -z "$ACME_DEPLOY_SSH_URL" ]; then + if [ -z "$Le_Deploy_ssh_url" ]; then + _err "ACME_DEPLOY_SSH_URL not defined." + return 1 + fi + else + Le_Deploy_ssh_url="$ACME_DEPLOY_SSH_URL" + _savedomainconf Le_Deploy_ssh_url "$Le_Deploy_ssh_url" + fi + + _info "Deploy certificates to remote server $Le_Deploy_ssh_url" + + if [ -n "$ACME_DEPLOY_SSH_SERVICE_STOP" ]; then + Le_Deploy_ssh_service_stop="$ACME_DEPLOY_SSH_SERVICE_STOP" + _savedomainconf Le_Deploy_ssh_service_stop "$Le_Deploy_ssh_service_stop" + fi + if [ -n "$Le_Deploy_ssh_service_stop" ]; then + _cmdstr="$_cmdstr $Le_Deploy_ssh_service_stop ;" + _info "Will stop remote service with command $Le_Deploy_ssh_service_stop" + fi + + if [ -n "$ACME_DEPLOY_SSH_KEYFILE" ]; then + Le_Deploy_ssh_keyfile="$ACME_DEPLOY_SSH_KEYFILE" + _savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile" + fi + if [ -n "$Le_Deploy_ssh_keyfile" ]; then + _cmdstr="$_cmdstr echo \"$(cat $_ckey)\" > $Le_Deploy_ssh_keyfile ;" + _info "will copy private key to remote file $Le_Deploy_ssh_keyfile" + fi + + if [ -n "$ACME_DEPLOY_SSH_CERTFILE" ]; then + Le_Deploy_ssh_certfile="$ACME_DEPLOY_SSH_CERTFILE" + _savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile" + fi + if [ -n "$Le_Deploy_ssh_certfile" ]; then + if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then + _cmdstr="$_cmdstr echo \"$(cat $_ccert)\" >> $Le_Deploy_ssh_certfile ;" + _info "will append certificate to same file" + else + _cmdstr="$_cmdstr echo \"$(cat $_ccert)\" > $Le_Deploy_ssh_certfile ;" + _info "will copy certificate to remote file $Le_Deploy_ssh_certfile" + fi + fi + + if [ -n "$ACME_DEPLOY_SSH_CAFILE" ]; then + Le_Deploy_ssh_cafile="$ACME_DEPLOY_SSH_CAFILE" + _savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile" + fi + if [ -n "$Le_Deploy_ssh_cafile" ]; then + _cmdstr="$_cmdstr echo \"$(cat $_cca)\" > $Le_Deploy_ssh_cafile ;" + _info "will copy CA file to remote file $Le_Deploy_ssh_cafile" + fi + + if [ -n "$ACME_DEPLOY_SSH_FULLCHAIN" ]; then + Le_Deploy_ssh_fullchain="$ACME_DEPLOY_SSH_FULLCHAIN" + _savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain" + fi + if [ -n "$Le_Deploy_ssh_fullchain" ]; then + _cmdstr="$_cmdstr echo \"$(cat $_cfullchain)\" > $Le_Deploy_ssh_fullchain ;" + _info "will copy full chain to remote file $Le_Deploy_ssh_fullchain" + fi + + if [ -n "$ACME_DEPLOY_SSH_REMOTE_CMD" ]; then + Le_Deploy_ssh_remote_cmd="$ACME_DEPLOY_SSH_REMOTE_CMD" + _savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd" + fi + if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then + _cmdstr="$_cmdstr sleep 2 ; $Le_Deploy_ssh_remote_cmd ;" + _info "Will sleep 2 seconds then execute remote command $Le_Deploy_ssh_remote_cmd" + fi + + if [ -n "$ACME_DEPLOY_SSH_SERVICE_START" ]; then + Le_Deploy_ssh_service_start="$ACME_DEPLOY_SSH_SERVICE_START" + _savedomainconf Le_Deploy_ssh_service_start "$Le_Deploy_ssh_service_start" + fi + if [ -n "$Le_Deploy_ssh_service_start" ]; then + _cmdstr="$_cmdstr sleep 2 ; $Le_Deploy_ssh_service_start ;" + _info "Will sleep 2 seconds then start remote service with command $Le_Deploy_ssh_remote_cmd" + fi + + _cmdstr="$_cmdstr }" + + _debug "Remote command to execute: $_cmdstr" + + _info "Submitting sequence of commands to remote server by ssh" + ssh -T "$Le_Deploy_ssh_url" bash -c "'$_cmdstr'" + + return 0 +} From 7d75ad4c56a97ae7576bcc89eb41610df1d856b5 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 5 Feb 2017 14:35:05 -0500 Subject: [PATCH 02/35] Backup old certificates before overwriting. Add userid export parameter. And generate error if nothing to do at remote server. --- deploy/sshdeploy.sh | 104 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 82 insertions(+), 22 deletions(-) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index d33aad7a..aa924136 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -1,22 +1,26 @@ #!/usr/bin/env sh -#Here is a script to deploy certificates to remote server by ssh -#This file name is "sshdeploy.sh" -#So, here must be a method sshdeploy_deploy() -#Which will be called by acme.sh to deploy the cert -#returns 0 means success, otherwise error. - +# Script to deploy certificates to remote server by SSH +# Note that SSH must be able to login to remote host without a password... +# SSH Keys must have been exchanged with the remote host. Validate and +# test that you can login to USER@URL from the host running acme.sh before +# using this script. +# # The following variables exported from environment will be used. # If not set then values previously saved in domain.conf file are used. # -# export ACME_DEPLOY_SSH_URL="admin@qnap" -# export ACME_DEPLOY_SSH_SERVICE_STOP="/etc/init.d/stunnel.sh stop" +# Only a username is required. All others are optional. +# +# The following examples are for QNAP NAS running QTS 4.2 +# export ACME_DEPLOY_SSH_USER="admin" +# export ACME_DEPLOY_SSH_URL="qnap" +# export ACME_DEPLOY_SSH_SERVICE_STOP="" # export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" # export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" # export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" # export ACME_DEPLOY_SSH_FULLCHAIN="" # export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" -# export ACME_DEPLOY_SSH_SERVICE_START="/etc/init.d/stunnel.sh stop" +# export ACME_DEPLOY_SSH_SERVICE_START="" . "$DOMAIN_CONF" @@ -29,7 +33,9 @@ sshdeploy_deploy() { _ccert="$3" _cca="$4" _cfullchain="$5" - _cmdstr="{" + _cmdstr="" + _homedir="~/.acme_ssh_deploy" + _backupdir="$_homedir/certs-backup-$(date +%Y%m%d%H%M%S)" _debug _cdomain "$_cdomain" _debug _ckey "$_ckey" @@ -37,18 +43,29 @@ sshdeploy_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - if [ -z "$ACME_DEPLOY_SSH_URL" ]; then - if [ -z "$Le_Deploy_ssh_url" ]; then - _err "ACME_DEPLOY_SSH_URL not defined." + # USER is required to login by SSH to remote host. + if [ -z "$ACME_DEPLOY_SSH_USER" ]; then + if [ -z "$Le_Deploy_ssh_user" ]; then + _err "ACME_DEPLOY_SSH_USER not defined." return 1 fi else + Le_Deploy_ssh_user="$ACME_DEPLOY_SSH_USER" + _savedomainconf Le_Deploy_ssh_user "$Le_Deploy_ssh_user" + fi + + # URL is optional. If not provided then use _cdomain + if [ -n "$ACME_DEPLOY_SSH_URL" ]; then Le_Deploy_ssh_url="$ACME_DEPLOY_SSH_URL" _savedomainconf Le_Deploy_ssh_url "$Le_Deploy_ssh_url" + elif [ -z "$Le_Deploy_ssh_url" ]; then + Le_Deploy_ssh_url="$_cdomain" fi - _info "Deploy certificates to remote server $Le_Deploy_ssh_url" + _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_url" + # SERVICE_STOP is optional. + # If provided then this command will be executed on remote host. if [ -n "$ACME_DEPLOY_SSH_SERVICE_STOP" ]; then Le_Deploy_ssh_service_stop="$ACME_DEPLOY_SSH_SERVICE_STOP" _savedomainconf Le_Deploy_ssh_service_stop "$Le_Deploy_ssh_service_stop" @@ -58,71 +75,114 @@ sshdeploy_deploy() { _info "Will stop remote service with command $Le_Deploy_ssh_service_stop" fi + # KEYFILE is optional. + # If provided then private key will be copied to provided filename. if [ -n "$ACME_DEPLOY_SSH_KEYFILE" ]; then Le_Deploy_ssh_keyfile="$ACME_DEPLOY_SSH_KEYFILE" _savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile" fi if [ -n "$Le_Deploy_ssh_keyfile" ]; then + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir ;" + # copy new certificate into file. _cmdstr="$_cmdstr echo \"$(cat $_ckey)\" > $Le_Deploy_ssh_keyfile ;" _info "will copy private key to remote file $Le_Deploy_ssh_keyfile" fi + # CERTFILE is optional. + # If provided then private key will be copied or appended to provided filename. if [ -n "$ACME_DEPLOY_SSH_CERTFILE" ]; then Le_Deploy_ssh_certfile="$ACME_DEPLOY_SSH_CERTFILE" _savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile" fi if [ -n "$Le_Deploy_ssh_certfile" ]; then if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then + # if filename is same as that provided for private key then append. _cmdstr="$_cmdstr echo \"$(cat $_ccert)\" >> $Le_Deploy_ssh_certfile ;" _info "will append certificate to same file" else + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir ;" + # copy new certificate into file. _cmdstr="$_cmdstr echo \"$(cat $_ccert)\" > $Le_Deploy_ssh_certfile ;" _info "will copy certificate to remote file $Le_Deploy_ssh_certfile" fi fi + # CAFILE is optional. + # If provided then CA intermediate certificate will be copied to provided filename. if [ -n "$ACME_DEPLOY_SSH_CAFILE" ]; then Le_Deploy_ssh_cafile="$ACME_DEPLOY_SSH_CAFILE" _savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile" fi if [ -n "$Le_Deploy_ssh_cafile" ]; then + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir ;" + # copy new certificate into file. _cmdstr="$_cmdstr echo \"$(cat $_cca)\" > $Le_Deploy_ssh_cafile ;" _info "will copy CA file to remote file $Le_Deploy_ssh_cafile" fi + # FULLCHAIN is optional. + # If provided then fullchain certificate will be copied to provided filename. if [ -n "$ACME_DEPLOY_SSH_FULLCHAIN" ]; then Le_Deploy_ssh_fullchain="$ACME_DEPLOY_SSH_FULLCHAIN" _savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain" fi if [ -n "$Le_Deploy_ssh_fullchain" ]; then + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir ;" + # copy new certificate into file. _cmdstr="$_cmdstr echo \"$(cat $_cfullchain)\" > $Le_Deploy_ssh_fullchain ;" _info "will copy full chain to remote file $Le_Deploy_ssh_fullchain" fi + # REMOTE_CMD is optional. + # If provided then this command will be executed on remote host. + # A 2 second delay is inserted to allow system to stabalize after + # executing a service stop. if [ -n "$ACME_DEPLOY_SSH_REMOTE_CMD" ]; then Le_Deploy_ssh_remote_cmd="$ACME_DEPLOY_SSH_REMOTE_CMD" _savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd" fi if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then - _cmdstr="$_cmdstr sleep 2 ; $Le_Deploy_ssh_remote_cmd ;" - _info "Will sleep 2 seconds then execute remote command $Le_Deploy_ssh_remote_cmd" + if [ -n "$Le_Deploy_ssh_service_stop" ]; then + _cmdstr="$_cmdstr sleep 2 ;" + fi + _cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd ;" + _info "Will execute remote command $Le_Deploy_ssh_remote_cmd" fi + # SERVICE_START is optional. + # If provided then this command will be executed on remote host. + # A 2 second delay is inserted to allow system to stabalize after + # executing a service stop or previous command. if [ -n "$ACME_DEPLOY_SSH_SERVICE_START" ]; then Le_Deploy_ssh_service_start="$ACME_DEPLOY_SSH_SERVICE_START" _savedomainconf Le_Deploy_ssh_service_start "$Le_Deploy_ssh_service_start" fi if [ -n "$Le_Deploy_ssh_service_start" ]; then - _cmdstr="$_cmdstr sleep 2 ; $Le_Deploy_ssh_service_start ;" - _info "Will sleep 2 seconds then start remote service with command $Le_Deploy_ssh_remote_cmd" + if [ -n "$Le_Deploy_ssh_service_stop" ] || [ -n "$Le_Deploy_ssh_remote_cmd" ] ; then + _cmdstr="$_cmdstr sleep 2 ;" + fi + _cmdstr="$_cmdstr $Le_Deploy_ssh_service_start ;" + _info "Will start remote service with command $Le_Deploy_ssh_remote_cmd" fi - _cmdstr="$_cmdstr }" - - _debug "Remote command to execute: $_cmdstr" + if [ -z "$_cmdstr" ]; then + _err "No remote commands to excute. Failed to deploy certificates to remote server" + return 1 + else + # something to execute. + # run cleanup on the backup directory, erase all older than 180 days. + _cmdstr="find $_homedir/* -type d -mtime +180 2>/dev/null | xargs rm -rf ; $_cmdstr" + # Create our backup directory for overwritten cert files. + _cmdstr="mkdir -p $_backupdir ; $_cmdstr" + fi + _debug "Remote commands to execute: $_cmdstr" _info "Submitting sequence of commands to remote server by ssh" - ssh -T "$Le_Deploy_ssh_url" bash -c "'$_cmdstr'" + ssh -T "$Le_Deploy_ssh_user@$Le_Deploy_ssh_url" bash -c "'$_cmdstr'" return 0 } From 5d3de4b670fefbc4f0fc54b390e0c196ea8583a7 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 5 Feb 2017 14:39:25 -0500 Subject: [PATCH 03/35] Additional info messages for backup management --- deploy/sshdeploy.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index aa924136..e34371a1 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -178,6 +178,8 @@ sshdeploy_deploy() { _cmdstr="find $_homedir/* -type d -mtime +180 2>/dev/null | xargs rm -rf ; $_cmdstr" # Create our backup directory for overwritten cert files. _cmdstr="mkdir -p $_backupdir ; $_cmdstr" + _info "Backup of old certificate files will be placed in remote directory $_backupdir" + _info "Backup directories erased after 180 days." fi _debug "Remote commands to execute: $_cmdstr" From 62e7d904b40af35884bfb1dd59d9a0486c993207 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 5 Feb 2017 15:02:59 -0500 Subject: [PATCH 04/35] Travis errors --- deploy/sshdeploy.sh | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index e34371a1..949bc1d3 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -22,8 +22,6 @@ # export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" # export ACME_DEPLOY_SSH_SERVICE_START="" -. "$DOMAIN_CONF" - ######## Public functions ##################### #domain keyfile certfile cafile fullchain @@ -34,9 +32,12 @@ sshdeploy_deploy() { _cca="$4" _cfullchain="$5" _cmdstr="" - _homedir="~/.acme_ssh_deploy" + _homedir='~' + _homedir="$_homedir/.acme_ssh_deploy" _backupdir="$_homedir/certs-backup-$(date +%Y%m%d%H%M%S)" + . "$DOMAIN_CONF" + _debug _cdomain "$_cdomain" _debug _ckey "$_ckey" _debug _ccert "$_ccert" @@ -61,7 +62,7 @@ sshdeploy_deploy() { elif [ -z "$Le_Deploy_ssh_url" ]; then Le_Deploy_ssh_url="$_cdomain" fi - + _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_url" # SERVICE_STOP is optional. @@ -146,9 +147,9 @@ sshdeploy_deploy() { _savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd" fi if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then - if [ -n "$Le_Deploy_ssh_service_stop" ]; then - _cmdstr="$_cmdstr sleep 2 ;" - fi + if [ -n "$Le_Deploy_ssh_service_stop" ]; then + _cmdstr="$_cmdstr sleep 2 ;" + fi _cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd ;" _info "Will execute remote command $Le_Deploy_ssh_remote_cmd" fi @@ -162,9 +163,9 @@ sshdeploy_deploy() { _savedomainconf Le_Deploy_ssh_service_start "$Le_Deploy_ssh_service_start" fi if [ -n "$Le_Deploy_ssh_service_start" ]; then - if [ -n "$Le_Deploy_ssh_service_stop" ] || [ -n "$Le_Deploy_ssh_remote_cmd" ] ; then - _cmdstr="$_cmdstr sleep 2 ;" - fi + if [ -n "$Le_Deploy_ssh_service_stop" ] || [ -n "$Le_Deploy_ssh_remote_cmd" ] ; then + _cmdstr="$_cmdstr sleep 2 ;" + fi _cmdstr="$_cmdstr $Le_Deploy_ssh_service_start ;" _info "Will start remote service with command $Le_Deploy_ssh_remote_cmd" fi From ff60dc4d24b27998fe2e435c94135e1494dd2cc8 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 5 Feb 2017 15:12:23 -0500 Subject: [PATCH 05/35] More Travis issues !!! --- deploy/sshdeploy.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index 949bc1d3..672b25cd 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -36,8 +36,16 @@ sshdeploy_deploy() { _homedir="$_homedir/.acme_ssh_deploy" _backupdir="$_homedir/certs-backup-$(date +%Y%m%d%H%M%S)" + if [ -z "$DOMAIN_CONF" ]; then + DOMAIN_CONF="" + fi + if [ ! -f "$DOMAIN_CONF" ]; then + _err "$DOMAIN_CONF does not exist." + return 1 + fi + . "$DOMAIN_CONF" - + _debug _cdomain "$_cdomain" _debug _ckey "$_ckey" _debug _ccert "$_ccert" @@ -163,7 +171,7 @@ sshdeploy_deploy() { _savedomainconf Le_Deploy_ssh_service_start "$Le_Deploy_ssh_service_start" fi if [ -n "$Le_Deploy_ssh_service_start" ]; then - if [ -n "$Le_Deploy_ssh_service_stop" ] || [ -n "$Le_Deploy_ssh_remote_cmd" ] ; then + if [ -n "$Le_Deploy_ssh_service_stop" ] || [ -n "$Le_Deploy_ssh_remote_cmd" ]; then _cmdstr="$_cmdstr sleep 2 ;" fi _cmdstr="$_cmdstr $Le_Deploy_ssh_service_start ;" From 9ab6353d73c4ac747e1063ec8d2e40017222b6ba Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 5 Feb 2017 15:16:05 -0500 Subject: [PATCH 06/35] Trying again. --- deploy/sshdeploy.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index 672b25cd..63d72fb8 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -36,15 +36,9 @@ sshdeploy_deploy() { _homedir="$_homedir/.acme_ssh_deploy" _backupdir="$_homedir/certs-backup-$(date +%Y%m%d%H%M%S)" - if [ -z "$DOMAIN_CONF" ]; then - DOMAIN_CONF="" + if [ -f "$DOMAIN_CONF" ]; then + . "$DOMAIN_CONF" fi - if [ ! -f "$DOMAIN_CONF" ]; then - _err "$DOMAIN_CONF does not exist." - return 1 - fi - - . "$DOMAIN_CONF" _debug _cdomain "$_cdomain" _debug _ckey "$_ckey" From 6c1561f415c18d66f8d7294c479ef3c47a443702 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 5 Feb 2017 15:20:06 -0500 Subject: [PATCH 07/35] Grasping at straws now !! --- deploy/sshdeploy.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index 63d72fb8..39819ba9 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -37,6 +37,7 @@ sshdeploy_deploy() { _backupdir="$_homedir/certs-backup-$(date +%Y%m%d%H%M%S)" if [ -f "$DOMAIN_CONF" ]; then + # shellcheck disable=SC1090 . "$DOMAIN_CONF" fi From 3812b275e9995ada19604da863f2d2d6dd31d5d2 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 5 Feb 2017 15:26:55 -0500 Subject: [PATCH 08/35] Moving on to the next batch of travis errors. --- deploy/sshdeploy.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index 39819ba9..96eabc74 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -89,7 +89,7 @@ sshdeploy_deploy() { # backup file we are about to overwrite. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir ;" # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat $_ckey)\" > $Le_Deploy_ssh_keyfile ;" + _cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile ;" _info "will copy private key to remote file $Le_Deploy_ssh_keyfile" fi @@ -102,13 +102,13 @@ sshdeploy_deploy() { if [ -n "$Le_Deploy_ssh_certfile" ]; then if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then # if filename is same as that provided for private key then append. - _cmdstr="$_cmdstr echo \"$(cat $_ccert)\" >> $Le_Deploy_ssh_certfile ;" + _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" >> $Le_Deploy_ssh_certfile ;" _info "will append certificate to same file" else # backup file we are about to overwrite. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir ;" # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat $_ccert)\" > $Le_Deploy_ssh_certfile ;" + _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" > $Le_Deploy_ssh_certfile ;" _info "will copy certificate to remote file $Le_Deploy_ssh_certfile" fi fi @@ -123,7 +123,7 @@ sshdeploy_deploy() { # backup file we are about to overwrite. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir ;" # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat $_cca)\" > $Le_Deploy_ssh_cafile ;" + _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" > $Le_Deploy_ssh_cafile ;" _info "will copy CA file to remote file $Le_Deploy_ssh_cafile" fi @@ -137,7 +137,7 @@ sshdeploy_deploy() { # backup file we are about to overwrite. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir ;" # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat $_cfullchain)\" > $Le_Deploy_ssh_fullchain ;" + _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" > $Le_Deploy_ssh_fullchain ;" _info "will copy full chain to remote file $Le_Deploy_ssh_fullchain" fi @@ -188,6 +188,8 @@ sshdeploy_deploy() { _debug "Remote commands to execute: $_cmdstr" _info "Submitting sequence of commands to remote server by ssh" + # quotations in bash cmd below intended. Squash travis spellcheck error + # shellcheck disable=SC2029 ssh -T "$Le_Deploy_ssh_user@$Le_Deploy_ssh_url" bash -c "'$_cmdstr'" return 0 From 9507b121acfe49b922683809d853f27c2f229ecd Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 5 Feb 2017 15:34:03 -0500 Subject: [PATCH 09/35] More selective pruning of certificate backup directories. --- deploy/sshdeploy.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index 96eabc74..55d248ca 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -33,8 +33,8 @@ sshdeploy_deploy() { _cfullchain="$5" _cmdstr="" _homedir='~' - _homedir="$_homedir/.acme_ssh_deploy" - _backupdir="$_homedir/certs-backup-$(date +%Y%m%d%H%M%S)" + _backupprefix="$_homedir/.acme_ssh_deploy/certs-backup" + _backupdir="$_backupprefix-$(date +%Y%m%d%H%M%S)" if [ -f "$DOMAIN_CONF" ]; then # shellcheck disable=SC1090 @@ -179,7 +179,7 @@ sshdeploy_deploy() { else # something to execute. # run cleanup on the backup directory, erase all older than 180 days. - _cmdstr="find $_homedir/* -type d -mtime +180 2>/dev/null | xargs rm -rf ; $_cmdstr" + _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf ; $_cmdstr" # Create our backup directory for overwritten cert files. _cmdstr="mkdir -p $_backupdir ; $_cmdstr" _info "Backup of old certificate files will be placed in remote directory $_backupdir" From f158caa2ebba77a343ca7badddba8395e822a609 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Mon, 6 Feb 2017 21:49:20 -0500 Subject: [PATCH 10/35] Updates from code review --- deploy/sshdeploy.sh | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index 55d248ca..e7ca78a8 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -3,7 +3,7 @@ # Script to deploy certificates to remote server by SSH # Note that SSH must be able to login to remote host without a password... # SSH Keys must have been exchanged with the remote host. Validate and -# test that you can login to USER@URL from the host running acme.sh before +# test that you can login to USER@SERVER from the host running acme.sh before # using this script. # # The following variables exported from environment will be used. @@ -13,7 +13,8 @@ # # The following examples are for QNAP NAS running QTS 4.2 # export ACME_DEPLOY_SSH_USER="admin" -# export ACME_DEPLOY_SSH_URL="qnap" +# export ACME_DEPLOY_SSH_SERVER="qnap" +# export ACME_DEPLOY_SSH_PORT="22" # export ACME_DEPLOY_SSH_SERVICE_STOP="" # export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" # export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" @@ -34,7 +35,7 @@ sshdeploy_deploy() { _cmdstr="" _homedir='~' _backupprefix="$_homedir/.acme_ssh_deploy/certs-backup" - _backupdir="$_backupprefix-$(date +%Y%m%d%H%M%S)" + _backupdir="$_backupprefix-$(_utc_date | tr ' ' '-')" if [ -f "$DOMAIN_CONF" ]; then # shellcheck disable=SC1090 @@ -58,15 +59,23 @@ sshdeploy_deploy() { _savedomainconf Le_Deploy_ssh_user "$Le_Deploy_ssh_user" fi - # URL is optional. If not provided then use _cdomain - if [ -n "$ACME_DEPLOY_SSH_URL" ]; then - Le_Deploy_ssh_url="$ACME_DEPLOY_SSH_URL" - _savedomainconf Le_Deploy_ssh_url "$Le_Deploy_ssh_url" - elif [ -z "$Le_Deploy_ssh_url" ]; then - Le_Deploy_ssh_url="$_cdomain" + # SERVER is optional. If not provided then use _cdomain + if [ -n "$ACME_DEPLOY_SSH_SERVER" ]; then + Le_Deploy_ssh_server="$ACME_DEPLOY_SSH_SERVER" + _savedomainconf Le_Deploy_ssh_server "$Le_Deploy_ssh_server" + elif [ -z "$Le_Deploy_ssh_server" ]; then + Le_Deploy_ssh_server="$_cdomain" fi - _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_url" + # PORT is optional. If not provided then use port 22 + if [ -n "$ACME_DEPLOY_SSH_PORT" ]; then + Le_Deploy_ssh_port="$ACME_DEPLOY_SSH_PORT" + _savedomainconf Le_Deploy_ssh_port "$Le_Deploy_ssh_port" + elif [ -z "$Le_Deploy_ssh_port" ]; then + Le_Deploy_ssh_port="22" + fi + + _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server on port $Le_Deploy_ssh_port" # SERVICE_STOP is optional. # If provided then this command will be executed on remote host. @@ -190,7 +199,7 @@ sshdeploy_deploy() { _info "Submitting sequence of commands to remote server by ssh" # quotations in bash cmd below intended. Squash travis spellcheck error # shellcheck disable=SC2029 - ssh -T "$Le_Deploy_ssh_user@$Le_Deploy_ssh_url" bash -c "'$_cmdstr'" + ssh -T -p "$Le_Deploy_ssh_port" "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmdstr'" - return 0 + return $? } From 3be5a68e12bd366ab80c93c8d8f353d1ebda268a Mon Sep 17 00:00:00 2001 From: David Kerr Date: Tue, 7 Feb 2017 13:05:22 -0500 Subject: [PATCH 11/35] Rename sshdeploy.sh to ssh.sh --- deploy/{sshdeploy.sh => ssh.sh} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename deploy/{sshdeploy.sh => ssh.sh} (99%) diff --git a/deploy/sshdeploy.sh b/deploy/ssh.sh similarity index 99% rename from deploy/sshdeploy.sh rename to deploy/ssh.sh index e7ca78a8..c3b89448 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/ssh.sh @@ -26,7 +26,7 @@ ######## Public functions ##################### #domain keyfile certfile cafile fullchain -sshdeploy_deploy() { +ssh_deploy() { _cdomain="$1" _ckey="$2" _ccert="$3" From 3365df77789b97c8e2b54eae02afd581d5714636 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Wed, 8 Feb 2017 10:15:39 -0500 Subject: [PATCH 12/35] Make certificate domain name part of the backup directory name. --- deploy/ssh.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/ssh.sh b/deploy/ssh.sh index c3b89448..6d628436 100644 --- a/deploy/ssh.sh +++ b/deploy/ssh.sh @@ -34,7 +34,7 @@ ssh_deploy() { _cfullchain="$5" _cmdstr="" _homedir='~' - _backupprefix="$_homedir/.acme_ssh_deploy/certs-backup" + _backupprefix="$_homedir/.acme_ssh_deploy/$_cdomain-backup" _backupdir="$_backupprefix-$(_utc_date | tr ' ' '-')" if [ -f "$DOMAIN_CONF" ]; then From 1a5989350fad48a824dda39c7d83703d6ae490f1 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Wed, 8 Feb 2017 21:02:00 -0500 Subject: [PATCH 13/35] Some documentation in README --- deploy/README.md | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/deploy/README.md b/deploy/README.md index 580eaac8..8096073d 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -1 +1,92 @@ #Using deploy api + +#Using the ssh deploy plugin + +The ssh deploy plugin allows you to deploy certificates to a remote host +using SSH command to connect to the remote server. The ssh plugin is invoked +with the following command... + +```bash +acme.sh --deploy -d example.com --deploy-hook ssh +``` +Prior to running this for the first time you must tell the plugin where +and how to deploy the certificates. This is done by exporting the following +environment variables. + +This is not required for subsequent runs as the +values are stored by acme.sh in the domain configuration files. + +Required... +```bash +export ACME_DEPLOY_SSH_USER="admin" +``` +Optional... +```bash +export ACME_DEPLOY_SSH_SERVER="qnap" +export ACME_DEPLOY_SSH_PORT="22" +export ACME_DEPLOY_SSH_SERVICE_STOP="" +export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" +export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" +export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" +export ACME_DEPLOY_SSH_FULLCHAIN="" +export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" +export ACME_DEPLOY_SSH_SERVICE_START="" +``` +The values used above are illustrative only and represent those used +to deploy certificates to a QNAP NAS device running QTS 4.2 + +###ACME_DEPLOY_SSH_USER +Username at the remote host that SSH will login with. Note that +SSH must be able to login to remote host without a password... SSH Keys +must have been exchanged with the remote host. Validate and test that you +can login to USER@URL from the host running acme.sh before using this script. + +The USER@URL at the remote server must also have has permissions to write to +the target location of the certificate files and to execute any commands +(e.g. to stop/start services). + +###ACME_DEPLOY_SSH_SERVER +URL or IP Address of the remote server. If not provided then the domain +name provided on the acme.sh --deploy command line is used. + +###ACME_DEPLOY_SSH_PORT +Port number that SSH will attempt to connect to at the remote server. If +not specified then defaults to 22. + +###ACME_DEPLOY_SSH_SERVICE_STOP +Command to execute on the remote server prior to copying any certificates. This +would typically be used to stop the service for which the certificates are +being deployed. + +###ACME_DEPLOY_SSH_KEYFILE +###ACME_DEPLOY_SSH_CERTFILE +###ACME_DEPLOY_SSH_CAFILE +###ACME_DEPLOY_SSH_FULLCHAIN +These four variables identify the target location for the respective +certificates issued by LetsEncrypt. Directory path and filenames are those +on the remote server and the SSH user must have write permissions. + +###ACME_DEPLOY_SSH_REMOTE_CMD +Command to execute on the remote server after copying any certificates. This +could be any additional command required prior to starting the service again, +or could be a all-inclusive restart (stop and start of service). If +ACME_DEPLOY_SSH_SERVICE_STOP value was provided then a 2 second sleep is +inserted prior to calling this command to allow the system to stabalize. + +###ACME_DEPLOY_SSH_SERVICE_START +Command to execute on the remote server after copying any certificates. This +would typically be used to stop the service for which the certificates are +being deployed. If ACME_DEPLOY_SSH_SERVICE_STOP or ACME_DEPLOY_SSH_REMOTE_CMD +value were provided then a 2 second sleep is inserted prior to calling +this command to allow the system to stabalize. + +##Backups +Before writing a certificate file to the remote server the existing +certificate will be copied to a backup directory on the remote server. +These are placed in a hidden directory in the home directory of the SSH +user +```bash +~/.acme_ssh_deploy/[domain name]-backup-[timestamp] +``` +Any backups older than 180 days will be deleted when new certificates +are deployed. From e3feac3fd87db1bbd0838c3e851c8724d17a2fe1 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Wed, 8 Feb 2017 21:13:00 -0500 Subject: [PATCH 14/35] Documentation updates --- deploy/README.md | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 8096073d..2e490a17 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -11,9 +11,7 @@ acme.sh --deploy -d example.com --deploy-hook ssh ``` Prior to running this for the first time you must tell the plugin where and how to deploy the certificates. This is done by exporting the following -environment variables. - -This is not required for subsequent runs as the +environment variables. This is not required for subsequent runs as the values are stored by acme.sh in the domain configuration files. Required... @@ -32,8 +30,8 @@ export ACME_DEPLOY_SSH_FULLCHAIN="" export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" export ACME_DEPLOY_SSH_SERVICE_START="" ``` -The values used above are illustrative only and represent those used -to deploy certificates to a QNAP NAS device running QTS 4.2 +The values used above are illustrative only and represent those that could +be used to deploy certificates to a QNAP NAS device running QTS 4.2 ###ACME_DEPLOY_SSH_USER Username at the remote host that SSH will login with. Note that @@ -44,40 +42,37 @@ can login to USER@URL from the host running acme.sh before using this script. The USER@URL at the remote server must also have has permissions to write to the target location of the certificate files and to execute any commands (e.g. to stop/start services). - ###ACME_DEPLOY_SSH_SERVER URL or IP Address of the remote server. If not provided then the domain name provided on the acme.sh --deploy command line is used. - ###ACME_DEPLOY_SSH_PORT Port number that SSH will attempt to connect to at the remote server. If -not specified then defaults to 22. - +not provided then defaults to 22. ###ACME_DEPLOY_SSH_SERVICE_STOP Command to execute on the remote server prior to copying any certificates. This would typically be used to stop the service for which the certificates are being deployed. - ###ACME_DEPLOY_SSH_KEYFILE +Target filename for the private key issued by LetsEncrypt. ###ACME_DEPLOY_SSH_CERTFILE +Target filename for the certificate issued by LetsEncrypt. If this filename +is the same as that provided for ACME_DEPLOY_SSH_KEYFILE then this certificate +is appended to the same file as the private key. ###ACME_DEPLOY_SSH_CAFILE +Target filename for the CA intermediate certificate issued by LetsEncrypt. ###ACME_DEPLOY_SSH_FULLCHAIN -These four variables identify the target location for the respective -certificates issued by LetsEncrypt. Directory path and filenames are those -on the remote server and the SSH user must have write permissions. - +Target filename for the fullchain certificate issued by LetsEncrypt. ###ACME_DEPLOY_SSH_REMOTE_CMD Command to execute on the remote server after copying any certificates. This could be any additional command required prior to starting the service again, or could be a all-inclusive restart (stop and start of service). If ACME_DEPLOY_SSH_SERVICE_STOP value was provided then a 2 second sleep is inserted prior to calling this command to allow the system to stabalize. - ###ACME_DEPLOY_SSH_SERVICE_START Command to execute on the remote server after copying any certificates. This would typically be used to stop the service for which the certificates are being deployed. If ACME_DEPLOY_SSH_SERVICE_STOP or ACME_DEPLOY_SSH_REMOTE_CMD -value were provided then a 2 second sleep is inserted prior to calling +values were provided then a 2 second sleep is inserted prior to calling this command to allow the system to stabalize. ##Backups From 68d708e56da391e86bd13ea8900d015048d7f279 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sat, 11 Feb 2017 16:11:27 -0500 Subject: [PATCH 15/35] Reduce and simplify number of exported variables. Also allow any cert file to append to previous file. --- deploy/README.md | 33 ++++++--------- deploy/ssh.sh | 106 ++++++++++++++++++++--------------------------- 2 files changed, 58 insertions(+), 81 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 15b7ae1d..95f31d45 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -42,15 +42,13 @@ export ACME_DEPLOY_SSH_USER="admin" ``` Optional... ```bash +export ACME_DEPLOY_SSH_CMD="" export ACME_DEPLOY_SSH_SERVER="qnap" -export ACME_DEPLOY_SSH_PORT="22" -export ACME_DEPLOY_SSH_SERVICE_STOP="" export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" export ACME_DEPLOY_SSH_FULLCHAIN="" export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" -export ACME_DEPLOY_SSH_SERVICE_START="" ``` The values used above are illustrative only and represent those that could be used to deploy certificates to a QNAP NAS device running QTS 4.2 @@ -64,16 +62,13 @@ can login to USER@URL from the host running acme.sh before using this script. The USER@URL at the remote server must also have has permissions to write to the target location of the certificate files and to execute any commands (e.g. to stop/start services). +###ACME_DEPLOY_SSH_CMD +You can customize the ssh command used to connect to the remote host. For example +if you need to connect to a specific port at the remote server you can set this +to, for example, "ssh -p 22" ###ACME_DEPLOY_SSH_SERVER URL or IP Address of the remote server. If not provided then the domain name provided on the acme.sh --deploy command line is used. -###ACME_DEPLOY_SSH_PORT -Port number that SSH will attempt to connect to at the remote server. If -not provided then defaults to 22. -###ACME_DEPLOY_SSH_SERVICE_STOP -Command to execute on the remote server prior to copying any certificates. This -would typically be used to stop the service for which the certificates are -being deployed. ###ACME_DEPLOY_SSH_KEYFILE Target filename for the private key issued by LetsEncrypt. ###ACME_DEPLOY_SSH_CERTFILE @@ -82,22 +77,18 @@ is the same as that provided for ACME_DEPLOY_SSH_KEYFILE then this certificate is appended to the same file as the private key. ###ACME_DEPLOY_SSH_CAFILE Target filename for the CA intermediate certificate issued by LetsEncrypt. +If this is the same as a previous filename then it is appended to the same +file ###ACME_DEPLOY_SSH_FULLCHAIN Target filename for the fullchain certificate issued by LetsEncrypt. +If this is the same as a previous filename then it is appended to the same +file ###ACME_DEPLOY_SSH_REMOTE_CMD Command to execute on the remote server after copying any certificates. This -could be any additional command required prior to starting the service again, -or could be a all-inclusive restart (stop and start of service). If -ACME_DEPLOY_SSH_SERVICE_STOP value was provided then a 2 second sleep is -inserted prior to calling this command to allow the system to stabalize. -###ACME_DEPLOY_SSH_SERVICE_START -Command to execute on the remote server after copying any certificates. This -would typically be used to stop the service for which the certificates are -being deployed. If ACME_DEPLOY_SSH_SERVICE_STOP or ACME_DEPLOY_SSH_REMOTE_CMD -values were provided then a 2 second sleep is inserted prior to calling -this command to allow the system to stabalize. +could be any additional command required for example to stop and restart +the service. -##Backups +###Backups Before writing a certificate file to the remote server the existing certificate will be copied to a backup directory on the remote server. These are placed in a hidden directory in the home directory of the SSH diff --git a/deploy/ssh.sh b/deploy/ssh.sh index 6d628436..0adeba89 100644 --- a/deploy/ssh.sh +++ b/deploy/ssh.sh @@ -12,16 +12,14 @@ # Only a username is required. All others are optional. # # The following examples are for QNAP NAS running QTS 4.2 +# export ACME_DEPLOY_SSH_CMD="" # export ACME_DEPLOY_SSH_USER="admin" # export ACME_DEPLOY_SSH_SERVER="qnap" -# export ACME_DEPLOY_SSH_PORT="22" -# export ACME_DEPLOY_SSH_SERVICE_STOP="" # export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" # export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" # export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" # export ACME_DEPLOY_SSH_FULLCHAIN="" -# export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" -# export ACME_DEPLOY_SSH_SERVICE_START="" +# export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" ######## Public functions ##################### @@ -67,26 +65,15 @@ ssh_deploy() { Le_Deploy_ssh_server="$_cdomain" fi - # PORT is optional. If not provided then use port 22 - if [ -n "$ACME_DEPLOY_SSH_PORT" ]; then - Le_Deploy_ssh_port="$ACME_DEPLOY_SSH_PORT" - _savedomainconf Le_Deploy_ssh_port "$Le_Deploy_ssh_port" - elif [ -z "$Le_Deploy_ssh_port" ]; then - Le_Deploy_ssh_port="22" + # CMD is optional. If not provided then use ssh + if [ -n "$ACME_DEPLOY_SSH_CMD" ]; then + Le_Deploy_ssh_cmd="$ACME_DEPLOY_SSH_CMD" + _savedomainconf Le_Deploy_ssh_cmd "$Le_Deploy_ssh_cmd" + elif [ -z "$Le_Deploy_ssh_cmd" ]; then + Le_Deploy_ssh_cmd="ssh" fi - _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server on port $Le_Deploy_ssh_port" - - # SERVICE_STOP is optional. - # If provided then this command will be executed on remote host. - if [ -n "$ACME_DEPLOY_SSH_SERVICE_STOP" ]; then - Le_Deploy_ssh_service_stop="$ACME_DEPLOY_SSH_SERVICE_STOP" - _savedomainconf Le_Deploy_ssh_service_stop "$Le_Deploy_ssh_service_stop" - fi - if [ -n "$Le_Deploy_ssh_service_stop" ]; then - _cmdstr="$_cmdstr $Le_Deploy_ssh_service_stop ;" - _info "Will stop remote service with command $Le_Deploy_ssh_service_stop" - fi + _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server" # KEYFILE is optional. # If provided then private key will be copied to provided filename. @@ -110,78 +97,72 @@ ssh_deploy() { fi if [ -n "$Le_Deploy_ssh_certfile" ]; then if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then - # if filename is same as that provided for private key then append. - _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" >> $Le_Deploy_ssh_certfile ;" - _info "will append certificate to same file" + # if filename is same as previous file then append. + _pipe=">>" else # backup file we are about to overwrite. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir ;" - # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" > $Le_Deploy_ssh_certfile ;" - _info "will copy certificate to remote file $Le_Deploy_ssh_certfile" + _pipe=">" fi + # copy new certificate into file. + _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile ;" + _info "will copy certificate to remote file $Le_Deploy_ssh_certfile" fi # CAFILE is optional. - # If provided then CA intermediate certificate will be copied to provided filename. + # If provided then CA intermediate certificate will be copied or appended to provided filename. if [ -n "$ACME_DEPLOY_SSH_CAFILE" ]; then Le_Deploy_ssh_cafile="$ACME_DEPLOY_SSH_CAFILE" _savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile" fi if [ -n "$Le_Deploy_ssh_cafile" ]; then - # backup file we are about to overwrite. - _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir ;" + if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] || + [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then + # if filename is same as previous file then append. + _pipe=">>" + else + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir ;" + _pipe=">" + fi # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" > $Le_Deploy_ssh_cafile ;" + _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile ;" _info "will copy CA file to remote file $Le_Deploy_ssh_cafile" fi # FULLCHAIN is optional. - # If provided then fullchain certificate will be copied to provided filename. + # If provided then fullchain certificate will be copied or appended to provided filename. if [ -n "$ACME_DEPLOY_SSH_FULLCHAIN" ]; then Le_Deploy_ssh_fullchain="$ACME_DEPLOY_SSH_FULLCHAIN" _savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain" fi if [ -n "$Le_Deploy_ssh_fullchain" ]; then - # backup file we are about to overwrite. - _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir ;" + if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] || + [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] || + [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then + # if filename is same as previous file then append. + _pipe=">>" + else + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir ;" + _pipe=">" + fi # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" > $Le_Deploy_ssh_fullchain ;" - _info "will copy full chain to remote file $Le_Deploy_ssh_fullchain" + _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain ;" + _info "will copy fullchain to remote file $Le_Deploy_ssh_fullchain" fi # REMOTE_CMD is optional. # If provided then this command will be executed on remote host. - # A 2 second delay is inserted to allow system to stabalize after - # executing a service stop. if [ -n "$ACME_DEPLOY_SSH_REMOTE_CMD" ]; then Le_Deploy_ssh_remote_cmd="$ACME_DEPLOY_SSH_REMOTE_CMD" _savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd" fi if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then - if [ -n "$Le_Deploy_ssh_service_stop" ]; then - _cmdstr="$_cmdstr sleep 2 ;" - fi _cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd ;" _info "Will execute remote command $Le_Deploy_ssh_remote_cmd" fi - # SERVICE_START is optional. - # If provided then this command will be executed on remote host. - # A 2 second delay is inserted to allow system to stabalize after - # executing a service stop or previous command. - if [ -n "$ACME_DEPLOY_SSH_SERVICE_START" ]; then - Le_Deploy_ssh_service_start="$ACME_DEPLOY_SSH_SERVICE_START" - _savedomainconf Le_Deploy_ssh_service_start "$Le_Deploy_ssh_service_start" - fi - if [ -n "$Le_Deploy_ssh_service_start" ]; then - if [ -n "$Le_Deploy_ssh_service_stop" ] || [ -n "$Le_Deploy_ssh_remote_cmd" ]; then - _cmdstr="$_cmdstr sleep 2 ;" - fi - _cmdstr="$_cmdstr $Le_Deploy_ssh_service_start ;" - _info "Will start remote service with command $Le_Deploy_ssh_remote_cmd" - fi - if [ -z "$_cmdstr" ]; then _err "No remote commands to excute. Failed to deploy certificates to remote server" return 1 @@ -199,7 +180,12 @@ ssh_deploy() { _info "Submitting sequence of commands to remote server by ssh" # quotations in bash cmd below intended. Squash travis spellcheck error # shellcheck disable=SC2029 - ssh -T -p "$Le_Deploy_ssh_port" "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmdstr'" + $Le_Deploy_ssh_cmd -T "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmdstr'" + _ret="$?" - return $? + if [ "$_ret" != "0" ]; then + _err "Error code $_ret returned from $Le_Deploy_ssh_cmd" + fi + + return $_ret } From a4b2cebef61e6add91c423aa146ab7313d7ab740 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sat, 11 Feb 2017 16:42:44 -0500 Subject: [PATCH 16/35] Make backup of certs on remote server optional. Defaults to yes. --- deploy/README.md | 6 +++--- deploy/ssh.sh | 50 +++++++++++++++++++++++++++++------------------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 95f31d45..01705838 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -49,6 +49,7 @@ export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" export ACME_DEPLOY_SSH_FULLCHAIN="" export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" +export ACME_DEPLOY_SSH_BACKUP="" ``` The values used above are illustrative only and represent those that could be used to deploy certificates to a QNAP NAS device running QTS 4.2 @@ -87,8 +88,7 @@ file Command to execute on the remote server after copying any certificates. This could be any additional command required for example to stop and restart the service. - -###Backups +###ACME_DEPLOY_SSH_BACKUP Before writing a certificate file to the remote server the existing certificate will be copied to a backup directory on the remote server. These are placed in a hidden directory in the home directory of the SSH @@ -97,4 +97,4 @@ user ~/.acme_ssh_deploy/[domain name]-backup-[timestamp] ``` Any backups older than 180 days will be deleted when new certificates -are deployed. +are deployed. This defaults to "yes" set to "no" to disable backup. diff --git a/deploy/ssh.sh b/deploy/ssh.sh index 0adeba89..26963ed5 100644 --- a/deploy/ssh.sh +++ b/deploy/ssh.sh @@ -12,15 +12,16 @@ # Only a username is required. All others are optional. # # The following examples are for QNAP NAS running QTS 4.2 -# export ACME_DEPLOY_SSH_CMD="" -# export ACME_DEPLOY_SSH_USER="admin" -# export ACME_DEPLOY_SSH_SERVER="qnap" +# export ACME_DEPLOY_SSH_CMD="" # defaults to ssh +# export ACME_DEPLOY_SSH_USER="admin" # required +# export ACME_DEPLOY_SSH_SERVER="qnap" # defaults to domain name # export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" # export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" # export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" # export ACME_DEPLOY_SSH_FULLCHAIN="" -# export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" - +# export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" +# export ACME_DEPLOY_SSH_BACKUP="" # yes or no, default to yes +# ######## Public functions ##################### #domain keyfile certfile cafile fullchain @@ -73,6 +74,14 @@ ssh_deploy() { Le_Deploy_ssh_cmd="ssh" fi + # BACKUP is optional. If not provided then default to yes + if [ "$ACME_DEPLOY_SSH_BACKUP" = "no"]; then + Le_Deploy_ssh_backup="no" + elif [ -z "$Le_Deploy_ssh_backup" ]; then + Le_Deploy_ssh_backup="yes" + fi + _savedomainconf Le_Deploy_ssh_backup "$Le_Deploy_ssh_backup" + _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server" # KEYFILE is optional. @@ -82,8 +91,10 @@ ssh_deploy() { _savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile" fi if [ -n "$Le_Deploy_ssh_keyfile" ]; then - # backup file we are about to overwrite. - _cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir ;" + if [ "$Le_Deploy_ssh_backup" = "yes" ]; then + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir ;" + fi # copy new certificate into file. _cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile ;" _info "will copy private key to remote file $Le_Deploy_ssh_keyfile" @@ -96,13 +107,13 @@ ssh_deploy() { _savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile" fi if [ -n "$Le_Deploy_ssh_certfile" ]; then + _pipe=">" if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then # if filename is same as previous file then append. _pipe=">>" - else + elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then # backup file we are about to overwrite. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir ;" - _pipe=">" fi # copy new certificate into file. _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile ;" @@ -116,14 +127,14 @@ ssh_deploy() { _savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile" fi if [ -n "$Le_Deploy_ssh_cafile" ]; then - if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] || - [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then + _pipe=">" + if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] \ + || [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then # if filename is same as previous file then append. _pipe=">>" - else + elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then # backup file we are about to overwrite. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir ;" - _pipe=">" fi # copy new certificate into file. _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile ;" @@ -137,15 +148,15 @@ ssh_deploy() { _savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain" fi if [ -n "$Le_Deploy_ssh_fullchain" ]; then - if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] || - [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] || - [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then + _pipe=">" + if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] \ + || [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] \ + || [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then # if filename is same as previous file then append. _pipe=">>" - else + elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then # backup file we are about to overwrite. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir ;" - _pipe=">" fi # copy new certificate into file. _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain ;" @@ -166,8 +177,7 @@ ssh_deploy() { if [ -z "$_cmdstr" ]; then _err "No remote commands to excute. Failed to deploy certificates to remote server" return 1 - else - # something to execute. + elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then # run cleanup on the backup directory, erase all older than 180 days. _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf ; $_cmdstr" # Create our backup directory for overwritten cert files. From 18a90734d94f77ab90e45aa6e32bf065567e2cc2 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sat, 11 Feb 2017 17:55:05 -0500 Subject: [PATCH 17/35] Alternate backup cleanup after 180 days method. --- deploy/ssh.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/deploy/ssh.sh b/deploy/ssh.sh index 26963ed5..eb3690a6 100644 --- a/deploy/ssh.sh +++ b/deploy/ssh.sh @@ -75,7 +75,7 @@ ssh_deploy() { fi # BACKUP is optional. If not provided then default to yes - if [ "$ACME_DEPLOY_SSH_BACKUP" = "no"]; then + if [ "$ACME_DEPLOY_SSH_BACKUP" = "no" ]; then Le_Deploy_ssh_backup="no" elif [ -z "$Le_Deploy_ssh_backup" ]; then Le_Deploy_ssh_backup="yes" @@ -178,8 +178,12 @@ ssh_deploy() { _err "No remote commands to excute. Failed to deploy certificates to remote server" return 1 elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then - # run cleanup on the backup directory, erase all older than 180 days. - _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf ; $_cmdstr" + # run cleanup on the backup directory, erase all older + # than 180 days (15552000 seconds). + _cmdstr="{ now=\"\$(date -u +%s)\"; for fn in $_backupprefix*; \ +do if [ -d \"\$fn\" ] && [ \"\$(expr \$now - \$(date -ur \$fn +%s) )\" -ge \"15552000\" ]; \ +then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; done; }; $_cmdstr" + # Alternate version of above... _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf ; $_cmdstr" # Create our backup directory for overwritten cert files. _cmdstr="mkdir -p $_backupdir ; $_cmdstr" _info "Backup of old certificate files will be placed in remote directory $_backupdir" From 3a77a6eded17122416ecec87babe59b8492ef927 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 12 Feb 2017 11:17:23 -0500 Subject: [PATCH 18/35] cleanup documentation and suppress some remote messages. --- deploy/README.md | 104 ++++++++++++++++++++++++++++++++++------------- deploy/ssh.sh | 22 +++++----- 2 files changed, 87 insertions(+), 39 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 01705838..8f386056 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -38,23 +38,21 @@ values are stored by acme.sh in the domain configuration files. Required... ```bash -export ACME_DEPLOY_SSH_USER="admin" +export ACME_DEPLOY_SSH_USER=username ``` Optional... ```bash -export ACME_DEPLOY_SSH_CMD="" -export ACME_DEPLOY_SSH_SERVER="qnap" -export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" -export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" -export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" -export ACME_DEPLOY_SSH_FULLCHAIN="" -export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" -export ACME_DEPLOY_SSH_BACKUP="" +export ACME_DEPLOY_SSH_CMD=custom ssh command +export ACME_DEPLOY_SSH_SERVER=url or ip address of remote host +export ACME_DEPLOY_SSH_KEYFILE=filename for private key +export ACME_DEPLOY_SSH_CERTFILE=filename for certificate file +export ACME_DEPLOY_SSH_CAFILE=filename for intermediate CA file +export ACME_DEPLOY_SSH_FULLCHAIN=filename forfullchain file +export ACME_DEPLOY_SSH_REMOTE_CMD=command to execute on remote host +export ACME_DEPLOY_SSH_BACKUP=yes or no ``` -The values used above are illustrative only and represent those that could -be used to deploy certificates to a QNAP NAS device running QTS 4.2 -###ACME_DEPLOY_SSH_USER +**ACME_DEPLOY_SSH_USER** Username at the remote host that SSH will login with. Note that SSH must be able to login to remote host without a password... SSH Keys must have been exchanged with the remote host. Validate and test that you @@ -63,32 +61,42 @@ can login to USER@URL from the host running acme.sh before using this script. The USER@URL at the remote server must also have has permissions to write to the target location of the certificate files and to execute any commands (e.g. to stop/start services). -###ACME_DEPLOY_SSH_CMD + +**ACME_DEPLOY_SSH_CMD** You can customize the ssh command used to connect to the remote host. For example if you need to connect to a specific port at the remote server you can set this -to, for example, "ssh -p 22" -###ACME_DEPLOY_SSH_SERVER +to, for example, "ssh -p 22" or to use `sshpass` to provide password inline +instead of exchanging ssh keys (this is not recommended, using keys is +more secure). + +**ACME_DEPLOY_SSH_SERVER** URL or IP Address of the remote server. If not provided then the domain name provided on the acme.sh --deploy command line is used. -###ACME_DEPLOY_SSH_KEYFILE + +**ACME_DEPLOY_SSH_KEYFILE** Target filename for the private key issued by LetsEncrypt. -###ACME_DEPLOY_SSH_CERTFILE -Target filename for the certificate issued by LetsEncrypt. If this filename -is the same as that provided for ACME_DEPLOY_SSH_KEYFILE then this certificate -is appended to the same file as the private key. -###ACME_DEPLOY_SSH_CAFILE + +**ACME_DEPLOY_SSH_CERTFILE** +Target filename for the certificate issued by LetsEncrypt. +If this is the same as the previous filename (for keyfile) then it is +appended to the same file. + +**ACME_DEPLOY_SSH_CAFILE** Target filename for the CA intermediate certificate issued by LetsEncrypt. -If this is the same as a previous filename then it is appended to the same -file -###ACME_DEPLOY_SSH_FULLCHAIN +If this is the same as a previous filename (for keyfile or certfile) then +it is appended to the same file. + +**ACME_DEPLOY_SSH_FULLCHAIN** Target filename for the fullchain certificate issued by LetsEncrypt. -If this is the same as a previous filename then it is appended to the same -file -###ACME_DEPLOY_SSH_REMOTE_CMD +If this is the same as a previous filename (for keyfile, certfile or +cafile) then it is appended to the same file. + +**ACME_DEPLOY_SSH_REMOTE_CMD** Command to execute on the remote server after copying any certificates. This could be any additional command required for example to stop and restart the service. -###ACME_DEPLOY_SSH_BACKUP + +**ACME_DEPLOY_SSH_BACKUP** Before writing a certificate file to the remote server the existing certificate will be copied to a backup directory on the remote server. These are placed in a hidden directory in the home directory of the SSH @@ -98,3 +106,43 @@ user ``` Any backups older than 180 days will be deleted when new certificates are deployed. This defaults to "yes" set to "no" to disable backup. + + +###Eamples using SSH deploy +The following example illustrates deploying certifcates to a QNAP NAS +running QTS 4.2 + +```bash +export ACME_DEPLOY_SSH_USER="admin" +export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" +export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" +export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" +export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" + +acme.sh --deploy -d qnap.example.com --deploy-hook ssh +``` + +The next example illustates deploying certificates to a Unifi +Contolller (tested with version 5.4.11). + +```bash +export ACME_DEPLOY_SSH_USER="root" +export ACME_DEPLOY_SSH_KEYFILE="/var/lib/unifi/unifi.example.com.key" +export ACME_DEPLOY_SSH_FULLCHAIN="/var/lib/unifi/unifi.example.com.cer" +export ACME_DEPLOY_SSH_REMOTE_CMD="openssl pkcs12 -export \ + -inkey /var/lib/unifi/unifi.example.com.key \ + -in /var/lib/unifi/unifi.example.com.cer \ + -out /var/lib/unifi/unifi.example.com.p12 \ + -name ubnt -password pass:temppass \ + && keytool -importkeystore -deststorepass aircontrolenterprise \ + -destkeypass aircontrolenterprise -destkeystore /var/lib/unifi/keystore \ + -srckeystore /var/lib/unifi/unifi.example.com.p12 \ + -srcstoretype PKCS12 -srcstorepass temppass -alias ubnt -noprompt \ + && service unifi restart" + +acme.sh --deploy -d qnap.example.com --deploy-hook ssh +``` +Note how in this exmple we execute several commands on the remote host +after the certificate files have been copied... to generate a pkcs12 file +compatible with Unifi, to import it into the Unifi keystore and then finaly +to restart the service. diff --git a/deploy/ssh.sh b/deploy/ssh.sh index eb3690a6..a8ed6a10 100644 --- a/deploy/ssh.sh +++ b/deploy/ssh.sh @@ -93,10 +93,10 @@ ssh_deploy() { if [ -n "$Le_Deploy_ssh_keyfile" ]; then if [ "$Le_Deploy_ssh_backup" = "yes" ]; then # backup file we are about to overwrite. - _cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir ;" + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir >/dev/null;" fi # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile ;" + _cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile;" _info "will copy private key to remote file $Le_Deploy_ssh_keyfile" fi @@ -113,10 +113,10 @@ ssh_deploy() { _pipe=">>" elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then # backup file we are about to overwrite. - _cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir ;" + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir >/dev/null;" fi # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile ;" + _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile;" _info "will copy certificate to remote file $Le_Deploy_ssh_certfile" fi @@ -134,10 +134,10 @@ ssh_deploy() { _pipe=">>" elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then # backup file we are about to overwrite. - _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir ;" + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir >/dev/null;" fi # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile ;" + _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile;" _info "will copy CA file to remote file $Le_Deploy_ssh_cafile" fi @@ -156,10 +156,10 @@ ssh_deploy() { _pipe=">>" elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then # backup file we are about to overwrite. - _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir ;" + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir >/dev/null;" fi # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain ;" + _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain;" _info "will copy fullchain to remote file $Le_Deploy_ssh_fullchain" fi @@ -170,7 +170,7 @@ ssh_deploy() { _savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd" fi if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then - _cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd ;" + _cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd;" _info "Will execute remote command $Le_Deploy_ssh_remote_cmd" fi @@ -183,9 +183,9 @@ ssh_deploy() { _cmdstr="{ now=\"\$(date -u +%s)\"; for fn in $_backupprefix*; \ do if [ -d \"\$fn\" ] && [ \"\$(expr \$now - \$(date -ur \$fn +%s) )\" -ge \"15552000\" ]; \ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; done; }; $_cmdstr" - # Alternate version of above... _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf ; $_cmdstr" + # Alternate version of above... _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf; $_cmdstr" # Create our backup directory for overwritten cert files. - _cmdstr="mkdir -p $_backupdir ; $_cmdstr" + _cmdstr="mkdir -p $_backupdir; $_cmdstr" _info "Backup of old certificate files will be placed in remote directory $_backupdir" _info "Backup directories erased after 180 days." fi From e35e31324078803cd1db2c398d070ce2cc184252 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 12 Feb 2017 11:20:16 -0500 Subject: [PATCH 19/35] Fix error in Unifi example --- deploy/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 8f386056..8cc40cd3 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -135,12 +135,13 @@ export ACME_DEPLOY_SSH_REMOTE_CMD="openssl pkcs12 -export \ -out /var/lib/unifi/unifi.example.com.p12 \ -name ubnt -password pass:temppass \ && keytool -importkeystore -deststorepass aircontrolenterprise \ - -destkeypass aircontrolenterprise -destkeystore /var/lib/unifi/keystore \ + -destkeypass aircontrolenterprise \ + -destkeystore /var/lib/unifi/keystore \ -srckeystore /var/lib/unifi/unifi.example.com.p12 \ -srcstoretype PKCS12 -srcstorepass temppass -alias ubnt -noprompt \ && service unifi restart" -acme.sh --deploy -d qnap.example.com --deploy-hook ssh +acme.sh --deploy -d unifi.example.com --deploy-hook ssh ``` Note how in this exmple we execute several commands on the remote host after the certificate files have been copied... to generate a pkcs12 file From 6f4abe95cb8be54272f080a98a3991e7ab9ee2ec Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 12 Feb 2017 11:24:00 -0500 Subject: [PATCH 20/35] update markdown examples. --- deploy/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 8cc40cd3..9c22e80b 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -28,7 +28,7 @@ The ssh deploy plugin allows you to deploy certificates to a remote host using SSH command to connect to the remote server. The ssh plugin is invoked with the following command... -```bash +```sh acme.sh --deploy -d example.com --deploy-hook ssh ``` Prior to running this for the first time you must tell the plugin where @@ -37,17 +37,17 @@ environment variables. This is not required for subsequent runs as the values are stored by acme.sh in the domain configuration files. Required... -```bash +``` export ACME_DEPLOY_SSH_USER=username ``` Optional... -```bash +``` export ACME_DEPLOY_SSH_CMD=custom ssh command export ACME_DEPLOY_SSH_SERVER=url or ip address of remote host export ACME_DEPLOY_SSH_KEYFILE=filename for private key export ACME_DEPLOY_SSH_CERTFILE=filename for certificate file export ACME_DEPLOY_SSH_CAFILE=filename for intermediate CA file -export ACME_DEPLOY_SSH_FULLCHAIN=filename forfullchain file +export ACME_DEPLOY_SSH_FULLCHAIN=filename for fullchain file export ACME_DEPLOY_SSH_REMOTE_CMD=command to execute on remote host export ACME_DEPLOY_SSH_BACKUP=yes or no ``` @@ -101,7 +101,7 @@ Before writing a certificate file to the remote server the existing certificate will be copied to a backup directory on the remote server. These are placed in a hidden directory in the home directory of the SSH user -```bash +```sh ~/.acme_ssh_deploy/[domain name]-backup-[timestamp] ``` Any backups older than 180 days will be deleted when new certificates @@ -112,7 +112,7 @@ are deployed. This defaults to "yes" set to "no" to disable backup. The following example illustrates deploying certifcates to a QNAP NAS running QTS 4.2 -```bash +```sh export ACME_DEPLOY_SSH_USER="admin" export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" @@ -125,7 +125,7 @@ acme.sh --deploy -d qnap.example.com --deploy-hook ssh The next example illustates deploying certificates to a Unifi Contolller (tested with version 5.4.11). -```bash +```sh export ACME_DEPLOY_SSH_USER="root" export ACME_DEPLOY_SSH_KEYFILE="/var/lib/unifi/unifi.example.com.key" export ACME_DEPLOY_SSH_FULLCHAIN="/var/lib/unifi/unifi.example.com.cer" From 76c1ed6628009d8752a8135e80c2614a28bb5e18 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 12 Feb 2017 18:08:17 -0500 Subject: [PATCH 21/35] Additional documentation for the unifi example. --- deploy/README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index 9c22e80b..10f355d6 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -143,7 +143,21 @@ export ACME_DEPLOY_SSH_REMOTE_CMD="openssl pkcs12 -export \ acme.sh --deploy -d unifi.example.com --deploy-hook ssh ``` -Note how in this exmple we execute several commands on the remote host +In this exmple we execute several commands on the remote host after the certificate files have been copied... to generate a pkcs12 file compatible with Unifi, to import it into the Unifi keystore and then finaly to restart the service. + +Note also that once the certificate is imported +into the keystore the individual certificate files are no longer +required. We could if we desired delete those files immediately. If we +do that then we should disable backup at the remote host (as there are +no files to backup -- they were erased during deployment). For example... +```sh +export ACME_DEPLOY_SSH_BACKUP=no +# modify the end of the remte command... +&& rm /var/lib/unifi/unifi.example.com.key \ + /var/lib/unifi/unifi.example.com.cer \ + /var/lib/unifi/unifi.example.com.p12 \ +&& service unifi restart +``` From d04ccb7a3ff71fbf114ace288aea5a49faf9db1a Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 12 Feb 2017 18:20:43 -0500 Subject: [PATCH 22/35] fix spelling error in readme --- deploy/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index 10f355d6..df0cdf0a 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -155,7 +155,7 @@ do that then we should disable backup at the remote host (as there are no files to backup -- they were erased during deployment). For example... ```sh export ACME_DEPLOY_SSH_BACKUP=no -# modify the end of the remte command... +# modify the end of the remote command... && rm /var/lib/unifi/unifi.example.com.key \ /var/lib/unifi/unifi.example.com.cer \ /var/lib/unifi/unifi.example.com.p12 \ From 68a35155e4c2ab8ecd13c60a6e723fb0bdd8eaf3 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Mon, 13 Feb 2017 20:32:12 -0500 Subject: [PATCH 23/35] Improve documentation in readme --- deploy/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index df0cdf0a..ab38f275 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -110,7 +110,7 @@ are deployed. This defaults to "yes" set to "no" to disable backup. ###Eamples using SSH deploy The following example illustrates deploying certifcates to a QNAP NAS -running QTS 4.2 +(tested with QTS version 4.2.3) ```sh export ACME_DEPLOY_SSH_USER="admin" @@ -121,6 +121,10 @@ export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" acme.sh --deploy -d qnap.example.com --deploy-hook ssh ``` +Note how in this example both the private key and certificate point to +the same file. This will result in the certificate being appended +to the same file as the private key... a common requirement of several +services. The next example illustates deploying certificates to a Unifi Contolller (tested with version 5.4.11). From 06492067966ef03344c92892d19b6fccee1cb86e Mon Sep 17 00:00:00 2001 From: David Kerr Date: Tue, 7 Mar 2017 11:57:03 -0500 Subject: [PATCH 24/35] remove _ACME prefix from all exported variables. --- deploy/README.md | 56 ++++++++++++++++++++++++------------------------ deploy/ssh.sh | 54 +++++++++++++++++++++++----------------------- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index ab38f275..22b8e8d2 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -38,21 +38,21 @@ values are stored by acme.sh in the domain configuration files. Required... ``` -export ACME_DEPLOY_SSH_USER=username +export DEPLOY_SSH_USER=username ``` Optional... ``` -export ACME_DEPLOY_SSH_CMD=custom ssh command -export ACME_DEPLOY_SSH_SERVER=url or ip address of remote host -export ACME_DEPLOY_SSH_KEYFILE=filename for private key -export ACME_DEPLOY_SSH_CERTFILE=filename for certificate file -export ACME_DEPLOY_SSH_CAFILE=filename for intermediate CA file -export ACME_DEPLOY_SSH_FULLCHAIN=filename for fullchain file -export ACME_DEPLOY_SSH_REMOTE_CMD=command to execute on remote host -export ACME_DEPLOY_SSH_BACKUP=yes or no +export DEPLOY_SSH_CMD=custom ssh command +export DEPLOY_SSH_SERVER=url or ip address of remote host +export DEPLOY_SSH_KEYFILE=filename for private key +export DEPLOY_SSH_CERTFILE=filename for certificate file +export DEPLOY_SSH_CAFILE=filename for intermediate CA file +export DEPLOY_SSH_FULLCHAIN=filename for fullchain file +export DEPLOY_SSH_REMOTE_CMD=command to execute on remote host +export DEPLOY_SSH_BACKUP=yes or no ``` -**ACME_DEPLOY_SSH_USER** +**DEPLOY_SSH_USER** Username at the remote host that SSH will login with. Note that SSH must be able to login to remote host without a password... SSH Keys must have been exchanged with the remote host. Validate and test that you @@ -62,41 +62,41 @@ The USER@URL at the remote server must also have has permissions to write to the target location of the certificate files and to execute any commands (e.g. to stop/start services). -**ACME_DEPLOY_SSH_CMD** +**DEPLOY_SSH_CMD** You can customize the ssh command used to connect to the remote host. For example if you need to connect to a specific port at the remote server you can set this to, for example, "ssh -p 22" or to use `sshpass` to provide password inline instead of exchanging ssh keys (this is not recommended, using keys is more secure). -**ACME_DEPLOY_SSH_SERVER** +**DEPLOY_SSH_SERVER** URL or IP Address of the remote server. If not provided then the domain name provided on the acme.sh --deploy command line is used. -**ACME_DEPLOY_SSH_KEYFILE** +**DEPLOY_SSH_KEYFILE** Target filename for the private key issued by LetsEncrypt. -**ACME_DEPLOY_SSH_CERTFILE** +**DEPLOY_SSH_CERTFILE** Target filename for the certificate issued by LetsEncrypt. If this is the same as the previous filename (for keyfile) then it is appended to the same file. -**ACME_DEPLOY_SSH_CAFILE** +**DEPLOY_SSH_CAFILE** Target filename for the CA intermediate certificate issued by LetsEncrypt. If this is the same as a previous filename (for keyfile or certfile) then it is appended to the same file. -**ACME_DEPLOY_SSH_FULLCHAIN** +**DEPLOY_SSH_FULLCHAIN** Target filename for the fullchain certificate issued by LetsEncrypt. If this is the same as a previous filename (for keyfile, certfile or cafile) then it is appended to the same file. -**ACME_DEPLOY_SSH_REMOTE_CMD** +**DEPLOY_SSH_REMOTE_CMD** Command to execute on the remote server after copying any certificates. This could be any additional command required for example to stop and restart the service. -**ACME_DEPLOY_SSH_BACKUP** +**DEPLOY_SSH_BACKUP** Before writing a certificate file to the remote server the existing certificate will be copied to a backup directory on the remote server. These are placed in a hidden directory in the home directory of the SSH @@ -113,11 +113,11 @@ The following example illustrates deploying certifcates to a QNAP NAS (tested with QTS version 4.2.3) ```sh -export ACME_DEPLOY_SSH_USER="admin" -export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" -export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" -export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" -export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" +export DEPLOY_SSH_USER="admin" +export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" +export DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" +export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" +export DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" acme.sh --deploy -d qnap.example.com --deploy-hook ssh ``` @@ -130,10 +130,10 @@ The next example illustates deploying certificates to a Unifi Contolller (tested with version 5.4.11). ```sh -export ACME_DEPLOY_SSH_USER="root" -export ACME_DEPLOY_SSH_KEYFILE="/var/lib/unifi/unifi.example.com.key" -export ACME_DEPLOY_SSH_FULLCHAIN="/var/lib/unifi/unifi.example.com.cer" -export ACME_DEPLOY_SSH_REMOTE_CMD="openssl pkcs12 -export \ +export DEPLOY_SSH_USER="root" +export DEPLOY_SSH_KEYFILE="/var/lib/unifi/unifi.example.com.key" +export DEPLOY_SSH_FULLCHAIN="/var/lib/unifi/unifi.example.com.cer" +export DEPLOY_SSH_REMOTE_CMD="openssl pkcs12 -export \ -inkey /var/lib/unifi/unifi.example.com.key \ -in /var/lib/unifi/unifi.example.com.cer \ -out /var/lib/unifi/unifi.example.com.p12 \ @@ -158,7 +158,7 @@ required. We could if we desired delete those files immediately. If we do that then we should disable backup at the remote host (as there are no files to backup -- they were erased during deployment). For example... ```sh -export ACME_DEPLOY_SSH_BACKUP=no +export DEPLOY_SSH_BACKUP=no # modify the end of the remote command... && rm /var/lib/unifi/unifi.example.com.key \ /var/lib/unifi/unifi.example.com.cer \ diff --git a/deploy/ssh.sh b/deploy/ssh.sh index a8ed6a10..a68da356 100644 --- a/deploy/ssh.sh +++ b/deploy/ssh.sh @@ -12,15 +12,15 @@ # Only a username is required. All others are optional. # # The following examples are for QNAP NAS running QTS 4.2 -# export ACME_DEPLOY_SSH_CMD="" # defaults to ssh -# export ACME_DEPLOY_SSH_USER="admin" # required -# export ACME_DEPLOY_SSH_SERVER="qnap" # defaults to domain name -# export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" -# export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" -# export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" -# export ACME_DEPLOY_SSH_FULLCHAIN="" -# export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" -# export ACME_DEPLOY_SSH_BACKUP="" # yes or no, default to yes +# export DEPLOY_SSH_CMD="" # defaults to ssh +# export DEPLOY_SSH_USER="admin" # required +# export DEPLOY_SSH_SERVER="qnap" # defaults to domain name +# export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" +# export DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" +# export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" +# export DEPLOY_SSH_FULLCHAIN="" +# export DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" +# export DEPLOY_SSH_BACKUP="" # yes or no, default to yes # ######## Public functions ##################### @@ -48,34 +48,34 @@ ssh_deploy() { _debug _cfullchain "$_cfullchain" # USER is required to login by SSH to remote host. - if [ -z "$ACME_DEPLOY_SSH_USER" ]; then + if [ -z "$DEPLOY_SSH_USER" ]; then if [ -z "$Le_Deploy_ssh_user" ]; then - _err "ACME_DEPLOY_SSH_USER not defined." + _err "DEPLOY_SSH_USER not defined." return 1 fi else - Le_Deploy_ssh_user="$ACME_DEPLOY_SSH_USER" + Le_Deploy_ssh_user="$DEPLOY_SSH_USER" _savedomainconf Le_Deploy_ssh_user "$Le_Deploy_ssh_user" fi # SERVER is optional. If not provided then use _cdomain - if [ -n "$ACME_DEPLOY_SSH_SERVER" ]; then - Le_Deploy_ssh_server="$ACME_DEPLOY_SSH_SERVER" + if [ -n "$DEPLOY_SSH_SERVER" ]; then + Le_Deploy_ssh_server="$DEPLOY_SSH_SERVER" _savedomainconf Le_Deploy_ssh_server "$Le_Deploy_ssh_server" elif [ -z "$Le_Deploy_ssh_server" ]; then Le_Deploy_ssh_server="$_cdomain" fi # CMD is optional. If not provided then use ssh - if [ -n "$ACME_DEPLOY_SSH_CMD" ]; then - Le_Deploy_ssh_cmd="$ACME_DEPLOY_SSH_CMD" + if [ -n "$DEPLOY_SSH_CMD" ]; then + Le_Deploy_ssh_cmd="$DEPLOY_SSH_CMD" _savedomainconf Le_Deploy_ssh_cmd "$Le_Deploy_ssh_cmd" elif [ -z "$Le_Deploy_ssh_cmd" ]; then Le_Deploy_ssh_cmd="ssh" fi # BACKUP is optional. If not provided then default to yes - if [ "$ACME_DEPLOY_SSH_BACKUP" = "no" ]; then + if [ "$DEPLOY_SSH_BACKUP" = "no" ]; then Le_Deploy_ssh_backup="no" elif [ -z "$Le_Deploy_ssh_backup" ]; then Le_Deploy_ssh_backup="yes" @@ -86,8 +86,8 @@ ssh_deploy() { # KEYFILE is optional. # If provided then private key will be copied to provided filename. - if [ -n "$ACME_DEPLOY_SSH_KEYFILE" ]; then - Le_Deploy_ssh_keyfile="$ACME_DEPLOY_SSH_KEYFILE" + if [ -n "$DEPLOY_SSH_KEYFILE" ]; then + Le_Deploy_ssh_keyfile="$DEPLOY_SSH_KEYFILE" _savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile" fi if [ -n "$Le_Deploy_ssh_keyfile" ]; then @@ -102,8 +102,8 @@ ssh_deploy() { # CERTFILE is optional. # If provided then private key will be copied or appended to provided filename. - if [ -n "$ACME_DEPLOY_SSH_CERTFILE" ]; then - Le_Deploy_ssh_certfile="$ACME_DEPLOY_SSH_CERTFILE" + if [ -n "$DEPLOY_SSH_CERTFILE" ]; then + Le_Deploy_ssh_certfile="$DEPLOY_SSH_CERTFILE" _savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile" fi if [ -n "$Le_Deploy_ssh_certfile" ]; then @@ -122,8 +122,8 @@ ssh_deploy() { # CAFILE is optional. # If provided then CA intermediate certificate will be copied or appended to provided filename. - if [ -n "$ACME_DEPLOY_SSH_CAFILE" ]; then - Le_Deploy_ssh_cafile="$ACME_DEPLOY_SSH_CAFILE" + if [ -n "$DEPLOY_SSH_CAFILE" ]; then + Le_Deploy_ssh_cafile="$DEPLOY_SSH_CAFILE" _savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile" fi if [ -n "$Le_Deploy_ssh_cafile" ]; then @@ -143,8 +143,8 @@ ssh_deploy() { # FULLCHAIN is optional. # If provided then fullchain certificate will be copied or appended to provided filename. - if [ -n "$ACME_DEPLOY_SSH_FULLCHAIN" ]; then - Le_Deploy_ssh_fullchain="$ACME_DEPLOY_SSH_FULLCHAIN" + if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then + Le_Deploy_ssh_fullchain="$DEPLOY_SSH_FULLCHAIN" _savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain" fi if [ -n "$Le_Deploy_ssh_fullchain" ]; then @@ -165,8 +165,8 @@ ssh_deploy() { # REMOTE_CMD is optional. # If provided then this command will be executed on remote host. - if [ -n "$ACME_DEPLOY_SSH_REMOTE_CMD" ]; then - Le_Deploy_ssh_remote_cmd="$ACME_DEPLOY_SSH_REMOTE_CMD" + if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then + Le_Deploy_ssh_remote_cmd="$DEPLOY_SSH_REMOTE_CMD" _savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd" fi if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then From 158abf5c6ca5c6de5a015569196403e4dad43395 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Tue, 7 Mar 2017 12:09:07 -0500 Subject: [PATCH 25/35] Remove line from README.md that I mistakenly added during merge with master. --- deploy/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 4008f64a..60ab34ae 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -26,8 +26,6 @@ Before you can deploy your cert, you must [issue the cert first](https://github. ## 3. Deploy the cert to remote server through SSH access. -Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert). - The ssh deploy plugin allows you to deploy certificates to a remote host using SSH command to connect to the remote server. The ssh plugin is invoked with the following command... From 41e3ecad4603c0dcac9d3e26db49cd02922e91bd Mon Sep 17 00:00:00 2001 From: Boyan Peychev Date: Mon, 19 Feb 2018 14:14:08 +0200 Subject: [PATCH 26/35] Update dns api to support v2 wildcard cert #1261 --- dnsapi/dns_cloudns.sh | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 4a1ae641..c9d38ed8 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -26,30 +26,18 @@ dns_cloudns_add() { host="$(echo "$1" | sed "s/\.$zone\$//")" record=$2 - record_id=$(_dns_cloudns_get_record_id "$zone" "$host") _debug zone "$zone" _debug host "$host" _debug record "$record" - _debug record_id "$record_id" - if [ -z "$record_id" ]; then - _info "Adding the TXT record for $1" - _dns_cloudns_http_api_call "dns/add-record.json" "domain-name=$zone&record-type=TXT&host=$host&record=$record&ttl=60" - if ! _contains "$response" "\"status\":\"Success\""; then - _err "Record cannot be added." - return 1 - fi - _info "Added." - else - _info "Updating the TXT record for $1" - _dns_cloudns_http_api_call "dns/mod-record.json" "domain-name=$zone&record-id=$record_id&record-type=TXT&host=$host&record=$record&ttl=60" - if ! _contains "$response" "\"status\":\"Success\""; then - _err "The TXT record for $1 cannot be updated." - return 1 - fi - _info "Updated." + _info "Adding the TXT record for $1" + _dns_cloudns_http_api_call "dns/add-record.json" "domain-name=$zone&record-type=TXT&host=$host&record=$record&ttl=60" + if ! _contains "$response" "\"status\":\"Success\""; then + _err "Record cannot be added." + return 1 fi + _info "Added." return 0 } From 5309afc347d22917cb250d59ca4c97638223decb Mon Sep 17 00:00:00 2001 From: Boyan Peychev Date: Tue, 20 Feb 2018 11:09:37 +0200 Subject: [PATCH 27/35] Update dns api to support v2 wildcard cert #1261 --- dnsapi/dns_cloudns.sh | 51 ++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index c9d38ed8..dfab302b 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -60,22 +60,32 @@ dns_cloudns_rm() { host="$(echo "$1" | sed "s/\.$zone\$//")" record=$2 - record_id=$(_dns_cloudns_get_record_id "$zone" "$host") - _debug zone "$zone" - _debug host "$host" - _debug record "$record" - _debug record_id "$record_id" - - if [ ! -z "$record_id" ]; then - _info "Deleting the TXT record for $1" - _dns_cloudns_http_api_call "dns/delete-record.json" "domain-name=$zone&record-id=$record_id" - if ! _contains "$response" "\"status\":\"Success\""; then - _err "The TXT record for $1 cannot be deleted." - return 1 - fi - _info "Deleted." + _dns_cloudns_http_api_call "dns/records.json" "domain-name=$zone&host=$host&type=TXT" + if ! _contains "$response" "\"id\":"; then + return 1 fi + + for i in $(echo $response | tr '{' "\n" | grep $record); do + record_id=$(echo $i | tr ',' "\n"| grep -E '^"id"'| sed -re 's/^\"id\"\:\"([0-9]+)\"$/\1/g'); + + if [ ! -z "$record_id" ]; then + _debug zone "$zone" + _debug host "$host" + _debug record "$record" + _debug record_id "$record_id" + + _info "Deleting the TXT record for $1" + _dns_cloudns_http_api_call "dns/delete-record.json" "domain-name=$zone&record-id=$record_id" + + if ! _contains "$response" "\"status\":\"Success\""; then + _err "The TXT record for $1 cannot be deleted." + else + _info "Deleted." + fi + fi + done + return 0 } @@ -114,7 +124,7 @@ _dns_cloudns_init_check() { return 1 fi - #save the api id and password to the account conf file. + # save the api id and password to the account conf file. _saveaccountconf_mutable CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" _saveaccountconf_mutable CLOUDNS_SUB_AUTH_ID "$CLOUDNS_SUB_AUTH_ID" _saveaccountconf_mutable CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" @@ -147,15 +157,6 @@ _dns_cloudns_get_zone_name() { return 1 } -_dns_cloudns_get_record_id() { - _dns_cloudns_http_api_call "dns/records.json" "domain-name=$1&host=$2&type=TXT" - if _contains "$response" "\"id\":"; then - echo "$response" | cut -d '"' -f 2 - return 0 - fi - return 1 -} - _dns_cloudns_http_api_call() { method=$1 @@ -177,7 +178,7 @@ _dns_cloudns_http_api_call() { response="$(_get "$CLOUDNS_API/$method?$data")" - _debug2 response "$response" + _debug response "$response" return 0 } From 9f6832d636316e7dfacea6c93cf455a835b084ca Mon Sep 17 00:00:00 2001 From: Boyan Peychev Date: Tue, 20 Feb 2018 11:16:42 +0200 Subject: [PATCH 28/35] Update dns api to support v2 wildcard cert #1261 --- dnsapi/dns_cloudns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index dfab302b..6f2cbfe6 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -66,8 +66,8 @@ dns_cloudns_rm() { return 1 fi - for i in $(echo $response | tr '{' "\n" | grep $record); do - record_id=$(echo $i | tr ',' "\n"| grep -E '^"id"'| sed -re 's/^\"id\"\:\"([0-9]+)\"$/\1/g'); + for i in $(echo "$response" | tr '{' "\n" | grep $record); do + record_id=$(echo "$i" | tr ',' "\n" | grep -E '^"id"'| sed -re 's/^\"id\"\:\"([0-9]+)\"$/\1/g') if [ ! -z "$record_id" ]; then _debug zone "$zone" From 28355335f82a04f68a1aecbc1ce7bec865df4fe8 Mon Sep 17 00:00:00 2001 From: Boyan Peychev Date: Tue, 20 Feb 2018 11:22:06 +0200 Subject: [PATCH 29/35] Update dns api to support v2 wildcard cert #1261 --- dnsapi/dns_cloudns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 6f2cbfe6..df824e86 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -66,8 +66,8 @@ dns_cloudns_rm() { return 1 fi - for i in $(echo "$response" | tr '{' "\n" | grep $record); do - record_id=$(echo "$i" | tr ',' "\n" | grep -E '^"id"'| sed -re 's/^\"id\"\:\"([0-9]+)\"$/\1/g') + for i in $(echo "$response" | tr '{' "\n" | grep "$record"); do + record_id=$(echo "$i" | tr ',' "\n" | grep -E '^"id"' | sed -re 's/^\"id\"\:\"([0-9]+)\"$/\1/g') if [ ! -z "$record_id" ]; then _debug zone "$zone" From 58f753136a6b92607fe8767b3367ab56108efe56 Mon Sep 17 00:00:00 2001 From: hebbet Date: Wed, 21 Feb 2018 09:01:56 +0100 Subject: [PATCH 30/35] small typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e2defb7..ad2a2459 100644 --- a/README.md +++ b/README.md @@ -204,7 +204,7 @@ Install/copy the cert/key to the production Apache or Nginx path. The cert will be renewed every **60** days by default (which is configurable). Once the cert is renewed, the Apache/Nginx service will be reloaded automatically by the command: `service apache2 force-reload` or `service nginx force-reload`. -**Please take care: The reloadcmd is very important. The cert can be automatically renewed, but, without a correct 'reloadcmd' the cert may not be flushed to your server(like nginx or apache), then your website will not be able to show renewwed cert in 60 days.** +**Please take care: The reloadcmd is very important. The cert can be automatically renewed, but, without a correct 'reloadcmd' the cert may not be flushed to your server(like nginx or apache), then your website will not be able to show renewed cert in 60 days.** # 4. Use Standalone server to issue cert From f49f55f4a51e0e5eb84212d670a3ac373ff78acb Mon Sep 17 00:00:00 2001 From: Mal Graty Date: Tue, 20 Feb 2018 14:55:05 +0000 Subject: [PATCH 31/35] Pull AWS creds from container role Extend the AWS DNS API driver to support ECS container metadata by using the special environment variable ECS sets in containers. --- dnsapi/dns_aws.sh | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 9c9e9313..8ce7c347 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -23,7 +23,7 @@ dns_aws_add() { AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}" if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then - _use_instance_role + _use_container_role || _use_instance_role fi if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then @@ -87,7 +87,7 @@ dns_aws_rm() { AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}" if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then - _use_instance_role + _use_container_role || _use_instance_role fi _debug "First detect the root zone" @@ -174,17 +174,30 @@ _get_root() { return 1 } +_use_container_role() { + # automatically set if running inside ECS + if [ -z "$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" ]; then + _debug "No ECS environment variable detected" + return 1 + fi + _use_metadata "169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" +} + _use_instance_role() { _url="http://169.254.169.254/latest/meta-data/iam/security-credentials/" _debug "_url" "$_url" if ! _get "$_url" true 1 | _head_n 1 | grep -Fq 200; then - _err "Unable to fetch IAM role from AWS instance metadata." - return + _debug "Unable to fetch IAM role from instance metadata" + return 1 fi _aws_role=$(_get "$_url" "" 1) _debug "_aws_role" "$_aws_role" + _use_metadata "$_url$_aws_role" +} + +_use_metadata() { _aws_creds="$( - _get "$_url$_aws_role" "" 1 \ + _get "$1" "" 1 \ | _normalizeJson \ | tr '{,}' '\n' \ | while read -r _line; do @@ -201,6 +214,11 @@ _use_instance_role() { | paste -sd' ' - )" _secure_debug "_aws_creds" "$_aws_creds" + + if [ -z "$_aws_creds" ]; then + return 1 + fi + eval "$_aws_creds" _using_role=true } From 83b1a98db18dded8eecb21d3937e4339ca64a2d9 Mon Sep 17 00:00:00 2001 From: martgras Date: Sun, 18 Feb 2018 16:32:39 +0100 Subject: [PATCH 32/35] Azure DNS API - support for ACME v2 and reliability improvments support adding 2 txt records Adding retry logic for REST API calls Reusing bearer token removes 50% of required REST calls --- dnsapi/dns_azure.sh | 158 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 124 insertions(+), 34 deletions(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index 0834ede7..677a9f75 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -1,5 +1,7 @@ #!/usr/bin/env sh +WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-use-Azure-DNS" + ######## Public functions ##################### # Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" @@ -69,12 +71,36 @@ dns_azure_add() { acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" | sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" _debug "$acmeRecordURI" - body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" + # Get existing TXT record + _azure_rest GET "$acmeRecordURI" "" "$accesstoken" + values="{\"value\":[\"$txtvalue\"]}" + timestamp="$(_time)" + if [ "$_code" = "200" ]; then + vlist="$(echo "$response" | _egrep_o "\"value\"\s*:\s*\[\s*\"[^\"]*\"\s*]" | cut -d : -f 2 | tr -d "[]\"")" + _debug "existing TXT found" + _debug "$vlist" + existingts="$(echo "$response" | _egrep_o "\"acmetscheck\"\s*:\s*\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d "\"")" + if [ -z "$existingts" ]; then + # the record was not created by acme.sh. Copy the exisiting entires + existingts=$timestamp + fi + _diff="$(_math "$timestamp - $existingts")" + _debug "existing txt age: $_diff" + # only use recently added records and discard if older than 2 hours because they are probably orphaned + if [ "$_diff" -lt 7200 ]; then + _debug "existing txt value: $vlist" + for v in $vlist; do + values="$values ,{\"value\":[\"$v\"]}" + done + fi + fi + # Add the txtvalue TXT Record + body="{\"properties\":{\"metadata\":{\"acmetscheck\":\"$timestamp\"},\"TTL\":10, \"TXTRecords\":[$values]}}" _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken" if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then - _info "validation record added" + _info "validation value added" else - _err "error adding validation record ($_code)" + _err "error adding validation value ($_code)" return 1 fi } @@ -141,13 +167,38 @@ dns_azure_rm() { acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" | sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" _debug "$acmeRecordURI" - body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" - _azure_rest DELETE "$acmeRecordURI" "" "$accesstoken" - if [ "$_code" = "200" ] || [ "$_code" = '204' ]; then - _info "validation record removed" - else - _err "error removing validation record ($_code)" - return 1 + # Get existing TXT record + _azure_rest GET "$acmeRecordURI" "" "$accesstoken" + timestamp="$(_time)" + if [ "$_code" = "200" ]; then + vlist="$(echo "$response" | _egrep_o "\"value\"\s*:\s*\[\s*\"[^\"]*\"\s*]" | cut -d : -f 2 | tr -d "[]\"" | grep -v "$txtvalue")" + values="" + comma="" + for v in $vlist; do + values="$values$comma{\"value\":[\"$v\"]}" + comma="," + done + if [ -z "$values" ]; then + # No values left remove record + _debug "removing validation record completely $acmeRecordURI" + _azure_rest DELETE "$acmeRecordURI" "" "$accesstoken" + if [ "$_code" = "200" ] || [ "$_code" = '204' ]; then + _info "validation record removed" + else + _err "error removing validation record ($_code)" + return 1 + fi + else + # Remove only txtvalue from the TXT Record + body="{\"properties\":{\"metadata\":{\"acmetscheck\":\"$timestamp\"},\"TTL\":10, \"TXTRecords\":[$values]}}" + _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken" + if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then + _info "validation value removed" + else + _err "error removing validation value ($_code)" + return 1 + fi + fi fi } @@ -159,52 +210,92 @@ _azure_rest() { data="$3" accesstoken="$4" - export _H1="authorization: Bearer $accesstoken" - export _H2="accept: application/json" - export _H3="Content-Type: application/json" - - _debug "$ep" - if [ "$m" != "GET" ]; then - _debug data "$data" - response="$(_post "$data" "$ep" "" "$m")" - else - response="$(_get "$ep")" - fi - _debug2 response "$response" - - _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" - _debug2 "http response code $_code" - - if [ "$?" != "0" ]; then - _err "error $ep" + MAX_REQUEST_RETRY_TIMES=5 + _request_retry_times=0 + while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do + _debug3 _request_retry_times "$_request_retry_times" + export _H1="authorization: Bearer $accesstoken" + export _H2="accept: application/json" + export _H3="Content-Type: application/json" + # clear headers from previous request to avoid getting wrong http code on timeouts + :>"$HTTP_HEADER" + _debug "$ep" + if [ "$m" != "GET" ]; then + _secure_debug2 "data $data" + response="$(_post "$data" "$ep" "" "$m")" + else + response="$(_get "$ep")" + fi + _secure_debug2 "response $response" + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + _debug "http response code $_code" + if [ "$_code" = "401" ]; then + # we have an invalid access token set to expired + _saveaccountconf_mutable AZUREDNS_TOKENVALIDTO "0" + _err "access denied make sure your Azure settings are correct. See $WIKI" + return 1 + fi + # See https://docs.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#general-rest-and-retry-guidelines for retryable HTTP codes + if [ "$?" != "0" ] || [ -z "$_code" ] || [ "$_code" = "408" ] || [ "$_code" = "500" ] || [ "$_code" = "503" ] || [ "$_code" = "504" ]; then + _request_retry_times="$(_math "$_request_retry_times" + 1)" + _info "REST call error $_code retrying $ep in $_request_retry_times s" + _sleep "$_request_retry_times" + continue + fi + break + done + if [ "$_request_retry_times" = "$MAX_REQUEST_RETRY_TIMES" ]; then + _err "Error Azure REST called was retried $MAX_REQUEST_RETRY_TIMES times." + _err "Calling $ep failed." return 1 fi + response="$(echo "$response" | _normalizeJson)" return 0 } ## Ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service#request-an-access-token _azure_getaccess_token() { - TENANTID=$1 + tenantID=$1 clientID=$2 clientSecret=$3 + accesstoken="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}" + expires_on="${AZUREDNS_TOKENVALIDTO:-$(_readaccountconf_mutable AZUREDNS_TOKENVALIDTO)}" + + # can we reuse the bearer token? + if [ -n "$accesstoken" ] && [ -n "$expires_on" ]; then + if [ "$(_time)" -lt "$expires_on" ]; then + # brearer token is still valid - reuse it + _debug "reusing bearer token" + printf "%s" "$accesstoken" + return 0 + else + _debug "bearer token expired" + fi + fi + _debug "getting new bearer token" + export _H1="accept: application/json" export _H2="Content-Type: application/x-www-form-urlencoded" body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials" - _debug data "$body" - response="$(_post "$body" "https://login.windows.net/$TENANTID/oauth2/token" "" "POST")" + _secure_debug2 "data $body" + response="$(_post "$body" "https://login.microsoftonline.com/$tenantID/oauth2/token" "" "POST")" + _secure_debug2 "response $response" + response="$(echo "$response" | _normalizeJson)" accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") - _debug2 "response $response" + expires_on=$(echo "$response" | _egrep_o "\"expires_on\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") if [ -z "$accesstoken" ]; then - _err "no acccess token received" + _err "no acccess token received. Check your Azure settings see $WIKI" return 1 fi if [ "$?" != "0" ]; then _err "error $response" return 1 fi + _saveaccountconf_mutable AZUREDNS_BEARERTOKEN "$accesstoken" + _saveaccountconf_mutable AZUREDNS_TOKENVALIDTO "$expires_on" printf "%s" "$accesstoken" return 0 } @@ -222,7 +313,6 @@ _get_root() { ## Per https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits#dns-limits you are limited to 100 Zone/subscriptions anyways ## _azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/dnszones?api-version=2017-09-01" "" "$accesstoken" - # Find matching domain name is Json response while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) From e26f9b8095291f83b4fa5a0a56f5958824b404f1 Mon Sep 17 00:00:00 2001 From: nytral Date: Sat, 24 Feb 2018 09:08:44 +0100 Subject: [PATCH 33/35] DNSMadeEasy ACMEv2 support --- dnsapi/dns_me.sh | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index 3393fb75..dec07b71 100644 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -45,8 +45,7 @@ dns_me_add() { count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2) _debug count "$count" - if [ "$count" = "0" ]; then - _info "Adding record" +# _info "Adding record" if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then if printf -- "%s" "$response" | grep \"id\": >/dev/null; then _info "Added" @@ -58,20 +57,7 @@ dns_me_add() { fi fi _err "Add txt record error." - else - _info "Updating record" - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | head -n 1) - _debug "record_id" "$record_id" - - _me_rest PUT "$_domain_id/records/$record_id/" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}" - if [ "$?" = "0" ]; then - _info "Updated" - #todo: check if the record takes effect - return 0 - fi - _err "Update error" return 1 - fi } @@ -96,7 +82,7 @@ dns_me_rm() { if [ "$count" = "0" ]; then _info "Don't need to remove." else - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | head -n 1) + record_id=$(printf "%s\n" "$response" | _egrep_o ",\"value\":\"..$txtvalue..\",\"id\":[^,]*" | cut -d : -f 3 | head -n 1) _debug "record_id" "$record_id" if [ -z "$record_id" ]; then _err "Can not get record id to remove." @@ -152,7 +138,7 @@ _me_rest() { data="$3" _debug "$ep" - cdate=$(date -u +"%a, %d %b %Y %T %Z") + cdate=$(LANG=C date -u +"%a, %d %b %Y %T %Z") hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(printf "%s" "$ME_Secret" | _hex_dump | tr -d " ")" hex) export _H1="x-dnsme-apiKey: $ME_Key" From 5a883889a221f9983ae6d5cc94f7271401f8b225 Mon Sep 17 00:00:00 2001 From: nytral Date: Mon, 26 Feb 2018 14:53:31 +0100 Subject: [PATCH 34/35] fixes --- dnsapi/dns_me.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index dec07b71..ca36607f 100644 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -43,8 +43,6 @@ dns_me_add() { return 1 fi - count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2) - _debug count "$count" # _info "Adding record" if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then if printf -- "%s" "$response" | grep \"id\": >/dev/null; then @@ -56,8 +54,6 @@ dns_me_add() { return 1 fi fi - _err "Add txt record error." - return 1 } From 3bc59a0327df3e1a1662fff2351ffd29c834ad6c Mon Sep 17 00:00:00 2001 From: nytral Date: Mon, 26 Feb 2018 21:47:51 +0100 Subject: [PATCH 35/35] first attempt to fix CI errors --- dnsapi/dns_me.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index ca36607f..382eeedd 100644 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -43,17 +43,17 @@ dns_me_add() { return 1 fi -# _info "Adding record" - if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then - if printf -- "%s" "$response" | grep \"id\": >/dev/null; then - _info "Added" - #todo: check if the record takes effect - return 0 - else - _err "Add txt record error." - return 1 - fi + _info "Adding record" + if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then + if printf -- "%s" "$response" | grep \"id\": >/dev/null; then + _info "Added" + #todo: check if the record takes effect + return 0 + else + _err "Add txt record error." + return 1 fi + fi }