Jak skopiować pliki wymagające dostępu do konta root za pomocą scp?

167

Mam serwer Ubuntu, z którym łączę się za pomocą SSH.

Muszę przesłać pliki z mojego komputera /var/www/na serwer, pliki /var/www/są własnością root.

Korzystając z PuTTY, po zalogowaniu muszę sudo sunajpierw wpisać hasło i hasło, aby móc modyfikować pliki /var/www/.

Ale kiedy kopiuję pliki za pomocą WinSCP, nie mogę tworzyć plików do tworzenia / modyfikowania /var/www/, ponieważ użytkownik, z którym się łączę, nie ma uprawnień do plików /var/www/i nie mogę powiedzieć, sudo suco mam w przypadku sesji ssh .

Czy wiesz jak sobie z tym poradzić?

Gdybym pracował na moim komputerze lokalnym, zadzwoniłbym, gksudo nautilusale w tym przypadku mam tylko dostęp do terminalu.

Dimitris Sapikas
źródło
To wydaje się bardziej pytaniem dla twojego wirtualnego dostawcy serwera, lub dla deweloperów putty lub winscp.
dobey,
7
@Dobey, oczywiście, że się mylisz, chodzi o przywileje ubuntu!
Dimitris Sapikas
7
Dlaczego to jest zamknięte? To jest całkowicie poprawne pytanie dotyczące kopiowania plików za pomocą scp - każdy programista zna tę sytuację
Sergey
Mam podobny problem. Tworzę plik (w tym przypadku HTML) na komputerze z systemem Windows i próbuję skopiować go za pomocą WinSCP do folderu / var / www / html / website. I mówi, że jest problem z pozwoleniem. Ponieważ mogę skopiować do folderu / home, skopiowałem plik w dwóch krokach, ale nie jest to zbyt wygodne :-) Próbowałem z dodaniem mojego użytkownika do grupy www-data, ale to nie pomogło. Masz pojęcie, dlaczego dodanie użytkownika do danych www nadal nie pozwala użytkownikowi skopiować pliku do folderu, który jest własnością grupy danych www?
JanezKranjski

Odpowiedzi:

125

Masz rację, nie ma, sudokiedy pracujesz scp. Obejściem tego problemu jest scpprzesłanie plików do katalogu, w którym użytkownik ma uprawnienia do tworzenia plików, a następnie zalogowanie się za pomocą ssh i sudoprzeniesienie / skopiowanie plików do miejsca docelowego.

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

Innym rozwiązaniem może być zmiana uprawnień / własności katalogów, do których przesyłasz pliki, aby Twój nieuprzywilejowany użytkownik mógł pisać do tych katalogów.

Ogólnie rzecz biorąc, praca na rootkoncie powinna być wyjątkiem, a nie regułą - sposób, w jaki piszesz swoje pytanie, sprawia, że ​​myślę, że możesz go trochę nadużywać, co z kolei prowadzi do problemów z uprawnieniami - w normalnych okolicznościach nie potrzebujesz uprawnienia superadministratora do uzyskiwania dostępu do własnych plików.

Technicznie rzecz biorąc, możesz skonfigurować Ubuntu, aby zezwalał na zdalne logowanie bezpośrednio jako root, ale ta funkcja jest wyłączona z jakiegoś powodu, więc zdecydowanie odradzam to robić.

Siergiej
źródło
nie dostałem pierwszego rozwiązania, czy mógłbyś być trochę bardziej specyficzny?
Dimitris Sapikas
Kiedy mówię, że moje własne pliki mam na myśli / var / www, używam mojego vps jako serwera WWW .... na własnym folderze mam pełny dostęp
Dimitris Sapikas
7
Re. pierwsze rozwiązanie. 1. scp -R mysite [email protected]:/home/dimitris/2. ssh [email protected]3. sudo mv ~/mysite /var/www- jest to proces dwuetapowy, najpierw scppliki do katalogu domowego, następnie logujesz się przez ssh i kopiujesz / przenosisz pliki tam, gdzie powinny być
Sergey
36

Inną metodą jest kopiowanie przy użyciu tar + ssh zamiast scp:

tar -c -C ./my/local/dir \
  | ssh [email protected] "sudo tar -x --no-same-owner -C /var/www"
