¿Cómo copio archivos que necesitan acceso raíz con scp?

168

Tengo un servidor Ubuntu al que me estoy conectando usando SSH.

Necesito cargar archivos de mi máquina en /var/www/el servidor, los archivos /var/www/son propiedad de root.

Con PuTTY, después de iniciar sesión, sudo suprimero tengo que escribir y mi contraseña para poder modificar archivos /var/www/.

Pero cuando estoy copiando archivos usando WinSCP, no puedo crear crear / modificar archivos /var/www/, porque el usuario con el que me estoy conectando no tiene permisos en los archivos /var/www/y no puedo decir sudo sulo que hago en caso de una sesión ssh .

¿Sabes cómo podría lidiar con esto?

Si estuviera trabajando en mi máquina local, llamaría gksudo nautiluspero en este caso solo tengo acceso de terminal a la máquina.

Dimitris Sapikas
fuente
Esto parece más una pregunta para su proveedor de servidor virtual, o para los desarrolladores de masilla o winscp.
dobey
77
@dobey obviamente te equivocas, ¡se trata de los privilegios de ubuntu!
Dimitris Sapikas
77
¿Por qué está cerrado esto? Esta es una pregunta perfectamente válida sobre la copia de archivos con scp: cada desarrollador web está familiarizado con esta situación
Sergey
Tengo un problema similar. Creo un archivo (HTML en este caso) en una computadora con Windows e intento copiarlo con WinSCP en la carpeta / var / www / html / website. Y dice que hay un problema de permiso. Debido a que puedo copiar en mi carpeta / home, copié el archivo en dos pasos, pero no es muy conveniente :-) Intenté agregar mi usuario al grupo www-data, pero no me ayudó. ¿Alguna idea de por qué agregar al usuario a www-data todavía no le permite al usuario copiar un archivo a la carpeta que pertenece al grupo www-data?
JanezKranjski

Respuestas:

126

Tienes razón, no hay sudocuando trabajas scp. Una solución alternativa es usar scppara cargar archivos en un directorio donde su usuario tiene permisos para crear archivos, luego iniciar sesión a través de ssh y usar sudopara mover / copiar archivos a su 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

Otra solución sería cambiar los permisos / propiedad de los directorios en los que carga los archivos, para que su usuario no privilegiado pueda escribir en esos directorios.

En general, trabajar en la rootcuenta debe ser una excepción, no una regla: la forma en que formula su pregunta me hace pensar que tal vez está abusando un poco, lo que a su vez genera problemas con los permisos; en circunstancias normales, no necesita privilegios de superadministrador para acceder a sus propios archivos.

Técnicamente, puede configurar Ubuntu para permitir el inicio de sesión remoto directamente como root, pero esta característica está deshabilitada por una razón, por lo que le recomiendo encarecidamente que no lo haga.

Sergey
fuente
No obtuve la primera solución, ¿podría ser un poco más específico?
Dimitris Sapikas
Cuando digo mis propios archivos me refiero a / var / www, estoy usando mi vps como servidor web ... en mi propia carpeta tengo acceso completo
Dimitris Sapikas
77
Re. La primera solución. 1. scp -R mysite [email protected]:/home/dimitris/2. ssh [email protected]3. sudo mv ~/mysite /var/www- es un proceso de 2 pasos, primero scplos archivos a su directorio de inicio, luego inicia sesión a través de ssh y copia / mueve los archivos a donde deberían estar
Sergey
36

Otro método es copiar usando tar + ssh en lugar de scp:

tar -c -C ./my/local/dir \
  | ssh [email protected] "sudo tar -x --no-same-owner -C /var/www"
