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

303 lines
11 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
4 years ago
8 years ago
8 years ago
8 years ago
4 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. #!/usr/bin/env sh
  2. # Script to deploy certificates to remote server by SSH
  3. # Note that SSH must be able to login to remote host without a password...
  4. # SSH Keys must have been exchanged with the remote host. Validate and
  5. # test that you can login to USER@SERVER from the host running acme.sh before
  6. # using this script.
  7. #
  8. # The following variables exported from environment will be used.
  9. # If not set then values previously saved in domain.conf file are used.
  10. #
  11. # Only a username is required. All others are optional.
  12. #
  13. # The following examples are for QNAP NAS running QTS 4.2
  14. # export DEPLOY_SSH_CMD="" # defaults to "ssh -T"
  15. # export DEPLOY_SSH_USER="admin" # required
  16. # export DEPLOY_SSH_SERVER="qnap" # defaults to domain name
  17. # export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem"
  18. # export DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem"
  19. # export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem"
  20. # export DEPLOY_SSH_FULLCHAIN=""
  21. # export DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart"
  22. # export DEPLOY_SSH_BACKUP="" # yes or no, default to yes or previously saved value
  23. # export DEPLOY_SSH_BACKUP_PATH=".acme_ssh_deploy" # path on remote system. Defaults to .acme_ssh_deploy
  24. # export DEPLOY_SSH_MULTI_CALL="" # yes or no, default to no or previously saved value
  25. #
  26. ######## Public functions #####################
  27. #domain keyfile certfile cafile fullchain
  28. ssh_deploy() {
  29. _cdomain="$1"
  30. _ckey="$2"
  31. _ccert="$3"
  32. _cca="$4"
  33. _cfullchain="$5"
  34. _deploy_ssh_servers=""
  35. _debug _cdomain "$_cdomain"
  36. _debug _ckey "$_ckey"
  37. _debug _ccert "$_ccert"
  38. _debug _cca "$_cca"
  39. _debug _cfullchain "$_cfullchain"
  40. # USER is required to login by SSH to remote host.
  41. _getdeployconf DEPLOY_SSH_USER
  42. _debug2 DEPLOY_SSH_USER "$DEPLOY_SSH_USER"
  43. if [ -z "$DEPLOY_SSH_USER" ]; then
  44. if [ -z "$Le_Deploy_ssh_user" ]; then
  45. _err "DEPLOY_SSH_USER not defined."
  46. return 1
  47. fi
  48. else
  49. Le_Deploy_ssh_user="$DEPLOY_SSH_USER"
  50. _savedomainconf Le_Deploy_ssh_user "$Le_Deploy_ssh_user"
  51. fi
  52. # SERVER is optional. If not provided then use _cdomain
  53. _getdeployconf DEPLOY_SSH_SERVER
  54. _debug2 DEPLOY_SSH_SERVER "$DEPLOY_SSH_SERVER"
  55. if [ -n "$DEPLOY_SSH_SERVER" ]; then
  56. Le_Deploy_ssh_server="$DEPLOY_SSH_SERVER"
  57. _savedomainconf Le_Deploy_ssh_server "$Le_Deploy_ssh_server"
  58. elif [ -z "$Le_Deploy_ssh_server" ]; then
  59. Le_Deploy_ssh_server="$_cdomain"
  60. fi
  61. # CMD is optional. If not provided then use ssh
  62. _getdeployconf DEPLOY_SSH_CMD
  63. _debug2 DEPLOY_SSH_CMD "$DEPLOY_SSH_CMD"
  64. if [ -n "$DEPLOY_SSH_CMD" ]; then
  65. Le_Deploy_ssh_cmd="$DEPLOY_SSH_CMD"
  66. _savedomainconf Le_Deploy_ssh_cmd "$Le_Deploy_ssh_cmd"
  67. elif [ -z "$Le_Deploy_ssh_cmd" ]; then
  68. Le_Deploy_ssh_cmd="ssh -T"
  69. fi
  70. # BACKUP is optional. If not provided then default to previously saved value or yes.
  71. _getdeployconf DEPLOY_SSH_BACKUP
  72. _debug2 DEPLOY_SSH_BACKUP "$DEPLOY_SSH_BACKUP"
  73. if [ "$DEPLOY_SSH_BACKUP" = "no" ]; then
  74. Le_Deploy_ssh_backup="no"
  75. elif [ -z "$Le_Deploy_ssh_backup" ] || [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
  76. Le_Deploy_ssh_backup="yes"
  77. fi
  78. _savedomainconf Le_Deploy_ssh_backup "$Le_Deploy_ssh_backup"
  79. # BACKUP_PATH is optional. If not provided then default to previously saved value or .acme_ssh_deploy
  80. _getdeployconf DEPLOY_SSH_BACKUP_PATH
  81. _debug2 DEPLOY_SSH_BACKUP_PATH "$DEPLOY_SSH_BACKUP_PATH"
  82. if [ -n "$DEPLOY_SSH_BACKUP_PATH" ]; then
  83. Le_Deploy_ssh_backup_path="$DEPLOY_SSH_BACKUP_PATH"
  84. elif [ -z "$Le_Deploy_ssh_backup_path" ]; then
  85. Le_Deploy_ssh_backup_path=".acme_ssh_deploy"
  86. fi
  87. _savedomainconf Le_Deploy_ssh_backup_path "$Le_Deploy_ssh_backup_path"
  88. # MULTI_CALL is optional. If not provided then default to previously saved
  89. # value (which may be undefined... equivalent to "no").
  90. _getdeployconf DEPLOY_SSH_MULTI_CALL
  91. _debug2 DEPLOY_SSH_MULTI_CALL "$DEPLOY_SSH_MULTI_CALL"
  92. if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
  93. Le_Deploy_ssh_multi_call="yes"
  94. _savedomainconf Le_Deploy_ssh_multi_call "$Le_Deploy_ssh_multi_call"
  95. elif [ "$DEPLOY_SSH_MULTI_CALL" = "no" ]; then
  96. Le_Deploy_ssh_multi_call=""
  97. _cleardomainconf Le_Deploy_ssh_multi_call
  98. fi
  99. _deploy_ssh_servers=$Le_Deploy_ssh_server
  100. for Le_Deploy_ssh_server in $_deploy_ssh_servers; do
  101. _ssh_deploy
  102. done
  103. }
  104. _ssh_deploy() {
  105. _err_code=0
  106. _cmdstr=""
  107. _backupprefix=""
  108. _backupdir=""
  109. _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server"
  110. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  111. _info "Using MULTI_CALL mode... Required commands sent in multiple calls to remote host"
  112. else
  113. _info "Required commands batched and sent in single call to remote host"
  114. fi
  115. if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
  116. _backupprefix="$Le_Deploy_ssh_backup_path/$_cdomain-backup"
  117. _backupdir="$_backupprefix-$(_utc_date | tr ' ' '-')"
  118. # run cleanup on the backup directory, erase all older
  119. # than 180 days (15552000 seconds).
  120. _cmdstr="{ now=\"\$(date -u +%s)\"; for fn in $_backupprefix*; \
  121. do if [ -d \"\$fn\" ] && [ \"\$(expr \$now - \$(date -ur \$fn +%s) )\" -ge \"15552000\" ]; \
  122. then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; done; }; $_cmdstr"
  123. # Alternate version of above... _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf; $_cmdstr"
  124. # Create our backup directory for overwritten cert files.
  125. _cmdstr="mkdir -p $_backupdir; $_cmdstr"
  126. _info "Backup of old certificate files will be placed in remote directory $_backupdir"
  127. _info "Backup directories erased after 180 days."
  128. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  129. if ! _ssh_remote_cmd "$_cmdstr"; then
  130. return $_err_code
  131. fi
  132. _cmdstr=""
  133. fi
  134. fi
  135. # KEYFILE is optional.
  136. # If provided then private key will be copied to provided filename.
  137. _getdeployconf DEPLOY_SSH_KEYFILE
  138. _debug2 DEPLOY_SSH_KEYFILE "$DEPLOY_SSH_KEYFILE"
  139. if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
  140. Le_Deploy_ssh_keyfile="$DEPLOY_SSH_KEYFILE"
  141. _savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile"
  142. fi
  143. if [ -n "$Le_Deploy_ssh_keyfile" ]; then
  144. if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
  145. # backup file we are about to overwrite.
  146. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir >/dev/null;"
  147. fi
  148. # copy new certificate into file.
  149. _cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile;"
  150. _info "will copy private key to remote file $Le_Deploy_ssh_keyfile"
  151. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  152. if ! _ssh_remote_cmd "$_cmdstr"; then
  153. return $_err_code
  154. fi
  155. _cmdstr=""
  156. fi
  157. fi
  158. # CERTFILE is optional.
  159. # If provided then certificate will be copied or appended to provided filename.
  160. _getdeployconf DEPLOY_SSH_CERTFILE
  161. _debug2 DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
  162. if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
  163. Le_Deploy_ssh_certfile="$DEPLOY_SSH_CERTFILE"
  164. _savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile"
  165. fi
  166. if [ -n "$Le_Deploy_ssh_certfile" ]; then
  167. _pipe=">"
  168. if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then
  169. # if filename is same as previous file then append.
  170. _pipe=">>"
  171. elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
  172. # backup file we are about to overwrite.
  173. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir >/dev/null;"
  174. fi
  175. # copy new certificate into file.
  176. _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile;"
  177. _info "will copy certificate to remote file $Le_Deploy_ssh_certfile"
  178. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  179. if ! _ssh_remote_cmd "$_cmdstr"; then
  180. return $_err_code
  181. fi
  182. _cmdstr=""
  183. fi
  184. fi
  185. # CAFILE is optional.
  186. # If provided then CA intermediate certificate will be copied or appended to provided filename.
  187. _getdeployconf DEPLOY_SSH_CAFILE
  188. _debug2 DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
  189. if [ -n "$DEPLOY_SSH_CAFILE" ]; then
  190. Le_Deploy_ssh_cafile="$DEPLOY_SSH_CAFILE"
  191. _savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile"
  192. fi
  193. if [ -n "$Le_Deploy_ssh_cafile" ]; then
  194. _pipe=">"
  195. if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] ||
  196. [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then
  197. # if filename is same as previous file then append.
  198. _pipe=">>"
  199. elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
  200. # backup file we are about to overwrite.
  201. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir >/dev/null;"
  202. fi
  203. # copy new certificate into file.
  204. _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile;"
  205. _info "will copy CA file to remote file $Le_Deploy_ssh_cafile"
  206. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  207. if ! _ssh_remote_cmd "$_cmdstr"; then
  208. return $_err_code
  209. fi
  210. _cmdstr=""
  211. fi
  212. fi
  213. # FULLCHAIN is optional.
  214. # If provided then fullchain certificate will be copied or appended to provided filename.
  215. _getdeployconf DEPLOY_SSH_FULLCHAIN
  216. _debug2 DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
  217. if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then
  218. Le_Deploy_ssh_fullchain="$DEPLOY_SSH_FULLCHAIN"
  219. _savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain"
  220. fi
  221. if [ -n "$Le_Deploy_ssh_fullchain" ]; then
  222. _pipe=">"
  223. if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] ||
  224. [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] ||
  225. [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then
  226. # if filename is same as previous file then append.
  227. _pipe=">>"
  228. elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
  229. # backup file we are about to overwrite.
  230. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir >/dev/null;"
  231. fi
  232. # copy new certificate into file.
  233. _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain;"
  234. _info "will copy fullchain to remote file $Le_Deploy_ssh_fullchain"
  235. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  236. if ! _ssh_remote_cmd "$_cmdstr"; then
  237. return $_err_code
  238. fi
  239. _cmdstr=""
  240. fi
  241. fi
  242. # REMOTE_CMD is optional.
  243. # If provided then this command will be executed on remote host.
  244. _getdeployconf DEPLOY_SSH_REMOTE_CMD
  245. _debug2 DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
  246. if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
  247. Le_Deploy_ssh_remote_cmd="$DEPLOY_SSH_REMOTE_CMD"
  248. _savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd"
  249. fi
  250. if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then
  251. _cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd;"
  252. _info "Will execute remote command $Le_Deploy_ssh_remote_cmd"
  253. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  254. if ! _ssh_remote_cmd "$_cmdstr"; then
  255. return $_err_code
  256. fi
  257. _cmdstr=""
  258. fi
  259. fi
  260. # if commands not all sent in multiple calls then all commands sent in a single SSH call now...
  261. if [ -n "$_cmdstr" ]; then
  262. if ! _ssh_remote_cmd "$_cmdstr"; then
  263. return $_err_code
  264. fi
  265. fi
  266. return 0
  267. }
  268. #cmd
  269. _ssh_remote_cmd() {
  270. _cmd="$1"
  271. _secure_debug "Remote commands to execute: $_cmd"
  272. _info "Submitting sequence of commands to remote server by ssh"
  273. # quotations in bash cmd below intended. Squash travis spellcheck error
  274. # shellcheck disable=SC2029
  275. $Le_Deploy_ssh_cmd "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmd'"
  276. _err_code="$?"
  277. if [ "$_err_code" != "0" ]; then
  278. _err "Error code $_err_code returned from ssh"
  279. fi
  280. return $_err_code
  281. }