Come faccio a copiare i file che richiedono l'accesso root con scp?

140

Ho un server Ubuntu a cui mi sto connettendo usando SSH.

Ho bisogno di caricare file dalla mia macchina in /var/www/ sul server, i file in /var/www/ sono di proprietà di root .

Usando PuTTY, dopo aver effettuato l'accesso, devo digitare sudo su e la mia password prima di poter modificare i file in /var/www/ .

Ma quando copio i file usando WinSCP, non posso creare creare / modificare file in /var/www/ , perché l'utente con cui mi sto connettendo non ha permessi sui file in /var/www/ e non posso dire sudo su come faccio in caso di una sessione ssh.

Sai come potrei occuparmi di questo?

Se stavo lavorando sulla mia macchina locale, chiamerei gksudo nautilus , ma in questo caso ho solo accesso terminale alla macchina.

    
posta Dimitris Sapikas 29.10.2012 - 22:03
fonte

10 risposte

106

Hai ragione, non c'è sudo quando si lavora con scp . Una soluzione alternativa consiste nell'utilizzare scp per caricare i file in una directory in cui l'utente ha le autorizzazioni per creare file, quindi accedere tramite ssh e utilizzare sudo per spostare / copiare i file nella destinazione finale.

scp -r folder/ user@server.tld:/some/folder/you/dont/need/sudo
ssh user@server.tld
 $ sudo mv /some/folder /some/folder/requiring/perms 
# YOU MAY NEED TO CHANGE THE OWNER like:
# sudo chown -R user:user folder

Un'altra soluzione sarebbe quella di modificare i permessi / la proprietà delle directory in cui carichi i file, in modo che il tuo utente non privilegiato sia in grado di scrivere in quelle directory.

Generalmente, lavorare nell'account root dovrebbe essere un'eccezione, non una regola: il modo in cui formuli la tua domanda mi fa pensare che forse lo stai abusando un po ', che a sua volta porta a problemi con le autorizzazioni - in condizioni normali circostanze non hai bisogno di privilegi di super-amministratore per accedere ai tuoi file.

Tecnicamente, puoi configurare Ubuntu per consentire l'accesso remoto direttamente come root , ma questa funzione è disabilitata per un motivo, quindi ti consiglio caldamente di farlo.

    
risposta data Sergey 29.10.2012 - 23:22
fonte
29

Un altro metodo è copiare usando tar + ssh invece di scp:

tar -c -C ./my/local/dir \
  | ssh dimitris@myserver.com "sudo tar -x --no-same-owner -C /var/www"
    
risposta data Willie Wheeler 03.10.2014 - 20:56
fonte
23

Puoi anche usare ansible per realizzare questo.

Copia sull'host remoto utilizzando il modulo copy di ansible :

ansible -i HOST, -b -m copy -a "src=SRC_FILEPATH dest=DEST_FILEPATH" all

Recupera dall'host remoto utilizzando il modulo fetch di ansible :

ansible -i HOST, -b -m fetch -a "src=SRC_FILEPATH dest=DEST_FILEPATH flat=yes" all

NOTA:

  • La virgola nella sintassi -i HOST, non è un errore di battitura. È il modo di usare ansible senza bisogno di un file di inventario.
  • -b fa sì che le azioni sul server vengano eseguite come root. -b si espande in --become e il valore predefinito --become-user è root, con il --become-method predefinito sudo.
  • flat=yes copia solo il file, non copia tutto il percorso remoto che porta al file
  • L'utilizzo di caratteri jolly nei percorsi dei file non è supportato da questi moduli ansibili.
  • Copia di una directory è supportata dal modulo copy , ma non dal modulo fetch .

Invocazione specifica per questa domanda

Ecco un esempio specifico e completamente specificato, assumendo che la directory sul tuo host locale contenente i file da distribuire sia sourcedir e che il nome host della destinazione remota sia hostname :

cd sourcedir && \
ansible \
   --inventory-file hostname, \ 
   --become \
   --become-method sudo \
   --become-user root \
   --module-name copy \
   --args "src=. dest=/var/www/" \
   all