Willie Wheeler
fuente
2
Esta es la mejor manera de hacerlo.
mttdbrd
2
No puedo hacer que este método funcione con éxito. Como está escrito lo entiendo sudo: sorry, you must have a tty to run sudo. Si agrego "-t" para asignar un TTY, obtengo Pseudo-terminal will not be allocated because stdin is not a terminal.. No puedo ver esto funcionando sin sudo sin contraseña.
IBBoard
1
@IBBoard: pruebe la solución aquí usando ssh -t:ssh -t [email protected] "sudo tar -x --no-same-owner -C /var/www"
Alexander Bird
2
@AlexanderBird Si bien eso funciona en muchos casos, no estoy seguro de que funcione aquí porque estamos tratando de canalizar un tarball sobre la conexión SSH. Ver serverfault.com/questions/14389/…
IBBoard
Esto es lo que finalmente funcionó para mí. No tiene permisos para un archivo remoto que desea copiar a local, hacer sudo tar, archivar, cambiar los permisos usando chmody chown, y luego copiarlo a local. Especialmente si es un directorio.
forumulator
28

De manera rápida

Del servidor a la máquina local:

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

De la máquina local al servidor:

cat /home/user/file | ssh user@server "sudo tee -a /etc/dir/file"
Anderson Lira
fuente
55
Esta respuesta está subestimada. Es simple, limpio, lee o escribe un archivo raíz con una sola operación atómica, y no requiere nada que no esté garantizado si está usando scp. El inconveniente principal es que no copia los permisos. Si quieres eso, la solución de alquitrán es mejor. Esta es una técnica poderosa, particularmente si se combina con xargs / bash magic para atravesar caminos ...
markgo2k
Creo que la pregunta era sobre cargar un archivo de local a remoto y no al revés
Korayem
1
Muy bien hecho. Esto es exactamente lo que estaba buscando arriba y abajo. Gracias
Jeremy
Merece ser la mejor respuesta, seguro.
Andrew Watson
¿Se puede hacer esto también para un directorio en lugar de un archivo?
lucidbrot
26

También puedes usar ansiblepara lograr esto.

Copie al host remoto utilizando el copymódulo de ansible :

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

Recuperar desde host remoto utilizando el fetchmódulo de ansible :

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

NOTA:

  • La coma en la -i HOST,sintaxis no es un error tipográfico. Es la forma de usar ansible sin necesidad de un archivo de inventario.
  • -bhace que las acciones en el servidor se realicen como root. -bse expande a --become, y el valor predeterminado --become-useres root, siendo el valor predeterminado --become-methodsudo.
  • flat=yescopia solo el archivo, no copia la ruta remota completa que conduce al archivo
  • El uso de comodines en las rutas de archivo no es compatible con estos módulos ansibles.
  • Copiar un directorio es compatible con el copymódulo, pero no con el fetchmódulo.

Invocación específica para esta pregunta

Aquí hay un ejemplo que es específico y completamente especificado, suponiendo que el directorio en su host local que contiene los archivos a distribuir es sourcedir, y que el nombre de host del destino remoto es 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 invocación concisa siendo:

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

PD: Me doy cuenta de que decir "solo instala esta herramienta fabulosa" es una respuesta sorda. Pero he encontrado que Ansible es súper útil para administrar servidores remotos, por lo que instalarlo seguramente le brindará otros beneficios más allá de la implementación de archivos.

erik.weathers
fuente
Me gusta esta respuesta, pero le recomiendo que la dirija a la pregunta formulada versus un comentario más generalizado antes de votar. algo así comoansible -i "hostname," all -u user --become -m copy -a ...
Mike D
@MikeD: ¿cómo se ven los cambios anteriores?
erik.weathers
1
¿Sería algo así -i 'host,'como una sintaxis válida? Creo que es fácil perder la puntuación así cuando se lee un comando. (Para el lector, quiero decir, si no el caparazón)
Mwfearnley
1
@mwfearnley: claro, el shell se tratará -i 'host,'igual que -i host,o -i "host,". En general, prefiero mantener estas invocaciones lo más cortas posible para evitar que sean desalentadoras, pero debe sentirse libre de hacerlo tan detallado y explícito como cree que es necesario para mayor claridad.
erik.weathers
2
¡Así se hace pensar fuera de la caja! Gran uso de Ansible
jonatan
12

