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.

456 lines
16 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
8 years ago
8 years ago
5 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_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. # export DEPLOY_SSH_USE_SCP="" yes or no , default to no
  26. # export DEPLOY_SSH_SCP_CMD="" defaults to "scp -T -q "
  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. if [ -f "$DOMAIN_CONF" ]; then
  38. # shellcheck disable=SC1090
  39. . "$DOMAIN_CONF"
  40. fi
  41. _debug _cdomain "$_cdomain"
  42. _debug _ckey "$_ckey"
  43. _debug _ccert "$_ccert"
  44. _debug _cca "$_cca"
  45. _debug _cfullchain "$_cfullchain"
  46. # USER is required to login by SSH to remote host.
  47. if [ -z "$DEPLOY_SSH_USER" ]; then
  48. if [ -z "$Le_Deploy_ssh_user" ]; then
  49. _err "DEPLOY_SSH_USER not defined."
  50. return 1
  51. fi
  52. else
  53. Le_Deploy_ssh_user="$DEPLOY_SSH_USER"
  54. _savedomainconf Le_Deploy_ssh_user "$Le_Deploy_ssh_user"
  55. fi
  56. # SERVER is optional. If not provided then use _cdomain
  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. 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. # USE_SCP is optional. If not provided then default to previously saved
  71. # value (which may be undefined... equivalent to "no").
  72. if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
  73. Le_Deploy_ssh_use_scp="yes"
  74. _savedomainconf Le_Deploy_ssh_use_scp "$Le_Deploy_ssh_use_scp"
  75. elif [ "$DEPLOY_SSH_USE_SCP" = "no" ]; then
  76. Le_Deploy_ssh_use_scp=""
  77. _cleardomainconf Le_Deploy_ssh_use_scp
  78. fi
  79. # SCP_CMD is optional. If not provided then use scp
  80. if [ -n "$DEPLOY_SSH_SCP_CMD" ]; then
  81. Le_Deploy_ssh_scp_cmd="$DEPLOY_SSH_SCP_CMD"
  82. _savedomainconf Le_Deploy_ssh_scp_cmd "$Le_Deploy_ssh_scp_cmd"
  83. elif [ -z "$Le_Deploy_ssh_scp_cmd" ]; then
  84. Le_Deploy_ssh_scp_cmd="scp -T"
  85. fi
  86. # BACKUP is optional. If not provided then default to previously saved value or yes.
  87. if [ "$DEPLOY_SSH_BACKUP" = "no" ]; then
  88. Le_Deploy_ssh_backup="no"
  89. elif [ -z "$Le_Deploy_ssh_backup" ] || [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
  90. Le_Deploy_ssh_backup="yes"
  91. fi
  92. _savedomainconf Le_Deploy_ssh_backup "$Le_Deploy_ssh_backup"
  93. # BACKUP_PATH is optional. If not provided then default to previously saved value or .acme_ssh_deploy
  94. if [ -n "$DEPLOY_SSH_BACKUP_PATH" ]; then
  95. Le_Deploy_ssh_backup_path="$DEPLOY_SSH_BACKUP_PATH"
  96. elif [ -z "$Le_Deploy_ssh_backup_path" ]; then
  97. Le_Deploy_ssh_backup_path=".acme_ssh_deploy"
  98. fi
  99. _savedomainconf Le_Deploy_ssh_backup_path "$Le_Deploy_ssh_backup_path"
  100. # MULTI_CALL is optional. If not provided then default to previously saved
  101. # value (which may be undefined... equivalent to "no").
  102. if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
  103. Le_Deploy_ssh_multi_call="yes"
  104. _savedomainconf Le_Deploy_ssh_multi_call "$Le_Deploy_ssh_multi_call"
  105. elif [ "$DEPLOY_SSH_MULTI_CALL" = "no" ]; then
  106. Le_Deploy_ssh_multi_call=""
  107. _cleardomainconf Le_Deploy_ssh_multi_call
  108. fi
  109. # USE_SCP is optional. If not provided then default to previously saved
  110. # value (which may be undefined... equivalent to "no").
  111. if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
  112. Le_Deploy_ssh_use_scp="yes"
  113. _savedomainconf Le_Deploy_ssh_use_scp "$Le_Deploy_ssh_use_scp"
  114. Le_Deploy_ssh_multi_call="yes"
  115. _savedomainconf Le_Deploy_ssh_multi_call "$Le_Deploy_ssh_multi_call"
  116. elif [ "$DEPLOY_SSH_USE_SCP" = "no" ]; then
  117. Le_Deploy_ssh_use_scp=""
  118. _cleardomainconf Le_Deploy_ssh_use_scp
  119. fi
  120. # SCP_CMD is optional. If not provided then use scp
  121. if [ -n "$DEPLOY_SSH_SCP_CMD" ]; then
  122. Le_Deploy_ssh_scp_cmd="$DEPLOY_SSH_SCP_CMD"
  123. _savedomainconf Le_Deploy_ssh_scp_cmd "$Le_Deploy_ssh_scp_cmd"
  124. elif [ -z "$Le_Deploy_ssh_scp_cmd" ]; then
  125. Le_Deploy_ssh_scp_cmd="scp -T -q "
  126. fi
  127. _deploy_ssh_servers=$Le_Deploy_ssh_server
  128. for Le_Deploy_ssh_server in $_deploy_ssh_servers; do
  129. _ssh_deploy
  130. done
  131. }
  132. _ssh_deploy() {
  133. _err_code=0
  134. _cmdstr=""
  135. _backupprefix=""
  136. _backupdir=""
  137. _local_cert_file=""
  138. _local_ca_file=""
  139. _local_full_file=""
  140. _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server"
  141. if [ "$Le_Deploy_ssh_use_scp" = "yes" ]; then
  142. _info "Using scp as alternate method for copying files. Multicall Mode is implicit"
  143. Le_Deploy_ssh_multi_call="yes"
  144. _savedomainconf Le_Deploy_ssh_multi_call "$Le_Deploy_ssh_multi_call"
  145. fi
  146. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  147. _info "Using MULTI_CALL mode... Required commands sent in multiple calls to remote host"
  148. else
  149. _info "Required commands batched and sent in single call to remote host"
  150. fi
  151. if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
  152. _backupprefix="$Le_Deploy_ssh_backup_path/$_cdomain-backup"
  153. _backupdir="$_backupprefix-$(_utc_date | tr ' ' '-')"
  154. # run cleanup on the backup directory, erase all older
  155. # than 180 days (15552000 seconds).
  156. _cmdstr="{ now=\"\$(date -u +%s)\"; for fn in $_backupprefix*; \
  157. do if [ -d \"\$fn\" ] && [ \"\$(expr \$now - \$(date -ur \$fn +%s) )\" -ge \"15552000\" ]; \
  158. then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; done; }; $_cmdstr"
  159. # Alternate version of above... _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf; $_cmdstr"
  160. # Create our backup directory for overwritten cert files.
  161. _cmdstr="mkdir -p $_backupdir; $_cmdstr"
  162. _info "Backup of old certificate files will be placed in remote directory $_backupdir"
  163. _info "Backup directories erased after 180 days."
  164. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  165. if ! _ssh_remote_cmd "$_cmdstr"; then
  166. return $_err_code
  167. fi
  168. _cmdstr=""
  169. fi
  170. fi
  171. # KEYFILE is optional.
  172. # If provided then private key will be copied to provided filename.
  173. if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
  174. Le_Deploy_ssh_keyfile="$DEPLOY_SSH_KEYFILE"
  175. _savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile"
  176. fi
  177. if [ -n "$Le_Deploy_ssh_keyfile" ]; then
  178. if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
  179. # backup file we are about to overwrite.
  180. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir >/dev/null;"
  181. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  182. if ! _ssh_remote_cmd "$_cmdstr"; then
  183. return $_err_code
  184. fi
  185. _cmdstr=""
  186. fi
  187. fi
  188. # copy new key into file.
  189. if [ "$Le_Deploy_ssh_use_scp" = "yes" ]; then
  190. # scp the file
  191. if ! _scp_remote_cmd "$_ckey" "$Le_Deploy_ssh_keyfile"; then
  192. return $_err_code
  193. fi
  194. else
  195. _cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile;"
  196. _info "will copy private key to remote file $Le_Deploy_ssh_keyfile"
  197. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  198. if ! _ssh_remote_cmd "$_cmdstr"; then
  199. return $_err_code
  200. fi
  201. _cmdstr=""
  202. fi
  203. fi
  204. fi
  205. # CERTFILE is optional.
  206. # If provided then certificate will be copied or appended to provided filename.
  207. if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
  208. Le_Deploy_ssh_certfile="$DEPLOY_SSH_CERTFILE"
  209. _savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile"
  210. fi
  211. if [ -n "$Le_Deploy_ssh_certfile" ]; then
  212. _pipe=">"
  213. if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then
  214. # if filename is same as previous file then append.
  215. _pipe=">>"
  216. _local_cert_file=$(_mktemp)
  217. cat "$_ckey" >"$_local_cert_file"
  218. cat "$_ccert" >>"$_local_cert_file"
  219. elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
  220. # backup file we are about to overwrite.
  221. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir >/dev/null;"
  222. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  223. if ! _ssh_remote_cmd "$_cmdstr"; then
  224. return $_err_code
  225. fi
  226. _cmdstr=""
  227. fi
  228. fi
  229. if [ "$Le_Deploy_ssh_use_scp" = "yes" ]; then
  230. if [ -n "$_local_cert_file" ]; then
  231. if ! _scp_remote_cmd "$_local_cert_file" "$Le_Deploy_ssh_certfile"; then
  232. return $_err_code
  233. fi
  234. else
  235. if ! _scp_remote_cmd "$_ccert" "$Le_Deploy_ssh_certfile"; then
  236. return $_err_code
  237. fi
  238. fi
  239. else
  240. # copy new certificate into file.
  241. _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile;"
  242. _info "will copy certificate to remote file $Le_Deploy_ssh_certfile"
  243. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  244. if ! _ssh_remote_cmd "$_cmdstr"; then
  245. return $_err_code
  246. fi
  247. _cmdstr=""
  248. fi
  249. fi
  250. fi
  251. # CAFILE is optional.
  252. # If provided then CA intermediate certificate will be copied or appended to provided filename.
  253. if [ -n "$DEPLOY_SSH_CAFILE" ]; then
  254. Le_Deploy_ssh_cafile="$DEPLOY_SSH_CAFILE"
  255. _savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile"
  256. fi
  257. if [ -n "$Le_Deploy_ssh_cafile" ]; then
  258. _pipe=">"
  259. if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] ||
  260. [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then
  261. # if filename is same as previous file then append.
  262. _pipe=">>"
  263. _local_ca_file=$(_mktemp)
  264. if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ]; then
  265. cat "$_ckey" >>"$_local_ca_file"
  266. fi
  267. if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then
  268. cat "$_ccert" >>"$_local_ca_file"
  269. fi
  270. cat "$_cca" >>"$_local_ca_file"
  271. elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
  272. # backup file we are about to overwrite.
  273. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir >/dev/null;"
  274. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  275. if ! _ssh_remote_cmd "$_cmdstr"; then
  276. return $_err_code
  277. fi
  278. _cmdstr=""
  279. fi
  280. fi
  281. if [ "$Le_Deploy_ssh_use_scp" = "yes" ]; then
  282. if [ -n "$_local_ca_file" ]; then
  283. if ! _scp_remote_cmd "$_local_ca_file" "$Le_Deploy_ssh_cafile"; then
  284. return $_err_code
  285. fi
  286. else
  287. if ! _scp_remote_cmd "$_cca" "$Le_Deploy_ssh_cafile"; then
  288. return $_err_code
  289. fi
  290. fi
  291. else
  292. # copy new certificate into file.
  293. _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile;"
  294. _info "will copy CA file to remote file $Le_Deploy_ssh_cafile"
  295. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  296. if ! _ssh_remote_cmd "$_cmdstr"; then
  297. return $_err_code
  298. fi
  299. _cmdstr=""
  300. fi
  301. fi
  302. fi
  303. # FULLCHAIN is optional.
  304. # If provided then fullchain certificate will be copied or appended to provided filename.
  305. if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then
  306. Le_Deploy_ssh_fullchain="$DEPLOY_SSH_FULLCHAIN"
  307. _savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain"
  308. fi
  309. if [ -n "$Le_Deploy_ssh_fullchain" ]; then
  310. _pipe=">"
  311. if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] ||
  312. [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] ||
  313. [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then
  314. # if filename is same as previous file then append.
  315. _pipe=">>"
  316. _local_full_file=$(_mktemp)
  317. if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ]; then
  318. cat "$_ckey" >>"$_local_full_file"
  319. fi
  320. if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ]; then
  321. cat "$_ccert" >>"$_local_full_file"
  322. fi
  323. if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then
  324. cat "$_cca" >>"$_local_full_file"
  325. fi
  326. cat "$_cfullchain" >>"$_local_full_file"
  327. elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
  328. # backup file we are about to overwrite.
  329. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir >/dev/null;"
  330. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  331. if ! _ssh_remote_cmd "$_cmdstr"; then
  332. return $_err_code
  333. fi
  334. _cmdstr=""
  335. fi
  336. fi
  337. if [ "$Le_Deploy_ssh_use_scp" = "yes" ]; then
  338. if [ -n "$_local_full_file" ]; then
  339. if ! _scp_remote_cmd "$_local_full_file" "$Le_Deploy_ssh_fullchain"; then
  340. return $_err_code
  341. fi
  342. else
  343. if ! _scp_remote_cmd "$_cfullchain" "$Le_Deploy_ssh_fullchain"; then
  344. return $_err_code
  345. fi
  346. fi
  347. else
  348. # copy new certificate into file.
  349. _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain;"
  350. _info "will copy fullchain to remote file $Le_Deploy_ssh_fullchain"
  351. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  352. if ! _ssh_remote_cmd "$_cmdstr"; then
  353. return $_err_code
  354. fi
  355. _cmdstr=""
  356. fi
  357. fi
  358. fi
  359. # cleanup local files if any
  360. if [ -n "$_local_cert_file" ]; then
  361. rm "$_local_cert_file" >/dev/null 1>&2
  362. fi
  363. if [ -n "$_local_ca_file" ]; then
  364. rm "$_local_ca_file" >/dev/null 1>&2
  365. fi
  366. if [ -n "$_local_full_file" ]; then
  367. rm "$_local_full_file" >/dev/null 1>&2
  368. fi
  369. # REMOTE_CMD is optional.
  370. # If provided then this command will be executed on remote host.
  371. if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
  372. Le_Deploy_ssh_remote_cmd="$DEPLOY_SSH_REMOTE_CMD"
  373. _savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd"
  374. fi
  375. if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then
  376. _cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd;"
  377. _info "Will execute remote command $Le_Deploy_ssh_remote_cmd"
  378. if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
  379. if ! _ssh_remote_cmd "$_cmdstr"; then
  380. return $_err_code
  381. fi
  382. _cmdstr=""
  383. fi
  384. fi
  385. # if commands not all sent in multiple calls then all commands sent in a single SSH call now...
  386. if [ -n "$_cmdstr" ]; then
  387. if ! _ssh_remote_cmd "$_cmdstr"; then
  388. return $_err_code
  389. fi
  390. fi
  391. # cleanup in case all is ok
  392. return 0
  393. }
  394. #cmd
  395. _ssh_remote_cmd() {
  396. _cmd="$1"
  397. _secure_debug "Remote commands to execute: $_cmd"
  398. _info "Submitting sequence of commands to remote server by ssh"
  399. # quotations in bash cmd below intended. Squash travis spellcheck error
  400. # shellcheck disable=SC2029
  401. $Le_Deploy_ssh_cmd "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmd'"
  402. _err_code="$?"
  403. if [ "$_err_code" != "0" ]; then
  404. _err "Error code $_err_code returned from ssh"
  405. fi
  406. return $_err_code
  407. }
  408. # cmd scp
  409. _scp_remote_cmd() {
  410. _secure_debug "Remote scp source $1 and destination $2 using : $Le_Deploy_ssh_scp_cmd"
  411. _info "Submitting secure copy command : $Le_Deploy_ssh_scp_cmd"
  412. $Le_Deploy_ssh_scp_cmd "$1" "$Le_Deploy_ssh_user"@"$Le_Deploy_ssh_server":"$2"
  413. _err_code="$?"
  414. if [ "$_err_code" != "0" ]; then
  415. _err "Error code $_err_code returned from scp"
  416. fi
  417. return $_err_code
  418. }