Add password authentication for SSH
This commit is contained in:
parent
4f3d83f458
commit
3d3fbbcbd9
@ -55,7 +55,7 @@ It's possible to use a remote server as destination for the backup. Just use the
|
|||||||
For this to work, rsync must be installed on the server too.
|
For this to work, rsync must be installed on the server too.
|
||||||
|
|
||||||
### Server authentication
|
### Server authentication
|
||||||
Right now only authentication using SSH key works. The best way to handle the authentication is to have an ssh agent running on your system, otherwise if a passphrase is necessary to unlock the ssh key, it will be necessary to enter it more than once.
|
The best way to handle the authentication is to have an ssh agent running on your system, otherwise if a passphrase is necessary to unlock the ssh key, it will be necessary to enter it more than once.
|
||||||
If needed, it's possible to specify the ssh key location with the --keyfile argument or in the configuration file.
|
If needed, it's possible to specify the ssh key location with the --keyfile argument or in the configuration file.
|
||||||
|
|
||||||
To be able to connect to the user's ssh agent when running simple_backup with sudo, make sure to preserve the SSH_AUTH_SOCK environment variable. For example:
|
To be able to connect to the user's ssh agent when running simple_backup with sudo, make sure to preserve the SSH_AUTH_SOCK environment variable. For example:
|
||||||
@ -65,3 +65,4 @@ sudo --preserve-env=SSH_AUTH_SOCK -s simple_backup [options]
|
|||||||
```
|
```
|
||||||
|
|
||||||
or by editing the sudoers file.
|
or by editing the sudoers file.
|
||||||
|
If SSH key authentication is not available, password authentication will be used instead.
|
||||||
|
@ -28,11 +28,13 @@ simple_backup \- Backup files and folders using rsync
|
|||||||
.RE
|
.RE
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.BR simple_backup
|
.BR simple_backup
|
||||||
is a python script for performing backup of files and folders. It uses rsync to copy the files
|
is a python script for performing backup of files and folders.
|
||||||
to the specified location. Parameters for the backup such as input files/directories, output
|
.P
|
||||||
location and files or folders to exclude can be specified
|
It uses rsync to copy the files to the specified location. Parameters for the backup such as
|
||||||
|
input files/directories, output location and files or folders to exclude can be specified
|
||||||
in a configuration file (default location $HOME/.config/simple_backup/simple_backup.conf)
|
in a configuration file (default location $HOME/.config/simple_backup/simple_backup.conf)
|
||||||
or directly on the command line.
|
or directly on the command line.
|
||||||
|
.P
|
||||||
Parameters specified on the command line will override those in the configuration file.
|
Parameters specified on the command line will override those in the configuration file.
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
@ -61,7 +63,7 @@ Specify how many old backups (so excluding the current one) will be kept. The de
|
|||||||
is to keep them all (same as N=\-1)
|
is to keep them all (same as N=\-1)
|
||||||
.TP
|
.TP
|
||||||
.B \-\-host HOSTNAME
|
.B \-\-host HOSTNAME
|
||||||
Hostname of the server where to copy the files in case of remote backup through ssh
|
Hostname of the server where to copy the files in case of remote backup through SSH
|
||||||
.TP
|
.TP
|
||||||
.B \-u, \-\-username USERNAME
|
.B \-u, \-\-username USERNAME
|
||||||
Username for connecting to the server in case of remote backup
|
Username for connecting to the server in case of remote backup
|
||||||
@ -88,10 +90,38 @@ Copy it to the default location ($HOME/.config/simple_backup) and edit it as nee
|
|||||||
It is possible to choose a directory on a remote server as destination for the backup. The files
|
It is possible to choose a directory on a remote server as destination for the backup. The files
|
||||||
are copied by rsync through SSH. Server hostname and username must be specified, either in the
|
are copied by rsync through SSH. Server hostname and username must be specified, either in the
|
||||||
configuration file, or on the command line (\(aq\-\-host\(aq and \(aq\-\-username\(aq options).
|
configuration file, or on the command line (\(aq\-\-host\(aq and \(aq\-\-username\(aq options).
|
||||||
Currently only authentication with SSH key has been tested. The easiest way to connect to the
|
.SS AUTHENTICATION
|
||||||
server is to use an ssh agent. Otherwise, if the SSH key is encrypted, it will be necessary
|
For authentication, it is possible to use SSH key or password.
|
||||||
to enter the passphrase more than once. It is possible to specify the SSH key to use with the
|
.P
|
||||||
option \(aq\-\-keyfile\(aq, if necessary.
|
When using SSH key, the best way to connect to the server is to have an SSH agent running.
|
||||||
|
Otherwise, if the SSH key is encrypted, it will be necessary to enter the passphrase more
|
||||||
|
than once. It is possible to specify the SSH key to use with the option \(aq\-\-keyfile\(aq,
|
||||||
|
if necessary.
|
||||||
|
.P
|
||||||
|
When running
|
||||||
|
.B simple_backup
|
||||||
|
with
|
||||||
|
.B sudo,
|
||||||
|
in order to connect to the user\(aq s SSH agent it is necessary to preserve the \(aq SSH_AUTH_SOCK\(aq environment variable, for example:
|
||||||
|
.P
|
||||||
|
.EX
|
||||||
|
sudo --preserve-env=SSH_AUTH_SOCK -s simple_backup [options]
|
||||||
|
.EE
|
||||||
|
.P
|
||||||
|
It is also possible to make this permanent by editing the
|
||||||
|
.B sudoers
|
||||||
|
file (see
|
||||||
|
.B sudoers (5)
|
||||||
|
)
|
||||||
|
.P
|
||||||
|
If SSH key authentication is not available, password authentication will be used instead.
|
||||||
|
Note that in this case
|
||||||
|
.B sshpass
|
||||||
|
(if available) will be used to send the password to rsync, to avoid prompting the user for
|
||||||
|
the password multiple
|
||||||
|
times. This can pose some security risks, see
|
||||||
|
.B sshpass (1)
|
||||||
|
for details. For this reason, use SSH key authentication if possible.
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.BR rsync (1)
|
.BR rsync (1)
|
||||||
.SH AUTHORS
|
.SH AUTHORS
|
||||||
|
@ -10,13 +10,12 @@ Classes:
|
|||||||
MyFormatter
|
MyFormatter
|
||||||
Backup
|
Backup
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Import libraries
|
# Import libraries
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import warnings
|
import warnings
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from shutil import rmtree
|
from shutil import rmtree, which
|
||||||
import shlex
|
import shlex
|
||||||
import argparse
|
import argparse
|
||||||
import configparser
|
import configparser
|
||||||
@ -155,6 +154,8 @@ class Backup:
|
|||||||
self._remote = None
|
self._remote = None
|
||||||
self._err_flag = False
|
self._err_flag = False
|
||||||
self._ssh = None
|
self._ssh = None
|
||||||
|
self._password_auth = False
|
||||||
|
self._password = None
|
||||||
|
|
||||||
def check_params(self):
|
def check_params(self):
|
||||||
"""Check if parameters for the backup are valid"""
|
"""Check if parameters for the backup are valid"""
|
||||||
@ -325,13 +326,22 @@ class Backup:
|
|||||||
except paramiko.SSHException:
|
except paramiko.SSHException:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
pkey = None
|
|
||||||
password = None
|
|
||||||
|
|
||||||
if self.ssh_keyfile is None:
|
if self.ssh_keyfile is None:
|
||||||
logger.critical('Can\'t connect to the server. No authentication method available')
|
try:
|
||||||
|
password = getpass(f'{self.username}@{self.host}\'s password: ')
|
||||||
|
ssh.connect(self.host, username=self.username, password=password)
|
||||||
|
|
||||||
return None
|
self._password_auth = True
|
||||||
|
os.environ['SSHPASS'] = password
|
||||||
|
|
||||||
|
return ssh
|
||||||
|
except paramiko.SSHException as e:
|
||||||
|
logger.critical('Can\'t connect to the server.')
|
||||||
|
logger.critical(e)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
pkey = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
pkey = RSAKey.from_private_key_file(self.ssh_keyfile)
|
pkey = RSAKey.from_private_key_file(self.ssh_keyfile)
|
||||||
@ -427,12 +437,16 @@ class Backup:
|
|||||||
|
|
||||||
if euid == 0 and self.ssh_keyfile is not None:
|
if euid == 0 and self.ssh_keyfile is not None:
|
||||||
rsync = f'{rsync} -e \'ssh -i {self.ssh_keyfile}\''
|
rsync = f'{rsync} -e \'ssh -i {self.ssh_keyfile}\''
|
||||||
|
elif self._password_auth and which('sshpass'):
|
||||||
|
rsync = f'{rsync} -e \'sshpass -e ssh -l {self.username}\''
|
||||||
|
|
||||||
args = shlex.split(rsync)
|
args = shlex.split(rsync)
|
||||||
|
|
||||||
with Popen(args, stdin=PIPE, stdout=PIPE, stderr=STDOUT, shell=False) as p:
|
with Popen(args, stdin=PIPE, stdout=PIPE, stderr=STDOUT, shell=False) as p:
|
||||||
output, _ = p.communicate()
|
output, _ = p.communicate()
|
||||||
|
|
||||||
|
del os.environ['SSHPASS']
|
||||||
|
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
self._err_flag = True
|
self._err_flag = True
|
||||||
|
|
||||||
@ -444,7 +458,7 @@ class Backup:
|
|||||||
logger.info('rsync: %s', output[-3])
|
logger.info('rsync: %s', output[-3])
|
||||||
logger.info('rsync: %s', output[-2])
|
logger.info('rsync: %s', output[-2])
|
||||||
|
|
||||||
if self._remote:
|
if self._remote and not self._err_flag:
|
||||||
_, stdout, _ = \
|
_, stdout, _ = \
|
||||||
self._ssh.exec_command(f'if [ -L "{self.output}/simple_backup/last_backup" ]; then echo "ok"; fi')
|
self._ssh.exec_command(f'if [ -L "{self.output}/simple_backup/last_backup" ]; then echo "ok"; fi')
|
||||||
|
|
||||||
@ -458,7 +472,7 @@ class Backup:
|
|||||||
if err != '':
|
if err != '':
|
||||||
logger.error(err)
|
logger.error(err)
|
||||||
self._err_flag = True
|
self._err_flag = True
|
||||||
else:
|
elif not self._err_flag:
|
||||||
if os.path.islink(f'{self.output}/simple_backup/last_backup'):
|
if os.path.islink(f'{self.output}/simple_backup/last_backup'):
|
||||||
try:
|
try:
|
||||||
os.remove(f'{self.output}/simple_backup/last_backup')
|
os.remove(f'{self.output}/simple_backup/last_backup')
|
||||||
@ -478,7 +492,7 @@ class Backup:
|
|||||||
if err != '':
|
if err != '':
|
||||||
logger.error(err)
|
logger.error(err)
|
||||||
self._err_flag = True
|
self._err_flag = True
|
||||||
elif not self._remote:
|
elif not self._err_flag:
|
||||||
try:
|
try:
|
||||||
os.symlink(self._output_dir, f'{self.output}/simple_backup/last_backup', target_is_directory=True)
|
os.symlink(self._output_dir, f'{self.output}/simple_backup/last_backup', target_is_directory=True)
|
||||||
except FileExistsError:
|
except FileExistsError:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user