Cuando ejecuta sudo su, los archivos que cree serán propiedad de root, pero no es posible iniciar sesión directamente como root con ssh o scp de manera predeterminada. Tampoco es posible usar sudo con scp, por lo que los archivos no son utilizables. Solucione esto reclamando la propiedad sobre sus archivos:

Suponiendo que su nombre de usuario fuera dimitri, puede usar este comando.

sudo chown -R dimitri:dimitri /home/dimitri

A partir de entonces, como se menciona en otras respuestas, la forma "Ubuntu" es usar sudo, y no inicios de sesión de root. Es un paradigma útil, con grandes ventajas de seguridad.

trognanders
fuente
Estoy usando esta solución de cualquier manera, pero ¿y si pudiera obtener acceso completo a mi propio sistema de archivos? No quiero escribir sudo chow ...para cada directorio: S
Dimitris Sapikas
2
Se desaconseja cambiar la propiedad de todos los archivos del sistema al usuario para que sea más conveniente. Permite que cualquier error de espacio de usuario que pueda encontrar comprometa severamente la seguridad de su sistema. Es mucho mejor cambiar la propiedad de los archivos que necesita cambiar o actualizar mediante SCP, pero dejar todo lo demás propiedad de root (como se supone que debe ser). Dicho esto, el -Rin chownle dice que cambie la propiedad de ese directorio y todos los archivos y directorios secundarios de forma recursiva ... para que pueda hacer lo que quiera.
trognanders
hmm ... eso parece funcionar bien, gracias! lo siento, no puedo votar (el sistema no me permite hacer ...)
Dimitris Sapikas
11

¿Puede ser la mejor forma de usar rsync( Cygwin / cwRsync en Windows) sobre SSH?

Por ejemplo, para cargar archivos con el propietario www-data:

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

En su caso, si necesita privilegios de root, el comando será así:

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

Ver: scp al servidor remoto con sudo .

Alexey Vazhnov
fuente
5

Si utiliza las herramientas OpenSSH en lugar de PuTTY, puede lograr esto iniciando la scptransferencia de archivos en el servidor con sudo. Asegúrese de tener un sshddemonio ejecutándose en su máquina local. Con ssh -Rusted puede darle al servidor una forma de contactar su máquina.

En su máquina:

ssh -R 11111:localhost:22 REMOTE_USERNAME@SERVERNAME

Además de iniciar sesión en el servidor, esto reenviará cada conexión realizada en el puerto 11111 del servidor al puerto 22 de su máquina: el puerto en el que sshdestá escuchando.

En el servidor, inicie la transferencia de archivos de esta manera:

cd /var/www/
sudo scp -P 11111 -r LOCAL_USERNAME@localhost:FOLDERNAME .
bergoid
fuente
1

Puede usar un guión que he escrito inspirado en este tema:

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

pero esto requiere algunas cosas locas (que por cierto se hace automáticamente por script)

  1. el servidor al que se envía el archivo ya no solicitará contraseña mientras establece la conexión ssh con la computadora de origen
  2. debido a la necesidad de la falta de sudo prompt en el servidor, sudo ya no solicitará una contraseña en la máquina remota, para el usuario

Aquí va el guión:

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
fuente
@Braiam sí, claro, perdón por el enlace, el guión es bastante largo y esa fue la razón :)
test30
1

Puede combinar ssh, sudo y, por ejemplo, tar, para transferir archivos entre servidores sin poder iniciar sesión como root y sin tener permiso para acceder a los archivos con su usuario. Esto es un poco complicado, así que escribí un guión para ayudarlo. Puede encontrar el script aquí: https://github.com/sigmunau/sudoscp

o aquí:

#! / bin / bash
res = 0
desde = $ 1
a = $ 2
cambio
cambio
archivos = "$ @"
si prueba -z "$ de" -o -z "$ a" -o -z "$ archivos"
entonces
    echo "Uso: $ 0 (archivo) *"
    echo "ejemplo: $ 0 servidor1 servidor2 / usr / bin / myapp"
    salida 1
fi

leer -s -p "Introducir contraseña:" sudopassword
eco ""
temp1 = $ (mktemp)
temp2 = $ (mktemp)
(echo "$ sudopassword"; echo "$ sudopassword" | ssh $ de sudo -S tar c -P -C / $ archivos 2> $ temp1) | ssh $ a sudo -S tar x -v -P -C / 2 > $ temp2
sourceres = $ {PIPESTATUS [0]}
si [$? -ne 0 -o $ sourceres -ne 0]
entonces
    echo "¡Fracaso!" > Y 2
    echo "$ de salida:"> & 2
    cat $ temp1> & 2
    echo ""> & 2
    echo "$ a la salida:"> & 2
    cat $ temp2> & 2
    res = 1
fi

rm $ temp1 $ temp2
salir $ res
sigmunda
fuente
Bienvenido a Ask Ubuntu. ¿Podría incluir el guión en su respuesta? Sé que es poco probable, pero si alguna vez se eliminó el repositorio de Github o si se cambió la URL, la respuesta sería nula. Es mejor incluir el script directamente y dejar el repositorio de github como fuente.
Michael Lindman
0

Aquí hay una versión modificada de la respuesta de Willie Wheeler que transfiere los archivos a través de tar pero también admite pasar una contraseña a sudo en el 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\""

El poco de magia extra aquí es la opción -S para sudo. Desde la página de manual de sudo:

-S, --stdin Escriba la solicitud en el error estándar y lea la contraseña de la entrada estándar en lugar de usar el dispositivo terminal. La contraseña debe ir seguida de un carácter de nueva línea.

Ahora realmente queremos que la salida de tar se canalice a ssh y eso redirija el stdin de ssh al stdout de tar, eliminando cualquier forma de pasar la contraseña a sudo desde el terminal interactivo. (Podríamos usar la función ASKPASS de sudo en el extremo remoto, pero esa es otra historia). Sin embargo, podemos obtener la contraseña en sudo al capturarla de antemano y anteponerla a la salida tar realizando esas operaciones en un subshell y canalizando la salida de la subshell en ssh. Esto también tiene la ventaja adicional de no dejar una variable de entorno que contiene nuestra contraseña colgando en nuestro shell interactivo.

Notarás que no ejecuté 'leer' con la opción -p para imprimir un mensaje. Esto se debe a que la solicitud de contraseña de sudo se pasa convenientemente de vuelta al stderr de nuestro shell interactivo a través de ssh. Quizás se pregunte "¿cómo se está ejecutando sudo dado que se ejecuta dentro de ssh a la derecha de nuestra tubería?" Cuando ejecutamos múltiples comandos y canalizamos la salida de uno a otro, el shell principal (el shell interactivo en este caso) ejecuta cada comando en la secuencia inmediatamente después de ejecutar el anterior. A medida que se ejecuta cada comando detrás de una tubería, el shell principal adjunta (redirige) la salida estándar del lado izquierdo a la entrada estándar del lado derecho. La salida se convierte en entrada a medida que pasa por los procesos.

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

Nuestro shell interactivo es PID 7168, nuestro subshell es PID 7969 y nuestro proceso ssh es PID 7970.

El único inconveniente es que la lectura aceptará la entrada antes de que sudo tenga tiempo de enviarla nuevamente. En una conexión rápida y un host remoto rápido, no lo notará, pero podría hacerlo si alguno de ellos es lento. Cualquier retraso no afectará la capacidad de ingresar a la solicitud; puede aparecer después de que hayas comenzado a escribir.

Tenga en cuenta que simplemente agregué una entrada de archivo de host para "remote_Host" a mi máquina local para la demostración.

Bruce
fuente