Willie Wheeler
źródło
2
To najlepszy sposób, aby to zrobić.
mttdbrd
2
Nie mogę sprawić, by ta metoda działała pomyślnie. Jak napisałem, rozumiem sudo: sorry, you must have a tty to run sudo. Jeśli dodam „-t”, aby przydzielić TTY, to dostanę Pseudo-terminal will not be allocated because stdin is not a terminal.. Nie widzę tego działającego bez sudo bez hasła.
IBBoard
1
@IBBoard: wypróbuj rozwiązanie tutaj, używając ssh -t:ssh -t [email protected] "sudo tar -x --no-same-owner -C /var/www"
Alexander Bird
2
@AlexanderBird Chociaż działa to w wielu przypadkach, nie jestem pewien, czy to działa tutaj, ponieważ próbujemy przesłać tarball przez połączenie SSH. Zobacz serverfault.com/questions/14389/…
IBBoard
To w końcu dla mnie zadziałało. Nie masz uprawnień do zdalnego pliku, który chcesz skopiować do lokalnego, wykonaj sudo tar, zarchiwizuj go, zmień uprawnienia za pomocą chmodi chown, a następnie skopiuj go do lokalnego. Zwłaszcza jeśli jest to katalog.
forumulator
27

Szybki sposób

Z serwera na komputer lokalny:

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

Z komputera lokalnego na serwer:

cat /home/user/file | ssh user@server "sudo tee -a /etc/dir/file"
Anderson Lira
źródło
5
Ta odpowiedź jest niedoceniana. Jest prosty, czysty, odczytuje lub zapisuje plik główny za pomocą pojedynczej operacji atomowej i nie wymaga niczego, co nie jest jeszcze gwarantowane, jeśli używasz scp. Główną wadą jest to, że nie kopiuje uprawnień. Jeśli tego chcesz, rozwiązanie tar jest lepsze. Jest to potężna technika, szczególnie w połączeniu z magią xargs / bash do przemierzania ścieżek.
markgo2k
Myślę, że pytanie dotyczyło przesłania pliku z lokalnego do zdalnego, a nie odwrotnie
Korayem,
1
Pięknie zrobione. Właśnie tego szukałem zarówno w górę, jak i w dół. Dziękuję
Jeremy
Na pewno zasługuje na najwyższą odpowiedź.
Andrew Watson,
Czy można to zrobić również dla katalogu zamiast pliku?
lucidbrot
26

Możesz również użyć ansibledo tego celu.

Skopiuj na zdalny host za pomocą modułu ansiblecopy :

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

Pobierz ze zdalnego hosta za pomocą modułu ansiblefetch :

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

UWAGA:

  • Przecinek w -i HOST,składni nie jest literówką. Jest to sposób na użycie ansible bez potrzeby posiadania pliku inwentarza.
  • -bpowoduje, że akcje na serwerze są wykonywane jako root. -brozwija się do --become, a domyślnie --become-userjest to root, przy czym domyślnie --become-methodjest to sudo.
  • flat=yeskopiuje tylko plik, nie kopiuje całej zdalnej ścieżki prowadzącej do pliku
  • Korzystanie z symboli wieloznacznych w ścieżkach plików nie jest obsługiwane przez te moduły ansible.
  • Kopiowanie katalogu jest obsługiwane przez copymoduł, ale nie przez fetchmoduł.

Konkretne wywołanie tego pytania

Oto przykład, który jest konkretny i w pełni określony, przy założeniu, że katalog na twoim hoście lokalnym zawierający pliki do dystrybucji to sourcediri że nazwa hosta zdalnego celu to hostname:

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

Zwięzłe wywołanie jest następujące:

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

PS, zdaję sobie sprawę z tego, że powiedzenie „po prostu zainstaluj to wspaniałe narzędzie” jest jakby głuchą odpowiedzią. Ale uważam, że jest bardzo przydatny do administrowania zdalnymi serwerami, więc zainstalowanie go z pewnością przyniesie inne korzyści poza wdrażaniem plików.

erik.weathers
źródło
Podoba mi się ta odpowiedź, ale zalecam skierowanie jej na zadane pytanie w porównaniu z bardziej ogólnym komentarzem przed głosowaniem. coś w styluansible -i "hostname," all -u user --become -m copy -a ...
Mike D
@MikeD: jak wyglądają powyższe zmiany?
erik.weathers
1
Czy coś w rodzaju -i 'host,'poprawnej składni? Myślę, że łatwo jest stracić taką interpunkcję podczas czytania polecenia. (Dla czytelnika mam na myśli, jeśli nie skorupę).
mwfearnley
1
@mwfearnley: na pewno powłoka będzie traktować to -i 'host,'samo co -i host,lub -i "host,". Zasadniczo wolę, aby te inwokacje były jak najkrótsze, aby nie zniechęcały, ale powinieneś swobodnie wypowiadać się tak wyraźnie, jak uważasz, że jest to konieczne dla jasności.
erik.weathers
2
Spróbować myśleć nieszablonowo! Świetne użycie Ansible
jonatan
12

