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.

370 lines
14 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
5 years ago
8 years ago
8 years ago
8 years ago
5 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_SCP_CMD="" # defaults to "scp"
  16. # export DEPLOY_SSH_USER="admin" # required
  17. # export DEPLOY_SSH_SERVER="qnap" # defaults to domain name
  18. # export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem"
  19. # export DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem"
  20. # export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem"
  21. # export DEPLOY_SSH_FULLCHAIN=""
  22. # export DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart"
  23. # export DEPLOY_SSH_BACKUP="" # yes or no, default to yes or previously saved value
  24. # export DEPLOY_SSH_BACKUP_PATH=".acme_ssh_deploy" # path on remote system. Defaults to .acme_ssh_deploy
  25. # export DEPLOY_SSH_MULTI_CALL="" # yes or no, default to no or previously saved value
  26. # export DEPLOY_SSH_USE_SCP="" # yes or no, default to no or previously saved value
  27. #
  28. ######## Public functions #####################
  29. #domain keyfile certfile cafile fullchain
  30. ssh_deploy() {
  31. _cdomain="$1"
  32. _ckey="$2"
  33. _ccert="$3"
  34. _cca="$4"
  35. _cfullchain="$5"
  36. _deploy_ssh_servers=""
  37. _debug _cdomain "$_cdomain"
  38. _debug _ckey "$_ckey"
  39. _debug _ccert "$_ccert"
  40. _debug _cca "$_cca"
  41. _debug _cfullchain "$_cfullchain"
  42. # USER is required to login by SSH to remote host.
  43. _getdeployconf DEPLOY_SSH_USER
  44. _debug2 DEPLOY_SSH_USER "$DEPLOY_SSH_USER"
  45. if [ -z "$DEPLOY_SSH_USER" ]; then
  46. if [ -z "$Le_Deploy_ssh_user" ]; then
  47. _err "DEPLOY_SSH_USER not defined."
  48. return 1
  49. fi
  50. else
  51. Le_Deploy_ssh_user="$DEPLOY_SSH_USER"
  52. _savedomainconf Le_Deploy_ssh_user "$Le_Deploy_ssh_user"
  53. fi
  54. # SERVER is optional. If not provided then use _cdomain
  55. _getdeployconf DEPLOY_SSH_SERVER
  56. _debug2 DEPLOY_SSH_SERVER "$DEPLOY_SSH_SERVER"
  57. if [ -n "$DEPLOY_SSH_SERVER" ]; then
  58. Le_Deploy_ssh_server="$DEPLOY_SSH_SERVER"
  59. _savedomainconf Le_Deploy_ssh_server "$Le_Deploy_ssh_server"
  60. elif [ -z "$Le_Deploy_ssh_server" ]; then
  61. Le_Deploy_ssh_server="$_cdomain"
  62. fi
  63. # CMD is optional. If not provided then use ssh
  64. _getdeployconf DEPLOY_SSH_CMD
  65. _debug2 DEPLOY_SSH_CMD "$DEPLOY_SSH_CMD"
  66. if [ -n "$DEPLOY_SSH_CMD" ]; then
  67. Le_Deploy_ssh_cmd="$DEPLOY_SSH_CMD"
  68. _savedomainconf Le_Deploy_ssh_cmd "$Le_Deploy_ssh_cmd"
  69. elif [ -z "$Le_Deploy_ssh_cmd" ]; then
  70. Le_Deploy_ssh_cmd="ssh -T"
  71. fi
  72. # SCP_CMD is optional. If not provided then use scp
  73. _getdeployconf DEPLOY_SSH_SCP_CMD
  74. _debug2 DEPLOY_SSH_SCP_CMD "$DEPLOY_SSH_SCP_CMD"
  75. if [ -n "$DEPLOY_SSH_SCP_CMD" ]; then
  76. Le_Deploy_ssh_scp_cmd="$DEPLOY_SSH_SCP_CMD"
  77. _savedomainconf Le_Deploy_ssh_scp_cmd "$Le_Deploy_ssh_scp_cmd"
  78. elif [ -z "$Le_Deploy_ssh_scp_cmd" ]; then
  79. Le_Deploy_ssh_scp_cmd="scp"
  80. fi
  81. # BACKUP is optional. If not provided then default to previously saved value or yes.
  82. _getdeployconf DEPLOY_SSH_BACKUP
  83. _debug2 DEPLOY_SSH_BACKUP "$DEPLOY_SSH_BACKUP"
  84. if [ "$DEPLOY_SSH_BACKUP" = "no" ]; then
  85. Le_Deploy_ssh_backup="no"
  86. elif [ -z "$Le_Deploy_ssh_backup" ] || [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
  87. Le_Deploy_ssh_backup="yes"
  88. fi
  89. _savedomainconf Le_Deploy_ssh_backup "$Le_Deploy_ssh_backup"
  90. # BACKUP_PATH is optional. If not provided then default to previously saved value or .acme_ssh_deploy
  91. _getdeployconf DEPLOY_SSH_BACKUP_PATH
  92. _debug2 DEPLOY_SSH_BACKUP_PATH "$DEPLOY_SSH_BACKUP_PATH"
  93. if [ -n "$DEPLOY_SSH_BACKUP_PATH" ]; then
  94. Le_Deploy_ssh_backup_path="$DEPLOY_SSH_BACKUP_PATH"
  95. elif [ -z "$Le_Deploy_ssh_backup_path" ]; then
  96. Le_Deploy_ssh_backup_path=".acme_ssh_deploy"
  97. fi
  98. _savedomainconf Le_Deploy_ssh_backup_path "$Le_Deploy_ssh_backup_path"
  99. # MULTI_CALL is optional. If not provided then default to previously saved
  100. # value (which may be undefined... equivalent to "no").
  101. _getdeployconf DEPLOY_SSH_MULTI_CALL
  102. _debug2 DEPLOY_SSH_MULTI_CALL "$DEPLOY_SSH_MULTI_CALL"
  103. if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
  104. Le_Deploy_ssh_multi_call="yes"
  105. _savedomainconf Le_Deploy_ssh_multi_call "$Le_Deploy_ssh_multi_call"
  106. elif [ "$DEPLOY_SSH_MULTI_CALL" = "no" ]; then
  107. Le_Deploy_ssh_multi_call=""
  108. _cleardomainconf Le_Deploy_ssh_multi_call
  109. fi
  110. # USE_SCP is optional. If not provided then default to previously saved
  111. # value (which may be undefined... equivalent to "no").
  112. _getdeployconf DEPLOY_SSH_USE_SCP
  113. _debug2 DEPLOY_SSH_USE_SCP "$DEPLOY_SSH_USE_SCP"
  114. if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
  115. Le_Deploy_ssh_use_scp="yes"
  116. _sevedomainconf Le_deploy_ssh_use_scp "$Le_Deploy_ssh_use_scp"
  117. elif [ "$DEPLOY_SSH_USE_SCP" = "no" ]; then
  118. Le_Deploy_ssh_use_scp=""
  119. _cleardomainconf Le_Deploy_ssh_use_scp
  120. fi
  121. _deploy_ssh_servers=$Le_Deploy_ssh_server
  122. for Le_Deploy_ssh_server in $_deploy_ssh_servers; do
  123. _ssh_deploy
  124. done
  125. }
  126. _ssh_deploy() {
  127. _err_code=0
  128. _cmdstr=""
  129. _backupprefix=""
  130. _backupdir=""
  131. _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server"
  132. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  133. _info "Using MULTI_CALL mode... Required commands sent in multiple calls to remote host"
  134. else
  135. _info "Required commands batched and sent in single call to remote host"
  136. fi
  137. if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
  138. _backupprefix="$Le_Deploy_ssh_backup_path/$_cdomain-backup"
  139. _backupdir="$_backupprefix-$(_utc_date | tr ' ' '-')"
  140. # run cleanup on the backup directory, erase all older
  141. # than 180 days (15552000 seconds).
  142. _cmdstr="{ now=\"\$(date -u +%s)\"; for fn in $_backupprefix*; \
  143. do if [ -d \"\$fn\" ] && [ \"\$(expr \$now - \$(date -ur \$fn +%s) )\" -ge \"15552000\" ]; \
  144. then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; done; }; $_cmdstr"
  145. # Alternate version of above... _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf; $_cmdstr"
  146. # Create our backup directory for overwritten cert files.
  147. _cmdstr="mkdir -p $_backupdir; $_cmdstr"
  148. _info "Backup of old certificate files will be placed in remote directory $_backupdir"
  149. _info "Backup directories erased after 180 days."
  150. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  151. if ! _ssh_remote_cmd "$_cmdstr"; then
  152. return $_err_code
  153. fi
  154. _cmdstr=""
  155. fi
  156. fi
  157. # KEYFILE is optional.
  158. # If provided then private key will be copied to provided filename.
  159. _getdeployconf DEPLOY_SSH_KEYFILE
  160. _debug2 DEPLOY_SSH_KEYFILE "$DEPLOY_SSH_KEYFILE"
  161. if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
  162. Le_Deploy_ssh_keyfile="$DEPLOY_SSH_KEYFILE"
  163. _savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile"
  164. fi
  165. if [ -n "$Le_Deploy_ssh_keyfile" ]; then
  166. if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
  167. # backup file we are about to overwrite.
  168. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir >/dev/null;"
  169. fi
  170. if [ "$Le_Deploy_ssh_use_scp" != "yes" ]; then
  171. # copy new certificate into file.
  172. _cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile;"
  173. fi
  174. _info "will copy private key to remote file $Le_Deploy_ssh_keyfile"
  175. if [ "$Le_Deploy_ssh_use_scp" = "yes" -o "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  176. if ! _ssh_remote_cmd "$_cmdstr"; then
  177. return $_err_code
  178. fi
  179. _cmdstr=""
  180. if [ "$Le_Deploy_ssh_use_scp" = "yes" ]; then
  181. if ! _scp_remote_cmd "$_ckey" "$Le_Deploy_ssh_keyfile"; then
  182. return $_err_code
  183. fi
  184. fi
  185. fi
  186. fi
  187. # CERTFILE is optional.
  188. # If provided then certificate will be copied or appended to provided filename.
  189. _getdeployconf DEPLOY_SSH_CERTFILE
  190. _debug2 DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
  191. if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
  192. Le_Deploy_ssh_certfile="$DEPLOY_SSH_CERTFILE"
  193. _savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile"
  194. fi
  195. if [ -n "$Le_Deploy_ssh_certfile" ]; then
  196. _pipe=">"
  197. if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then
  198. # if filename is same as previous file then append.
  199. _pipe=">>"
  200. elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
  201. # backup file we are about to overwrite.
  202. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir >/dev/null;"
  203. fi
  204. if [ "$Le_Deploy_ssh_use_scp" != "yes" ]; then
  205. # copy new certificate into file.
  206. _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile;"
  207. fi
  208. _info "will copy certificate to remote file $Le_Deploy_ssh_certfile"
  209. if [ "$Le_Deploy_ssh_use_scp" = "yes" -o "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  210. if ! _ssh_remote_cmd "$_cmdstr"; then
  211. return $_err_code
  212. fi
  213. _cmdstr=""
  214. if [ "$Le_Deploy_ssh_use_scp" = "yes" ]; then
  215. if ! _scp_remote_cmd "$_ccert" "$Le_Deploy_ssh_certfile"; then
  216. return $_err_code
  217. fi
  218. fi
  219. fi
  220. fi
  221. # CAFILE is optional.
  222. # If provided then CA intermediate certificate will be copied or appended to provided filename.
  223. _getdeployconf DEPLOY_SSH_CAFILE
  224. _debug2 DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
  225. if [ -n "$DEPLOY_SSH_CAFILE" ]; then
  226. Le_Deploy_ssh_cafile="$DEPLOY_SSH_CAFILE"
  227. _savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile"
  228. fi
  229. if [ -n "$Le_Deploy_ssh_cafile" ]; then
  230. _pipe=">"
  231. if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] ||
  232. [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then
  233. # if filename is same as previous file then append.
  234. _pipe=">>"
  235. elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
  236. # backup file we are about to overwrite.
  237. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir >/dev/null;"
  238. fi
  239. if [ "$Le_Deploy_ssh_use_scp" != "yes" ]; then
  240. # copy new certificate into file.
  241. _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile;"
  242. fi
  243. _info "will copy CA file to remote file $Le_Deploy_ssh_cafile"
  244. if [ "$Le_Deploy_ssh_use_scp" = "yes" -o "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  245. if ! _ssh_remote_cmd "$_cmdstr"; then
  246. return $_err_code
  247. fi
  248. _cmdstr=""
  249. if [ "$Le_Deploy_ssh_use_scp" = "yes" ]; then
  250. if ! _scp_remote_cmd "$_cca" "$Le_Deploy_ssh_cafile"; then
  251. return $_err_code
  252. fi
  253. fi
  254. fi
  255. fi
  256. # FULLCHAIN is optional.
  257. # If provided then fullchain certificate will be copied or appended to provided filename.
  258. _getdeployconf DEPLOY_SSH_FULLCHAIN
  259. _debug2 DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
  260. if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then
  261. Le_Deploy_ssh_fullchain="$DEPLOY_SSH_FULLCHAIN"
  262. _savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain"
  263. fi
  264. if [ -n "$Le_Deploy_ssh_fullchain" ]; then
  265. _pipe=">"
  266. if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] ||
  267. [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] ||
  268. [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then
  269. # if filename is same as previous file then append.
  270. _pipe=">>"
  271. elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
  272. # backup file we are about to overwrite.
  273. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir >/dev/null;"
  274. fi
  275. if [ "$Le_Deploy_ssh_use_scp" != "yes" ]; then
  276. # copy new certificate into file.
  277. _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain;"
  278. fi
  279. _info "will copy fullchain to remote file $Le_Deploy_ssh_fullchain"
  280. if [ "$Le_Deploy_ssh_use_scp" = "yes" -o "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  281. if ! _ssh_remote_cmd "$_cmdstr"; then
  282. return $_err_code
  283. fi
  284. _cmdstr=""
  285. if [ "$Le_Deploy_ssh_use_scp" = "yes" ]; then
  286. if ! _scp_remote_cmd "$_cfullchain" "$Le_Deploy_ssh_fullchain"; then
  287. return $_err_code
  288. fi
  289. fi
  290. fi
  291. fi
  292. # REMOTE_CMD is optional.
  293. # If provided then this command will be executed on remote host.
  294. _getdeployconf DEPLOY_SSH_REMOTE_CMD
  295. _debug2 DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
  296. if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
  297. Le_Deploy_ssh_remote_cmd="$DEPLOY_SSH_REMOTE_CMD"
  298. _savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd"
  299. fi
  300. if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then
  301. _cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd;"
  302. _info "Will execute remote command $Le_Deploy_ssh_remote_cmd"
  303. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  304. if ! _ssh_remote_cmd "$_cmdstr"; then
  305. return $_err_code
  306. fi
  307. _cmdstr=""
  308. fi
  309. fi
  310. # if commands not all sent in multiple calls then all commands sent in a single SSH call now...
  311. if [ -n "$_cmdstr" ]; then
  312. if ! _ssh_remote_cmd "$_cmdstr"; then
  313. return $_err_code
  314. fi
  315. fi
  316. return 0
  317. }
  318. #cmd
  319. _ssh_remote_cmd() {
  320. _cmd="$1"
  321. _secure_debug "Remote commands to execute: $_cmd"
  322. _info "Submitting sequence of commands to remote server by ssh"
  323. # quotations in bash cmd below intended. Squash travis spellcheck error
  324. # shellcheck disable=SC2029
  325. $Le_Deploy_ssh_cmd "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmd'"
  326. _err_code="$?"
  327. if [ "$_err_code" != "0" ]; then
  328. _err "Error code $_err_code returned from ssh"
  329. fi
  330. return $_err_code
  331. }
  332. _scp_remote_cmd() {
  333. _src="$1"
  334. _dst="$2"
  335. _secure_debug "Scp commands to execute: src_file = $_src, dst_file = $_dst"
  336. _info "Copy file to remote server by scp"
  337. $Le_Deploy_ssh_scp_cmd "$_src" "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server:$_dst"
  338. _err_code="$?"
  339. if [ "$_err_code" != "0" ]; then
  340. _err "Error code $_err_code returned from scp"
  341. fi
  342. return $_err_code
  343. }