Como copiar arquivos que precisam de acesso root com o scp?

168

Eu tenho um servidor Ubuntu ao qual estou me conectando usando SSH.

Preciso fazer o upload de arquivos da minha máquina para /var/www/o servidor em que os arquivos /var/www/pertencem root.

Usando o PuTTY, depois que eu faço o login, preciso digitar a sudo suminha senha primeiro para poder modificar os arquivos /var/www/.

Mas, quando estou copiando arquivos usando o WinSCP, não consigo criar arquivos de criação / modificação /var/www/, porque o usuário com o qual estou me conectando não tem permissões nos arquivos /var/www/e não posso dizer sudo sucomo faço no caso de uma sessão ssh .

Você sabe como eu poderia lidar com isso?

Se eu estivesse trabalhando na minha máquina local, telefonaria, gksudo nautilusmas, neste caso, só tenho acesso ao terminal na máquina.

Dimitris Sapikas
fonte
Isso parece mais uma pergunta para o seu provedor de servidor virtual ou para os desenvolvedores de massa de vidraceiro ou winscp.
Dobey
7
@ obey você obviamente errado, é sobre privilégios do ubuntu!
Dimitris Sapikas
7
Por que isso está fechado? Esta é uma questão perfeitamente válida sobre como copiar arquivos com scp - todo desenvolvedor web está familiarizado com esta situação
Sergey
Eu tenho um problema similar. Crio um arquivo (neste caso, HTML) no computador com Windows e tento copiá-lo com o WinSCP para a pasta / var / www / html / website. E diz que há um problema de permissão. Como posso copiar para minha pasta / home, copiei o arquivo em duas etapas, mas não é muito conveniente :-) Tentei adicionar meu usuário ao grupo www-data, mas não ajudou. Alguma idéia de por que adicionar ao usuário o www-data ainda não permite ao usuário copiar um arquivo para a pasta que pertence ao grupo www-data?
JanezKranjski

Respostas:

126

Você está certo, não há sudoquando se trabalha scp. Uma solução alternativa é usar o scpupload de arquivos para um diretório em que o usuário tenha permissões para criar arquivos, faça login via ssh e use sudopara mover / copiar arquivos para o destino final.

scp -r folder/ [email protected]:/some/folder/you/dont/need/sudo
ssh [email protected]
 $ sudo mv /some/folder /some/folder/requiring/perms 
# YOU MAY NEED TO CHANGE THE OWNER like:
# sudo chown -R user:user folder

Outra solução seria alterar as permissões / propriedade dos diretórios nos quais você está carregando os arquivos, para que seu usuário não privilegiado possa gravar nesses diretórios.

Geralmente, trabalhar na rootconta deve ser uma exceção, não uma regra - a maneira como você formula sua pergunta me faz pensar que talvez você esteja abusando um pouco dela, o que por sua vez leva a problemas com permissões - em circunstâncias normais, você não precisa privilégios de superadministrador para acessar seus próprios arquivos.

Tecnicamente, você pode configurar o Ubuntu para permitir o login remoto diretamente como root, mas esse recurso está desativado por um motivo, por isso aconselho você a não fazer isso.

Sergey
fonte
não obtive a primeira solução, você poderia ser um pouco mais específico?
Dimitris Sapikas
Quando digo meus próprios arquivos, quero dizer / var / www, estou usando meus vps como servidor da Web .... em minha própria pasta, tenho acesso total #
Dimitris Sapikas
7
Ré. a primeira solução. 1. scp -R mysite [email protected]:/home/dimitris/2. ssh [email protected]3. sudo mv ~/mysite /var/www- é um processo em duas etapas: primeiro, você scpenvia os arquivos para o diretório inicial, depois faz logon via ssh e copia / move os arquivos para onde eles deveriam estar.
Sergey
36

Outro método é copiar usando tar + ssh em vez de scp:

tar -c -C ./my/local/dir \
  | ssh [email protected] "sudo tar -x --no-same-owner -C /var/www"
