Bagaimana cara menyalin file yang membutuhkan akses root dengan scp?

168

Saya memiliki server Ubuntu yang saya hubungkan menggunakan SSH.

Saya perlu mengunggah file dari komputer saya ke /var/www/dalam server, file-file /var/www/itu dimiliki oleh root.

Menggunakan Putty, setelah saya login, saya harus mengetik sudo sudan kata sandi saya terlebih dahulu agar dapat memodifikasi file /var/www/.

Tetapi ketika saya menyalin file menggunakan WinSCP, saya tidak dapat membuat / memodifikasi file di /var/www/, karena pengguna saya terhubung dengan tidak memiliki izin pada file di /var/www/dan saya tidak bisa mengatakan sudo suseperti yang saya lakukan dalam kasus sesi ssh .

Apakah Anda tahu bagaimana saya bisa menangani ini?

Jika saya sedang mengerjakan mesin lokal saya, saya akan menelepon gksudo nautilustetapi dalam kasus ini saya hanya memiliki akses terminal ke mesin.

Dimitris Sapikas
sumber
Ini sepertinya lebih seperti pertanyaan untuk penyedia server virtual Anda, atau untuk pengembang dempul atau wincp.
dobey
7
@ jangan kamu salah, ini tentang hak istimewa ubuntu!
Dimitris Sapikas
7
Kenapa ini ditutup? Ini adalah pertanyaan yang sangat valid tentang menyalin file dengan scp - setiap pengembang web terbiasa dengan situasi ini
Sergey
Saya memiliki masalah serupa. Saya membuat file (HTML dalam hal ini) di komputer Windows dan mencoba menyalinnya dengan WinSCP ke / var / www / html / folder situs web. Dan dikatakan ada masalah izin. Karena saya dapat menyalin ke folder rumah saya, saya menyalin file dalam dua langkah, tetapi itu tidak terlalu nyaman :-) Saya mencoba menambahkan pengguna saya ke grup data-www, tetapi tidak membantu. Adakah ide mengapa menambahkan ke pengguna ke www-data masih tidak memungkinkan pengguna untuk menyalin file ke folder yang dimiliki oleh grup www-data?
JanezKranjski

Jawaban:

126

Anda benar, tidak ada sudosaat bekerja dengan scp. Solusinya adalah menggunakan scpuntuk mengunggah file ke direktori di mana pengguna Anda memiliki izin untuk membuat file, kemudian masuk melalui ssh dan gunakan sudountuk memindahkan / menyalin file ke tujuan akhir mereka.

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

Solusi lain adalah mengubah izin / kepemilikan direktori tempat Anda mengunggah file, sehingga pengguna yang tidak memiliki hak istimewa dapat menulis ke direktori tersebut.

Secara umum, bekerja di rootakun harus menjadi pengecualian, bukan aturan - cara Anda mengutarakan pertanyaan Anda membuat saya berpikir mungkin Anda sedikit melecehkannya, yang pada gilirannya menyebabkan masalah dengan izin - dalam keadaan normal Anda tidak perlu hak super admin untuk mengakses file Anda sendiri.

Secara teknis, Anda dapat mengonfigurasi Ubuntu untuk memungkinkan login jarak jauh secara langsung root, tetapi fitur ini dinonaktifkan karena suatu alasan, jadi saya sangat menyarankan Anda untuk tidak melakukannya.

Sergey
sumber
saya tidak mendapatkan solusi pertama, bisakah Anda menjadi sedikit lebih spesifik?
Dimitris Sapikas
Ketika saya mengatakan file saya sendiri maksud saya / var / www, saya menggunakan vps saya sebagai server web .... pada folder saya sendiri saya memiliki akses penuh
Dimitris Sapikas
7
Kembali. solusi pertama. 1. scp -R mysite [email protected]:/home/dimitris/2. ssh [email protected]3. sudo mv ~/mysite /var/www- ini adalah proses 2 langkah, pertama Anda scpfile ke dir rumah Anda, kemudian Anda login melalui ssh dan salin / pindahkan file ke tempat mereka seharusnya
Sergey
36

Metode lain adalah menyalin menggunakan tar + ssh daripada scp:

tar -c -C ./my/local/dir \
  | ssh [email protected] "sudo tar -x --no-same-owner -C /var/www"