Con la chiamata sintetica:

cd sourcedir && \
ansible -i hostname, -b -m copy -a "src=. dest=/var/www/" all

P.S., mi rendo conto che dire "basta installare questo favoloso strumento" è una specie di a risposta tono-sordo. Ma ho trovato che super è utile per amministrare server remoti, quindi installarlo ti porterà sicuramente altri vantaggi oltre alla distribuzione dei file.

    
risposta data erik.weathers 15.02.2016 - 08:03
fonte
12

Quando esegui sudo su , tutti i file che crei saranno di proprietà di root, ma non è possibile per impostazione predefinita accedere direttamente come root con ssh o scp. Inoltre, non è possibile usare sudo con scp, quindi i file non sono utilizzabili. Risolvi questo problema rivendicando la proprietà sui tuoi file:

Supponendo che il tuo nome utente fosse dimitri, potresti usare questo comando.

sudo chown -R dimitri:dimitri /home/dimitri

Da quel momento in poi, come menzionato in altre risposte, il modo "Ubuntu" è usare sudo e non i login di root. È un paradigma utile, con grandi vantaggi in termini di sicurezza.

    
risposta data Bailey S 30.10.2012 - 00:07
fonte
8

Il modo migliore è usare rsync ( Cygwin / cwRsync in Windows) su SSH?

Ad esempio, per caricare file con proprietario www-data :

rsync -a --rsync-path="sudo -u www-data rsync" path_to_local_data/ login@srv01.example.com:/var/www

Nel tuo caso, se hai bisogno dei privilegi di root, il comando sarà così:

rsync -a --rsync-path="sudo rsync" path_to_local_data/ login@srv01.example.com:/var/www

Vedi: scp al server remoto con sudo .

    
risposta data Alexey Vazhnov 15.11.2016 - 11:14
fonte
7

Modo rapido:

ssh user@server "sudo cat /etc/dir/file" > /home/user/file
    
risposta data Anderson Lira 16.01.2017 - 14:01
fonte
5

Se usi gli strumenti OpenSSH invece di PuTTY, puoi farlo iniziando il trasferimento di file scp sul server con sudo . Assicurati di avere un demone sshd in esecuzione sul tuo computer locale. Con ssh -R puoi dare al server un modo per contattare la tua macchina.

Sulla tua macchina:

ssh -R 11111:localhost:22 REMOTE_USERNAME@SERVERNAME

Oltre ad accedere al server, questo inoltrerà ogni connessione effettuata sulla porta 11111 del server alla porta 22 della tua macchina: la porta su cui sshd è in ascolto.

Sul server, avvia il trasferimento del file in questo modo:

cd /var/www/
sudo scp -P 11111 -r LOCAL_USERNAME@localhost:FOLDERNAME .
    
risposta data bergoid 21.11.2016 - 17:52
fonte
1

Puoi usare lo script che ho scritto ispirato a questo argomento:

touch /tmp/justtest && scpassudo /tmp/justtest remoteuser@ssh.superserver.com:/tmp/

ma ciò richiede alcune cose pazzesche (che viene eseguita automaticamente da script)

    Il server
  1. a cui viene inviato il file non richiederà più la password mentre stabilisce la connessione ssh al computer di origine
  2. a causa della necessità di mancanza di prompt sudo sul server, sudo non chiederà più la password sulla macchina remota, per l'utente

Ecco lo script:

interface=wlan0
if [[ $# -ge 3 ]]; then interface=$3; fi
thisIP=$(ifconfig | grep $interface -b1 | tail -n1 | egrep -o '[0-9.]{4,}' -m1 | head -n 1)
thisUser=$(whoami)
localFilePath=/tmp/justfortest
destIP=192.168.0.2
destUser=silesia
#dest 
#destFolderOnRemoteMachine=/opt/glassfish/glassfish/
#destFolderOnRemoteMachine=/tmp/

if [[ $# -eq 0 ]]; then 
echo -e "Send file to remote server to locatoin where root permision is needed.\n\tusage: $0 local_filename [username@](ip|host):(remote_folder/|remote_filename) [optionalInterface=wlan0]"
echo -e "Example: \n\ttouch /tmp/justtest &&\n\t $0 /tmp/justtest remoteuser@ssh.superserver.com:/tmp/ "
exit 1
fi

localFilePath=$1

test -e $localFilePath 

destString=$2
usernameAndHost=$(echo $destString | cut -f1 -d':')

if [[ "$usernameAndHost" == *"@"* ]]; then
destUser=$(echo $usernameAndHost | cut -f1 -d'@')
destIP=$(echo $usernameAndHost | cut -f2 -d'@')
else
destIP=$usernameAndHost
destUser=$thisUser
fi

destFolderOnRemoteMachine=$(echo $destString | cut -f2 -d':')

set -e #stop script if there is even single error

echo 'First step: we need to be able to execute scp without any user interaction'
echo 'generating public key on machine, which will receive file'
ssh $destUser@$destIP 'test -e ~/.ssh/id_rsa.pub -a -e ~/.ssh/id_rsa || ssh-keygen -t rsa'
echo 'Done'

echo 'Second step: download public key from remote machine to this machine so this machine allows remote machine (this one receiveing file) to login without asking for password'

key=$(ssh $destUser@$destIP 'cat ~/.ssh/id_rsa.pub')
if ! grep "$key" ~/.ssh/authorized_keys; then
echo $key >> ~/.ssh/authorized_keys
echo 'Added key to authorized hosts'
else
echo "Key already exists in authorized keys"
fi

echo "We will want to execute sudo command remotely, which means turning off asking for password"
echo 'This can be done by this tutorial http://stackoverflow.com/a/10310407/781312'
echo 'This you have to do manually: '
echo -e "execute in new terminal: \n\tssh $destUser:$destIP\nPress enter when ready"
read 
echo 'run there sudo visudo'
read
echo 'change '
echo '    %sudo   ALL=(ALL:ALL) ALL'
echo 'to'
echo '    %sudo   ALL=(ALL:ALL) NOPASSWD: ALL'
echo "After this step you will be done."
read

listOfFiles=$(ssh $destUser@$destIP "sudo ls -a")

if [[ "$listOfFiles" != "" ]]; then 
echo "Sending by executing command, in fact, receiving, file on remote machine"
echo 'Note that this command (due to " instead of '', see man bash | less -p''quotes'') is filled with values from local machine'
echo -e "Executing \n\t""identy=~/.ssh/id_rsa; sudo scp -i \$identy $(whoami)@$thisIP:$(readlink -f $localFilePath) $destFolderOnRemoteMachine"" \non remote machine"
ssh $destUser@$destIP "identy=~/.ssh/id_rsa; sudo scp -i \$identy $(whoami)@$thisIP:$(readlink -f $localFilePath) $destFolderOnRemoteMachine"
ssh $destUser@$destIP "ls ${destFolderOnRemoteMachine%\\n}/$(basename $localFilePath)"
if [[ ! "$?" -eq 0 ]]; then echo "errror in validating"; else echo -e "SUCCESS! Successfully sent\n\t$localFilePath \nto \n\t$destString\nFind more at http://arzoxadi.tk"; fi
else
echo "something went wrong with executing sudo on remote host, failure"

fi
ENDOFSCRIPT
) | sudo tee /usr/bin/scpassudo && chmod +x /usr/bin/scpassudo
    
risposta data test30 21.11.2013 - 20:47
fonte
1

Puoi combinare ssh, sudo e e.g tar per trasferire file tra server senza poter accedere come root e non avere il permesso di accedere ai file con il tuo utente. Questo è un po 'complicato, quindi ho scritto una sceneggiatura per aiutare questo. Puoi trovare lo script qui: link

o qui:

#! /bin/bash
res=0
from=$1
to=$2
shift
shift
files="$@"
if test -z "$from" -o -z "$to" -o -z "$files"
then
    echo "Usage: $0    (file)*"
    echo "example: $0 server1 server2 /usr/bin/myapp"
    exit 1
fi

read -s -p "Enter Password: " sudopassword
echo ""
temp1=$(mktemp)
temp2=$(mktemp)
(echo "$sudopassword";echo "$sudopassword"|ssh $from sudo -S tar c -P -C / $files 2>$temp1)|ssh $to sudo -S tar x -v -P -C / 2>$temp2
sourceres=${PIPESTATUS[0]}
if [ $? -ne 0 -o $sourceres -ne 0 ]
then
    echo "Failure!" >&2
    echo "$from output:" >&2
    cat $temp1 >&2
    echo "" >&2
    echo "$to output:" >&2
    cat $temp2 >&2
    res=1
fi

rm $temp1 $temp2
exit $res
    
risposta data sigmunda 01.07.2015 - 17:16
fonte
0

Ecco una versione modificata della risposta di Willie Wheeler che trasferisce i file via tar ma supporta anche il passaggio di una password a sudo sull'host remoto.

(stty -echo; read passwd; stty echo; echo $passwd; tar -cz foo.*) \
  | ssh remote_host "sudo -S bash -c \"tar -C /var/www/ -xz; echo\""

Il poco di magia extra qui è l'opzione -S di sudo. Dalla pagina man di sudo:

% Bl0ck_qu0te%

Ora vogliamo realmente che l'output di tar venga reimpostato in ssh e che reindirizzi lo stdin di ssh allo stdout di tar, rimuovendo qualsiasi modo per passare la password su sudo dal terminale interattivo. (Potremmo usare la funzione ASKPASS di sudo sul terminale remoto, ma questa è un'altra storia.) Possiamo ottenere la password su sudo acquisendolo in anticipo e anteponendolo all'output di tar eseguendo quelle operazioni in una subshell e pipando l'output di la subshell in ssh. Questo ha anche il vantaggio di non lasciare una variabile d'ambiente contenente la nostra password che penzola nella nostra shell interattiva.

Noterai che non ho eseguito 'leggi' con l'opzione -p per stampare un prompt. Questo perché la richiesta di password da sudo è passata di nuovo allo stderr della nostra shell interattiva tramite ssh. Ci si potrebbe chiedere "come viene eseguito sudo eseguendolo all'interno di ssh alla destra della nostra pipe?" Quando eseguiamo più comandi e inseriamo l'output di uno in un altro, la shell madre (la shell interattiva in questo caso) esegue ciascun comando nella sequenza immediatamente dopo l'esecuzione del precedente. Quando viene eseguito ogni comando dietro un tubo, la shell genitore attacca (reindirizza) lo stdout del lato sinistro allo stdin del lato destro. L'output diventa quindi input mentre passa attraverso i processi. Possiamo vederlo in azione eseguendo l'intero comando e facendo lo sfondo del gruppo di processi (Ctrl-z) prima di digitare la nostra password e quindi visualizzare la struttura del processo.

$ (stty -echo; read passwd; stty echo; echo $passwd; tar -cz foo.*) | ssh 
remote_host "sudo -S bash -c \"tar -C /var/www/ -xz; echo\""
[sudo] password for bruce: 
[1]+  Stopped                 ( stty -echo; read passwd; stty echo; echo 
$passwd; tar -cz foo.* ) | ssh remote_host "sudo -S bash -c \"tar -C 
/var/www/ -xz; echo\""

$ pstree -lap $$
bash,7168
  ├─bash,7969
  ├─pstree,7972 -lap 7168
  └─ssh,7970 remote_host sudo -S bash -c "tar -C /var/www/ -xz; echo"'

La nostra shell interattiva è PID 7168, la nostra sottoshell è PID 7969 e il nostro processo ssh è PID 7970.

L'unico inconveniente è che read accetterà l'input prima che sudo abbia il tempo di rispedire il suo prompt. Su una connessione veloce e un host remoto veloce non ti accorgerai di questo, ma potresti farlo se è lento. Qualsiasi ritardo non influirà sulla possibilità di inserire il prompt; potrebbe apparire solo dopo aver iniziato a digitare.

Nota Ho semplicemente aggiunto una voce del file host per "remote_host" al mio computer locale per la demo.

    
risposta data Bruce 06.05.2017 - 12:17
fonte

Leggi altre domande sui tag