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