Willie Wheeler
sumber
2
Ini adalah cara terbaik untuk melakukannya.
mttdbrd
2
Saya tidak bisa membuat metode ini berhasil. Seperti yang tertulis saya dapatkan sudo: sorry, you must have a tty to run sudo. Jika saya menambahkan "-t" untuk mengalokasikan TTY maka saya dapat Pseudo-terminal will not be allocated because stdin is not a terminal.. Saya tidak dapat melihat ini berfungsi tanpa sudo tanpa kata sandi.
IBBoard
1
@IBBoard: coba solusinya di sini menggunakan ssh -t:ssh -t [email protected] "sudo tar -x --no-same-owner -C /var/www"
Alexander Bird
2
@AlexanderBird Sementara itu berfungsi dalam banyak kasus, saya tidak yakin itu berfungsi di sini karena kami mencoba untuk mengirim tarball melalui koneksi SSH. Lihat serverfault.com/questions/14389/…
IBBoard
Inilah yang akhirnya berhasil untuk saya. Anda tidak memiliki izin untuk file jarak jauh yang ingin Anda salin ke lokal, lakukan sudo tar, arsipkan, ubah izin menggunakan chmoddan chown, lalu salin ke lokal. Apalagi kalau itu direktori.
forumulator
28

Cara cepat

Dari server ke mesin lokal:

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

Dari mesin lokal ke server:

cat /home/user/file | ssh user@server "sudo tee -a /etc/dir/file"
Anderson Lira
sumber
5
Jawaban ini diremehkan. Sederhana, bersih, membaca atau menulis file root dengan operasi atom tunggal, dan tidak memerlukan apa pun yang belum dijamin ada di sana jika Anda menggunakan scp. Kelemahan utama adalah tidak menyalin izin. Jika Anda menginginkannya, solusi tar lebih baik. Ini adalah teknik yang kuat, terutama jika dikombinasikan dengan xargs / bash magic untuk melintasi jalur ..
markgo2k
Saya pikir pertanyaannya adalah tentang mengunggah file dari lokal ke jarak jauh dan bukan sebaliknya
Korayem
1
Dilakukan dengan indah. Inilah yang saya cari baik atas dan ke bawah. Terima kasih
Jeremy
Pantas untuk menjadi jawaban teratas, pasti.
Andrew Watson
Bisakah ini dilakukan untuk direktori bukan file juga?
lucidbrot
26

Anda juga dapat menggunakannya ansibleuntuk mencapai ini.

Salin ke host jarak jauh menggunakan modul ansiblecopy :

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

Ambil dari host jarak jauh menggunakan modul ansiblefetch :

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

CATATAN:

  • Koma dalam -i HOST,sintaksis bukan kesalahan ketik. Ini adalah cara untuk menggunakan ansible tanpa memerlukan file inventaris.
  • -bmenyebabkan tindakan pada server dilakukan sebagai root. -bmeluas ke --become, dan default --become-useradalah root, dengan default --become-methodadalah sudo.
  • flat=yeshanya menyalin file, tidak menyalin seluruh jalur jauh yang mengarah ke file
  • Menggunakan wildcard di jalur file tidak didukung oleh modul yang memungkinkan ini.
  • Menyalin direktori yang didukung oleh copymodul, tetapi tidak oleh fetchmodul.

Doa Khusus untuk Pertanyaan ini

Berikut ini adalah contoh yang spesifik dan sepenuhnya ditentukan, dengan asumsi direktori pada host lokal Anda yang berisi file yang akan didistribusikan sourcedir, dan nama host target remote adalah hostname:

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

Dengan doa singkat:

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

PS, saya menyadari bahwa mengatakan "cukup instal alat yang luar biasa ini" adalah semacam nada-tuli. Tapi saya merasa sangat berguna untuk mengelola server jarak jauh, jadi menginstalnya pasti akan membawa Anda manfaat lain di luar penggunaan file.

erik
sumber
Saya suka jawaban ini, tetapi saya sarankan Anda mengarahkannya pada pertanyaan yang diajukan versus komentar yang lebih umum sebelum upvote. sesuatu sepertiansible -i "hostname," all -u user --become -m copy -a ...
Mike D
@ MikeD: bagaimana perubahan di atas terlihat?
erik.weathers
1
Apakah sesuatu seperti -i 'host,'sintaks yang valid? Saya pikir mudah untuk kehilangan tanda baca seperti itu ketika membaca sebuah perintah. (Untuk pembaca yang saya maksud, jika bukan kulitnya.)
mwfearnley
1
@ mwfearnley: tentu, shell akan memperlakukan -i 'host,'dan sama dengan -i host,atau -i "host,". Secara umum saya lebih suka untuk menjaga doa ini sesingkat mungkin untuk menjaga mereka dari menjadi menakutkan, tetapi Anda harus merasa bebas untuk membuatnya sebagai kata kerja dan eksplisit karena Anda pikir diperlukan untuk kejelasan.
erik.weathers
2
Cara untuk berpikir di luar kotak! Penggunaan Ansible
jonatan
12