Willie Wheeler
fonte
2
Essa é a melhor maneira de fazer isso.
mttdbrd
2
Não consigo fazer esse método funcionar com êxito. Como está escrito eu entendo sudo: sorry, you must have a tty to run sudo. Se eu adicionar "-t" para alocar um TTY, recebo Pseudo-terminal will not be allocated because stdin is not a terminal.. Não consigo ver isso funcionando sem o sudo sem senha.
IBBoard 26/10/2015
11
@IBBoard: experimente a solução aqui usando ssh -t:ssh -t [email protected] "sudo tar -x --no-same-owner -C /var/www"
Alexander Bird
2
@AlexanderBird Embora isso funcione em muitos casos, não tenho certeza de que funcione aqui, porque estamos tentando canalizar um tarball pela conexão SSH. Veja serverfault.com/questions/14389/…
IBBoard
Isto é o que finalmente funcionou para mim. Você não tem permissões para um arquivo remoto que você deseja copiar para o local, faça um sudo tar, arquivá-lo, alterar permissões usando chmode chown, em seguida, copiá-lo para local. Especialmente se for um diretório.
forumulator
28

Atalho

Do servidor para a máquina local:

ssh user@server "sudo cat /etc/dir/file" > /home/user/file

Da máquina local para o servidor:

cat /home/user/file | ssh user@server "sudo tee -a /etc/dir/file"
Anderson Lira
fonte
5
Esta resposta é subestimada. É simples, limpo, lê ou grava um arquivo raiz com uma única operação atômica e não requer nada que ainda não esteja garantido se você estiver usando o scp. A principal desvantagem é que ele não copia permissões. Se você quiser isso, a solução de alcatrão é melhor. Esta é uma técnica poderosa, particularmente se for combinado com mágica xargs / festa para percorrer percursos ..
markgo2k
Eu acho que a pergunta era sobre o upload de um arquivo de local para remoto e não vice-versa
Korayem
11
Lindamente feito. Era exatamente isso que eu procurava, tanto para cima quanto para baixo. Obrigado
Jeremy
Merece ser a melhor resposta, com certeza.
Andrew Watson
Isso pode ser feito para um diretório em vez de um arquivo também?
lucidbrot 11/08
26

Você também pode usar ansiblepara fazer isso.

Copie para o host remoto usando o copymódulo da ansible :

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

Busque no host remoto usando o fetchmódulo da ansible :

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

NOTA:

  • A vírgula na -i HOST,sintaxe não é um erro de digitação. É a maneira de usar o ansible sem precisar de um arquivo de inventário.
  • -bfaz com que as ações no servidor sejam executadas como raiz. -bexpande para --become, e o padrão --become-useré root, com o padrão --become-methodsendo sudo.
  • flat=yescopia apenas o arquivo, não copia todo o caminho remoto que leva ao arquivo
  • O uso de curingas nos caminhos de arquivo não é suportado por esses módulos ansible.
  • A cópia de um diretório é suportada pelo copymódulo, mas não pelo fetchmódulo.

Invocação específica para esta pergunta

Aqui está um exemplo específico e completo, assumindo que o diretório do host local que contém os arquivos a serem distribuídos seja sourcedire que o nome do host do destino remoto seja hostname:

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

Com a chamada concisa sendo:

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

PS, percebo que dizer "basta instalar esta ferramenta fabulosa" é uma resposta meio surda. Mas achei que o ansible é super útil para administrar servidores remotos; portanto, a instalação do aplicativo certamente trará outros benefícios além da implantação de arquivos.

erik.weathers
fonte
Gosto da resposta, mas recomendo que você a encaminhe para a pergunta feita versus comentários mais generalizados antes do voto positivo. algo comoansible -i "hostname," all -u user --become -m copy -a ...
Mike D
@ MikeD: como são as alterações acima?
Erik.weathers
11
Algo como -i 'host,'seria uma sintaxe válida? Eu acho que é fácil perder pontuação assim ao ler um comando. (Para o leitor Quer dizer, se não o shell.)
mwfearnley
11
@mwfearnley: claro, o shell tratará o -i 'host,'mesmo que -i host,ou -i "host,". Em geral, prefiro manter essas invocações o mais curtas possível para evitar que sejam assustadoras, mas você deve se sentir à vontade para torná-las tão detalhadas e explícitas quanto achar necessário para maior clareza.
Erik.weathers
2
Muito bem pensar fora da caixa! O que é Ansible?
jonatan
12

