Rsync per poter impostare correttamente il modification time richiede di essere eseguito con l’utente PROPRIETARIO del file, in quanto il mtime è un attributo che richiede un access super user. Non basta avere l’accesso in scrittura per esempio tramite permessi 664/775 come gruppo.
Ovviamente non è consigliato utilizzare una connessione ssh tramite publickey per un utente che non è dotato di accesso shell come l’utente www-data. Per risolvere è necessario usare la connessione ssh tramite un utente dotato di accesso shell e chiave privata su entrambe le macchine, ed eseguire il comando rsync sulla macchina remota scalando i priviligi dall’utente che apre la connessione ssh all’utente www-data.
In questo modo la connessione ssh viene aperta dall’utente normale , e poi il comando ssh viene eseguito tramite sudo dall’utente normale come account di servizio www-data:
You have to differentiate 2 things:
- who establishes the SSH connection.
- which remote user owns the files that you want to copy.
Overview
(srcmachine) (rsync) (destmachine)
srcuser -- SSH --> destuser
|
| sudo su jenkins
|
v
jenkins
Let’s say that you want to rsync:
- From:
- Machine:
srcmachine
- User:
srcuser
- Directory:
/var/lib/jenkins
- Machine:
- To:
- Machine:
destmachine
- User:
destuser
to establish the SSH connection. - Directory:
/tmp
- Final files owner:
jenkins
.
- Machine:
Solution
rsync --rsync-path 'sudo -u jenkins rsync' -avP --delete /var/lib/jenkins destuser@destmachine:/tmp
Solution with rsa key pair
rsync --rsync-path 'sudo -u jenkins rsync' -avP --delete -e "ssh -i ~/.ssh/id_rsa" /var/lib/jenkins destuser@destmachine:/tmp
Explanations
--rsync-path=PROGRAM specify the rsync to run on the remote machine
The trick is to tell to run rsync
on the remote machine with another user (jenkins
) than the one who establishes the SSH connection (destuser
).
Requirements
SSH access
(srcmachine) (rsync) (destmachine)
srcuser -- SSH --> destuser
[~/.ssh/id_rsa] [~/.ssh/authorized_keys] <-- "id_rsa.pub" inside
[~/.ssh/id_rsa.pub]
Don’t forget to restrict permissions on ~/.ssh
:
chmod 700 ~/.ssh
sudoer for the destuser
The destuser
must have the privilege to do sudo -u jenkins rsync
.
In general, we set the destuser
as a member of the sudoers
. To do this, on the root
@destmachine
:
cat > /etc/sudoers.d/destuser << EOF
destuser ALL=(ALL) NOPASSWD:ALL
EOF
To test it before rsync
, you can log onto the destuser
@destmachine
and run this:
sudo su jenkins
echo $USER
If it returns:
jenkins
it means that you are logged as jenkins
user, and it means that your rsync
command will work as well, because the escalade privilege to jenkins
works.
Note about a bad solution: establish the SSH connection with the destination user jenkins
Why don’t we just do this?
(srcmachine) (rsync) (destmachine)
srcuser -- SSH --> jenkins
[~/.ssh/id_rsa] [~/.ssh/authorized_keys] <-- "id_rsa.pub" inside
[~/.ssh/id_rsa.pub]
because jenkins
is a “service” account, which means that it runs a service which exposes a port (80
or so) for external HTTP access, and it means that it is POSSIBLE that there is a security breach through the Jenkins service over HTTP to gain access.
That’s why we have www-data
user and similars to run the different services. In case they get hacked from the ports they expose, they can’t do much:
- everything is read-only for them.
- except writing in
/var/log/THE_SERVICE
.
So allowing SSH access for the jenkins
user exposes a surface attack (and so it is for SSH access as root
!!).
Moreover, if you want to rsync as another user (root
, www-data
, etc.), you would have to copy your SSH key public key to those accounts (troublesome).
Good solution: You should set SSH access as few as possible to user accounts (destuser
) that CAN escaladate to the “service” account you want (jenkins
, root
, etc.).