Ketika Anda menjalankan sudo su, semua file yang Anda buat akan dimiliki oleh root, tetapi tidak mungkin secara default untuk langsung login sebagai root dengan ssh atau scp. Juga tidak mungkin menggunakan sudo dengan scp, sehingga file tidak dapat digunakan. Perbaiki ini dengan mengklaim kepemilikan atas file Anda:

Dengan asumsi nama pengguna Anda adalah dimitri, Anda dapat menggunakan perintah ini.

sudo chown -R dimitri:dimitri /home/dimitri

Sejak saat itu, sebagaimana disebutkan dalam jawaban lain, cara "Ubuntu" adalah menggunakan sudo, dan bukan login root. Ini adalah paradigma yang bermanfaat, dengan keuntungan keamanan yang luar biasa.

trognanders
sumber
saya menggunakan solusi ini dengan cara apa pun, tetapi bagaimana jika saya bisa mendapatkan akses penuh ke sistem file saya sendiri, saya tidak ingin mengetik sudo chow ...untuk setiap direktori tunggal: S
Dimitris Sapikas
2
Mengubah kepemilikan semua file sistem kepada pengguna untuk memberikan kenyamanan sangat tidak dianjurkan. Ini memungkinkan bug userspace yang mungkin Anda temui untuk sangat membahayakan keamanan sistem Anda. Adalah jauh lebih baik untuk mengubah kepemilikan file yang perlu Anda ubah atau perbarui oleh SCP, tetapi meninggalkan semua yang lainnya dimiliki oleh root (seperti seharusnya). Yang mengatakan, -Rdi chownmengatakan untuk mengubah kepemilikan direktori itu, dan semua file anak-anak dan direktori secara rekursif ... sehingga Anda dapat melakukan apa pun yang Anda suka.
trognanders
hmm .... itu sepertinya berfungsi dengan baik, terima kasih! maaf saya tidak bisa memperbaiki (sistem tidak memungkinkan saya untuk melakukan ...)
Dimitris Sapikas
11

Mungkin cara terbaik adalah menggunakan rsync( Cygwin / cwRsync di Windows) melalui SSH?

Misalnya, untuk mengunggah file dengan pemilik www-data:

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

Dalam kasus Anda, jika Anda membutuhkan root privilege, perintahnya akan seperti ini:

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

Lihat: scp ke server jauh dengan sudo .

Alexey Vazhnov
sumber
5

Jika Anda menggunakan alat OpenSSH alih-alih Putty, Anda dapat melakukannya dengan memulai scptransfer file pada server sudo. Pastikan Anda memiliki sshddaemon yang berjalan di mesin lokal Anda. Dengan ssh -RAnda dapat memberikan server cara untuk menghubungi mesin Anda.

Di mesin Anda:

ssh -R 11111:localhost:22 REMOTE_USERNAME@SERVERNAME

Selain masuk Anda di server, ini akan meneruskan setiap koneksi yang dibuat pada port server 11111 ke port mesin Anda 22: port yang sshdsedang Anda dengarkan.

Di server, mulai transfer file seperti ini:

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

Anda dapat menggunakan skrip yang saya tulis terinspirasi oleh topik ini:

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

tetapi ini membutuhkan beberapa hal gila (yang merupakan btw. secara otomatis dilakukan oleh skrip)

  1. server tempat file sedang dikirim tidak akan lagi meminta kata sandi saat membuat koneksi ssh ke komputer sumber
  2. karena perlunya kekurangan sudo prompt di server, sudo tidak akan lagi meminta kata sandi pada mesin jarak jauh, untuk pengguna

Ini dia skripnya:

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
sumber
@Braiam ya, tentu, maaf untuk tautannya, skripnya cukup panjang dan itulah alasannya :)
test30
1

Anda dapat menggabungkan ssh, sudo dan mis tar untuk mentransfer file antar server tanpa bisa login sebagai root dan tidak memiliki izin untuk mengakses file dengan pengguna Anda. Ini sedikit fiddly, jadi saya sudah menulis skrip untuk membantu ini. Anda dapat menemukan skrip di sini: https://github.com/sigmunau/sudoscp