Quando você executa sudo su, todos os arquivos criados por você pertencem ao root, mas por padrão não é possível efetuar login diretamente como root com ssh ou scp. Também não é possível usar o sudo com o scp, portanto os arquivos não são utilizáveis. Corrija isso reivindicando a propriedade dos seus arquivos:

Supondo que seu nome de usuário fosse dimitri, você poderia usar este comando.

sudo chown -R dimitri:dimitri /home/dimitri

A partir de então, como mencionado em outras respostas, a maneira "Ubuntu" é usar o sudo, e não os logins de raiz. É um paradigma útil, com grandes vantagens de segurança.

reconhecedores
fonte
Eu estou usando esta solução de qualquer maneira, mas o que se eu poderia obter acesso completo ao meu próprio sistema de arquivos, eu não quero escrever sudo chow ...para cada diretório único: S
Dimitris Sapikas
2
Alterar a propriedade de todos os arquivos do sistema para o usuário para facilitar a transmissão é altamente desencorajado. Ele permite que qualquer bug no espaço do usuário que você possa encontrar comprometa severamente a segurança do seu sistema. É muito melhor alterar a propriedade dos arquivos que você precisa alterar ou atualizar pelo SCP, mas deixar todo o resto pertencente ao root (como deveria ser). Dito isto, o -Rin chowndiz para alterar a propriedade desse diretório e todos os arquivos e diretórios filhos recursivamente ... para que você possa fazer o que quiser.
trognanders
hmm .... isso parece funcionar bem, obrigado! desculpe, eu não posso votar (o sistema não me permite fazer ...) #
Dimitris Sapikas 30/10/12
11

Pode ser a melhor maneira é usar rsync( Cygwin / cwRsync no Windows) sobre SSH?

Por exemplo, para enviar arquivos com o proprietário www-data:

rsync -a --rsync-path="sudo -u www-data rsync" path_to_local_data/ [email protected]:/var/www

No seu caso, se você precisar de privilégios de root, o comando será assim:

rsync -a --rsync-path="sudo rsync" path_to_local_data/ [email protected]:/var/www

Veja: scp no servidor remoto com sudo .

Alexey Vazhnov
fonte
5

Se você usar as ferramentas OpenSSH em vez do PuTTY, poderá fazer isso iniciando a scptransferência de arquivos no servidor com sudo. Verifique se você tem um sshddaemon em execução na sua máquina local. Com ssh -Rvocê pode dar ao servidor uma maneira de entrar em contato com sua máquina.

Na sua máquina:

ssh -R 11111:localhost:22 REMOTE_USERNAME@SERVERNAME

Além de fazer o login no servidor, isso encaminhará todas as conexões feitas na porta 11111 do servidor para a porta 22 da sua máquina: a porta na qual você sshdestá ouvindo.

No servidor, inicie a transferência de arquivos da seguinte maneira:

cd /var/www/
sudo scp -P 11111 -r LOCAL_USERNAME@localhost:FOLDERNAME .
Bergóide
fonte
1

Você pode usar o script que escrevi inspirado neste tópico:

touch /tmp/justtest && scpassudo /tmp/justtest [email protected]:/tmp/

mas isso requer algumas coisas malucas (que são feitas automaticamente por script)

  1. O servidor para o qual o arquivo está sendo enviado não solicitará mais a senha ao estabelecer a conexão ssh com o computador de origem
  2. devido à necessidade de falta de prompt do sudo no servidor, o sudo não solicitará mais a senha na máquina remota, para o usuário

Aqui está o 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 [email protected]:/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
test30
fonte
@Braiam sim, claro, desculpe pelo link, o script é bem longo e esse foi o motivo :) #
3030
1