Po uruchomieniu sudo suwszelkie utworzone pliki będą własnością root, ale domyślnie nie można zalogować się bezpośrednio jako root za pomocą ssh lub scp. Nie można również używać sudo z scp, więc pliki nie są użyteczne. Napraw to, zgłaszając własność do swoich plików:

Zakładając, że twoja nazwa użytkownika to dimitri, możesz użyć tego polecenia.

sudo chown -R dimitri:dimitri /home/dimitri

Odtąd, jak wspomniano w innych odpowiedziach, sposobem „Ubuntu” jest używanie sudo, a nie rootowanie. Jest to użyteczny paradygmat z dużymi zaletami bezpieczeństwa.

trognandery
źródło
korzystam z tego rozwiązania w jakikolwiek sposób, ale co, jeśli mógłbym uzyskać pełny dostęp do własnego systemu plików, nie chcę pisać sudo chow ...dla każdego pojedynczego katalogu: S
Dimitris Sapikas
2
Odradza się zmianę własności wszystkich plików systemowych na użytkownika w celu przekazania wygody. Pozwala to każdemu napotkanemu błędowi przestrzeni użytkownika poważnie zagrozić bezpieczeństwu twojego systemu. O wiele lepiej jest zmienić własność plików, które należy zmienić lub zaktualizować przez SCP, ale pozostawić wszystko inne, co należy do roota (tak jak powinno być). To powiedziawszy, -Rin chownmówi mu, aby zmieniła własność tego katalogu, a wszystkie pliki i katalogi podrzędne rekurencyjnie ... abyś mógł robić, co chcesz.
trognanders
hmm .... to wydaje się działać dobrze, dziękuję! przepraszam, nie mogę głosować dalej (system nie pozwala mi to zrobić ...)
Dimitris Sapikas
11

Czy najlepszym sposobem może być użycie rsync( Cygwin / cwRsync w Windows) przez SSH?

Na przykład, aby przesłać pliki z właścicielem www-data:

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

W twoim przypadku, jeśli potrzebujesz uprawnień roota, polecenie będzie wyglądać tak:

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

Zobacz: scp do zdalnego serwera za pomocą sudo .

Aleksiej Waznow
źródło
5

Jeśli używasz narzędzi OpenSSH zamiast PuTTY, możesz to zrobić, inicjując scptransfer plików na serwerze za pomocą sudo. Upewnij się, że sshdna komputerze lokalnym działa demon. Dzięki temu ssh -Rmożesz dać serwerowi sposób na skontaktowanie się z twoim komputerem.

Na twoim komputerze:

ssh -R 11111:localhost:22 REMOTE_USERNAME@SERVERNAME

Oprócz zalogowania się na serwerze, przekieruje ono każde połączenie wykonane na porcie 11111 serwera do portu 22 komputera: portu, na którym sshdnasłuchujesz.

Na serwerze rozpocznij przesyłanie plików w następujący sposób:

cd /var/www/
sudo scp -P 11111 -r LOCAL_USERNAME@localhost:FOLDERNAME .
bergoid
źródło
1

Możesz użyć skryptu, który napisałem, inspirowanego tym tematem:

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

ale wymaga to trochę szalonych rzeczy (które są przy okazji automatycznie wykonywane przez skrypt)

  1. serwer, do którego wysyłany jest plik, nie będzie już pytał o hasło podczas nawiązywania połączenia ssh z komputerem źródłowym
  2. z powodu konieczności braku monitu sudo na serwerze, sudo nie będzie już pytać o hasło na zdalnym komputerze dla użytkownika

Oto skrypt:

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
źródło
@Braiam, tak, przepraszam za link, skrypt jest dość długi i to był powód :)
test30
1

Możesz łączyć ssh, sudo i np. Tar, aby przenosić pliki między serwerami bez możliwości logowania się jako root i bez uprawnień dostępu do plików z użytkownikiem. Jest to trochę dziwne, więc napisałem skrypt, aby to pomóc. Skrypt można znaleźć tutaj: https://github.com/sigmunau/sudoscp

lub tu:

#! / bin / bash
res = 0
od = 1 $
do = 2 USD
przesunięcie
przesunięcie
pliki = „$ @”
jeśli test -z "$ z" -o -z "$ do" -o -z "$ pliki"
następnie
    echo „Użycie: 0 $ (plik) *”
    echo "przykład: $ 0 serwer1 serwer2 / usr / bin / myapp"
    wyjście 1
fi

czytaj -s -p „Wpisz hasło:” sudopassword
Echo ""
temp1 = $ (mktemp)
temp2 = $ (mktemp)
(echo "$ sudopassword"; echo "$ sudopassword" | ssh $ z sudo -S tar c -P -C / $ pliki 2> $ temp1) | ssh $ do sudo -S tar x -v -P -C / 2 > $ temp2
sourceres = $ {PIPESTATUS [0]}
jeśli [$? -ne 0 -o $ sourceres -ne 0]
następnie
    echo „Niepowodzenie!” > I 2
    echo „$ from output:”> & 2
    cat $ temp1> i 2
    echo „”> i 2
    echo „$ to output:”> & 2
    cat $ temp2> i 2
    res = 1
fi

rm $ temp1 $ temp2
exit $ res
Sigmunda
źródło
Witamy w Ask Ubuntu. Czy możesz podać skrypt w swojej odpowiedzi? Wiem, że jest to mało prawdopodobne, ale jeśli repozytorium github zostanie kiedykolwiek usunięte lub zmieni się adres URL, odpowiedź będzie nieważna. Lepiej jest dołączyć skrypt bezpośrednio i pozostawić repozytorium github jako źródło.
Michael Lindman
0

Oto zmodyfikowana wersja odpowiedzi Willie Wheeler, która przesyła pliki przez tar, ale obsługuje także przekazywanie hasła do sudo na zdalnym hoście.

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

Odrobina dodatkowej magii tutaj to opcja -S sudo. Ze strony podręcznika sudo:

-S, --stdin Napisz monit o błędzie standardowym i odczytaj hasło ze standardowego wejścia zamiast korzystać z urządzenia końcowego. Hasło musi poprzedzać znak nowej linii.

Teraz tak naprawdę chcemy, aby wyjście tar zostało przesłane do ssh, co przekieruje standardowe wejście ssh na standardowe wyjście tar, usuwając wszelkie sposoby przekazywania hasła do sudo z interaktywnego terminalu. (Możemy użyć funkcji sudo ASKPASS na odległym końcu, ale to inna historia.) Możemy dostać hasło do sudo, przechwytując je z wyprzedzeniem i przygotowując je do wyjścia tar, wykonując te operacje w podpowłoce i przesyłając dane wyjściowe podpowłoka w ssh. Ma to tę dodatkową zaletę, że nie pozostawia zmiennej środowiskowej zawierającej nasze hasło wiszące w interaktywnej powłoce.

Zauważysz, że nie wykonałem polecenia „czytaj” z opcją -p, aby wydrukować monit. Wynika to z faktu, że zapytanie o hasło z sudo jest wygodnie przekazywane z powrotem do stderr naszej interaktywnej powłoki przez ssh. Możesz się zastanawiać "jak działa sudo, biorąc pod uwagę, że działa ono w ssh po prawej stronie naszej rury?" Kiedy wykonujemy wiele poleceń i przesyłamy dane wyjściowe jednego do drugiego, powłoka nadrzędna (w tym przypadku powłoka interaktywna) wykonuje każde polecenie w sekwencji natychmiast po wykonaniu poprzedniego. Gdy każde polecenie za potokiem jest wykonywane, powłoka nadrzędna dołącza (przekierowuje) wyjście standardowej strony lewej do standardowej strony prawej. Dane wyjściowe stają się następnie danymi wejściowymi, gdy przechodzą przez procesy.

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

Nasza interaktywna powłoka to PID 7168, nasza podpowłoka to PID 7969, a nasz proces ssh to PID 7970.

Jedyną wadą jest to, że read zaakceptuje dane wejściowe, zanim sudo zdąży odesłać swój monit. W przypadku szybkiego połączenia i szybkiego zdalnego hosta nie zauważysz tego, ale możesz to zrobić, jeśli jedno z nich jest wolne. Każde opóźnienie nie wpłynie na możliwość wprowadzenia monitu; może pojawić się po rozpoczęciu pisania.

Uwaga Po prostu dodałem wpis pliku hosta dla „remote_Host” do mojego komputera lokalnego w celu pokazu.

Bruce
źródło