atau di sini:

#! / bin / bash
res = 0
dari = $ 1
ke = $ 2
bergeser
bergeser
files = "$ @"
jika uji -z "$ from" -o -z "$ ke" -o -z "$ files"
kemudian
    echo "Penggunaan: $ 0 (file) *"
    echo "contoh: $ 0 server1 server2 / usr / bin / myapp"
    keluar 1
fi

baca -s -p "Masukkan Kata Sandi:" sudopassword
gema ""
temp1 = $ (mktemp)
temp2 = $ (mktemp)
(echo "$ sudopassword"; echo "$ sudopassword" | ssh $ dari sudo -S tar c -P -C / $ file 2> $ temp1) | ssh $ ke sudo -S tar x -v -P -C / 2 > $ temp2
sourceres = $ {PIPESTATUS [0]}
jika [$? -ne 0 -o $ sourceres -ne 0]
kemudian
    gema "Kegagalan!" > & 2
    gema "$ from output:"> & 2
    cat $ temp1> & 2
    gema ""> & 2
    echo "$ to output:"> & 2
    cat $ temp2> & 2
    res = 1
fi

rm $ temp1 $ temp2
keluar $ res
sigmunda
sumber
Selamat Datang di Tanya Ubuntu. Bisakah Anda memasukkan skrip ke dalam jawaban Anda? Saya tahu itu tidak mungkin tetapi jika repo github pernah dihapus atau url berubah maka jawabannya akan batal. Lebih baik untuk memasukkan skrip secara langsung dan meninggalkan repositori github sebagai sumber.
Michael Lindman
0

Berikut adalah versi modifikasi dari jawaban Willie Wheeler yang mentransfer file melalui tar tetapi juga mendukung pemberian kata sandi ke sudo pada host jarak jauh.

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

Sedikit sihir ekstra di sini adalah opsi -S untuk sudo. Dari halaman manual sudo:

-S, --stdin Tulis prompt ke kesalahan standar dan baca kata sandi dari input standar daripada menggunakan perangkat terminal. Kata sandi harus diikuti oleh karakter baris baru.

Sekarang kita benar-benar ingin output tar untuk disalurkan ke ssh dan yang mengarahkan kembali stdin ssh ke stdout tar, menghapus cara apa pun untuk memasukkan kata sandi ke sudo dari terminal interaktif. (Kita bisa menggunakan fitur ASKPASS sudo pada ujung jarak jauh tetapi itu adalah cerita lain.) Namun kita dapat memasukkan kata sandi ke sudo dengan menangkapnya terlebih dahulu dan menambahkannya ke output tar dengan melakukan operasi-operasi dalam subkulit dan menyalurkan output dari subshell menjadi ssh. Ini juga memiliki keuntungan tambahan karena tidak meninggalkan variabel lingkungan yang berisi kata sandi kami menggantung di shell interaktif kami.

Anda akan melihat saya tidak menjalankan 'baca' dengan opsi -p untuk mencetak prompt. Ini karena prompt kata sandi dari sudo dengan mudah diteruskan kembali ke stderr shell interaktif kami melalui ssh. Anda mungkin bertanya-tanya "bagaimana eksekusi sudo mengingat itu berjalan di dalam ssh di sebelah kanan pipa kami?" Ketika kita menjalankan banyak perintah dan menyalurkan output dari satu ke yang lain, shell induk (shell interaktif dalam kasus ini) mengeksekusi setiap perintah dalam urutan segera setelah mengeksekusi sebelumnya. Karena setiap perintah di belakang pipa dieksekusi, shell induk menempel (mengarahkan) stdout sisi kiri ke stdin sisi kanan. Output kemudian menjadi input saat melewati proses.

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

Shell interaktif kami adalah PID 7168, subshell kami adalah PID 7969 dan proses ssh kami adalah PID 7970.

Satu-satunya kelemahan adalah bahwa membaca akan menerima input sebelum sudo punya waktu untuk mengirimkan kembali prompt itu. Pada koneksi cepat dan host jarak jauh cepat Anda tidak akan melihat ini tetapi Anda mungkin jika salah satu lambat. Penundaan apa pun tidak akan memengaruhi kemampuan untuk memasukkan prompt; mungkin saja muncul setelah Anda mulai mengetik.

Catatan saya hanya menambahkan entri file host untuk "remote_Host" ke mesin lokal saya untuk demo.

Bruce
sumber