Você pode combinar ssh, sudo e, por exemplo, tar para transferir arquivos entre servidores sem poder fazer login como root e sem ter permissão para acessar os arquivos com seu usuário. Isso é um pouco complicado, então escrevi um script para ajudar nisso. Você pode encontrar o script aqui: https://github.com/sigmunau/sudoscp

ou aqui:

#! / bin / bash
res = 0
from = $ 1
to = $ 2
mudança
mudança
arquivos = "$ @"
se teste -z "$ de" -o -z "$ para" -o -z "$ files"
então
    eco "Uso: $ 0 (arquivo) *"
    echo "exemplo: $ 0 server1 server2 / usr / bin / myapp"
    saída 1
fi

read -s -p "Digite a senha:" sudopassword
eco ""
temp1 = $ (mktemp)
temp2 = $ (mktemp)
(echo "$ sudopassword"; echo "$ sudopassword" | ssh $ do sudo -S tar c -P -C / $ arquivos 2> $ temp1) | ssh $ para o sudo -S tar x -v -P -C / 2 > $ temp2
fontes = $ {PIPESTATUS [0]}
se [$? -ne 0 -o $ fontes -ne 0]
então
    eco "Falha!" > & 2
    echo "$ from output:"> & 2
    cat $ temp1> & 2
    eco ""> & 2
    echo "$ to output:"> & 2
    cat $ temp2> & 2
    res = 1
fi

rm $ temp1 $ temp2
exit $ res
sigmunda
fonte
Bem-vindo ao Ask Ubuntu. Você poderia incluir o script na sua resposta? Eu sei que é improvável, mas se o repositório do github for removido ou o URL alterado, a resposta será anulada. É melhor incluir o script diretamente e deixar o repositório do github como fonte.
Michael Lindman
0

Aqui está uma versão modificada da resposta de Willie Wheeler que transfere o (s) arquivo (s) via tar, mas também suporta a passagem de uma senha para o sudo no 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\""

O pouco de mágica extra aqui é a opção -S para sudo. Na página do manual do sudo:

-S, --stdin Escreva o prompt para o erro padrão e leia a senha da entrada padrão em vez de usar o dispositivo terminal. A senha deve ser seguida por um caractere de nova linha.

Agora, na verdade, queremos que a saída do tar seja canalizada para o ssh e isso redirecione o stdin do ssh para o stdout do tar, removendo qualquer maneira de passar a senha para o sudo a partir do terminal interativo. (Poderíamos usar o recurso ASKPASS do sudo na extremidade remota, mas isso é outra história.) Podemos obter a senha no sudo, capturando-a com antecedência e acrescentando-a à saída do tar, executando essas operações em um subshell e canalizando a saída de o subshell em ssh. Isso também tem a vantagem adicional de não deixar uma variável de ambiente contendo nossa senha pendurada em nosso shell interativo.

Você notará que não executei 'read' com a opção -p para imprimir um prompt. Isso ocorre porque o prompt de senha do sudo é convenientemente passado de volta ao stderr do nosso shell interativo via ssh. Você pode se perguntar "como o sudo está sendo executado, uma vez que está sendo executado dentro do ssh à direita do nosso pipe?" Quando executamos vários comandos e canalizamos a saída de um para o outro, o shell pai (o shell interativo neste caso) executa cada comando na sequência imediatamente após a execução do anterior. À medida que cada comando atrás de um pipe é executado, o shell pai anexa (redireciona) o stdout do lado esquerdo ao stdin do lado direito. A saída se torna entrada à medida que passa pelos processos.

$ (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"`

Nosso shell interativo é o PID 7168, nosso subshell é o PID 7969 e nosso processo ssh é o PID 7970.

A única desvantagem é que a leitura aceitará a entrada antes que o sudo tenha tempo de enviar sua solicitação de volta. Em uma conexão rápida e em um host remoto rápido, você não notará isso, mas poderá se estiver lento. Qualquer atraso não afetará a capacidade de inserir o prompt; isso pode aparecer após você começar a digitar.

Nota: eu simplesmente adicionei uma entrada de arquivo host para "remote_Host" na minha máquina local para a demonstração.

Bruce
fonte