scpでルートアクセスが必要なファイルをコピーするにはどうすればよいですか?


168

SSHを使用して接続しているUbuntuサーバーがあります。

マシンから/var/www/サーバーにファイルをアップロードする必要があります。ファイルの/var/www/所有者はrootです。

ログイン後、PuTTYを使用して、でsudo suファイルを変更できるようにするには、最初にパスワードを入力する必要があります/var/www/

しかし、私はWinSCPのを使用してファイルをコピーしていたとき、私は/作成中のファイルを変更作成することはできません/var/www/私はとの接続てるユーザがファイルのアクセス許可を持っていないため、/var/www/と私が言うことができないsudo su私は、sshセッションの場合にはそうであるように。

私はこれに対処する方法を知っていますか?

ローカルマシンで作業してgksudo nautilusいる場合は、電話をかけますが、この場合、マシンへのターミナルアクセスしかありません。


これは、仮想サーバープロバイダー、またはパテまたはwinscp開発者にとっての質問のようです。
-dobey

7
@dobeyあなたは明らかに間違っています、それはubuntu特権についてです!
ディミトリスサピカス

7
なぜこれは閉じられているのですか?これは、SCPでファイルをコピーすることについて完全に有効な質問です-すべてのWeb開発者は、このような状況に精通している
セルゲイ


同様の問題があります。Windowsコンピューターでファイル(この場合はHTML)を作成し、WinSCPを使用して/ var / www / html / websiteフォルダーにコピーしようとします。そして、許可の問題があると言います。/ homeフォルダーにコピーできるため、2つのステップでファイルをコピーしましたが、あまり便利ではありません:-)ユーザーをwww-dataグループに追加しようとしましたが、助けにはなりませんでした。ユーザーをwww-dataに追加しても、ユーザーがwww-dataグループが所有するフォルダーにファイルをコピーできないのはなぜですか?
ヤネスクラニスキ

回答:


126

そうです、でsudo作業するときはありませんscp。回避策はscp、ユーザーがファイルを作成する権限を持っているディレクトリにファイルをアップロードするために使用し、ssh経由でログインsudoし、最終目的地にファイルを移動/コピーするために使用することです。

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

別の解決策は、ファイルをアップロードするディレクトリのアクセス権/所有権を変更することです。そうすれば、非特権ユーザーはそれらのディレクトリに書き込むことができます。

通常、rootアカウントでの作業はルールではなく例外である必要があります-あなたの質問の言い回しの仕方は、おそらくあなたがそれを少し乱用していると思うようになります。自分のファイルにアクセスするためのスーパー管理者特権。

技術的には、Ubuntuをとして直接ログインできるように設定できますrootが、この機能は理由により無効になっているため、これを行うことを強くお勧めします。


最初の解決策を見つけられませんでした。
ディミトリスサピカス

私は自分のファイルを言うWHE私は完全なアクセス権を持っているの/ var / WWW、私は自分のフォルダに.... Webサーバとしての私のVPSを使用しています意味
ディミトリスSapikas

7
Re。最初の解決策。1. scp -R mysite dimitris@myserver.com:/home/dimitris/2. ssh dimitris@myserver.com3.- sudo mv ~/mysite /var/wwwそれは2ステップのプロセスです。最初にscpホームディレクトリにファイルを配置し、次にsshを使用してログインし、ファイルを本来の場所にコピー/移動します
Sergey

36

別の方法は、scpの代わりにtar + sshを使用してコピーすることです。

tar -c -C ./my/local/dir \
  | ssh dimitris@myserver.com "sudo tar -x --no-same-owner -C /var/www"

2
これが最善の方法です。
mttdbrd

2
このメソッドを正常に動作させることはできません。書かれているように私は得るsudo: sorry, you must have a tty to run sudo。「-t」を追加してTTYを割り当てると、が得られPseudo-terminal will not be allocated because stdin is not a terminal.ます。パスワードなしのsudoがなければ、これが機能することはありません。
IBBoard

1
@IBBoard:ソリューションを試してみてください、ここでのssh -tを使用して:ssh -t dimitris@myserver.com "sudo tar -x --no-same-owner -C /var/www"
アレクサンダー鳥

2
@AlexanderBirdこれは多くの場合に機能しますが、SSH接続を介してtarballをパイプしようとしているため、ここで機能するかどうかはわかりません。参照してくださいserverfault.com/questions/14389/...
IBBoard

これは最終的に私のために働いたものです。ローカルにコピーするリモートファイルへのアクセス許可がなく、aを実行しsudo tar、アーカイブし、chmodand を使用してアクセス許可を変更しchownてから、ローカルにコピーします。特にディレクトリの場合。
フォーラムの

28

簡単な方法

サーバーからローカルマシンへ:

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

ローカルマシンからサーバーへ:

cat /home/user/file | ssh user@server "sudo tee -a /etc/dir/file"

5
この答えは過小評価されています。シンプルでクリーンで、単一のアトミック操作でルートファイルの読み取りまたは書き込みを行います。scpを使用している場合、そこにあることが保証されていないものは何も必要ありません。主な欠点は、許可をコピーしないことです。必要な場合は、tarソリューションの方が優れています。これは、特にパスをトラバースするxargs / bashマジックと組み合わせた場合、強力な手法です
。– markgo2k

私は質問がリモートにローカルではなくその逆からファイルをアップロードについてだったと思う
Korayem

1
美しくできました。これはまさに私がアップダウン両方を探していたものです。ありがとう
ジェレミー

間違いなく一番の答えに値する。
アンドリューワトソン

これは、ファイルではなくディレクトリに対しても実行できますか?
lucidbrot

26

ansibleこれを実現するためにも使用できます。

ansibleのcopyモジュールを使用してリモートホストにコピーします

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

ansibleのfetchモジュールを使用してリモートホストから取得します

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

注意:

  • -i HOST,構文のカンマはタイプミスではありません。インベントリファイルを必要とせずにansibleを使用する方法です。
  • -bサーバーでのアクションをルートとして実行します。-bに展開され--become、デフォルト--become-userはrootで、デフォルト--become-methodはsudoです。
  • flat=yesコピーだけでファイルは、ファイルにつながる全体のリモートパスをコピーしません。
  • これらのansibleモジュールでは、ファイルパスでワイルドカードを使用することはサポートされていません。
  • ディレクトリをコピーすることはされてによってサポートされcopyますが、モジュールではないことにより、fetchモジュール。

この質問の特定の呼び出し

配布するファイルを含むローカルホスト上のディレクトリがsourcedirであり、リモートターゲットのホスト名がhostname次のとおりであると仮定して、具体的で完全に指定された例を次に示します。

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

簡潔な呼び出しの場合:

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

PS、「このすばらしいツールをインストールするだけ」というのは、一種の耳が聞こえない答えだと思います。しかし、リモートサーバーの管理にはansibleが非常に役立つことがわかったため、リモートサーバーをインストールすると、ファイルを展開すること以外の利点が確実に得られます。


私はこの答えが好きですが、投票する前に、より一般化された解説に対して、質問に答えることをお勧めします。ようなものansible -i "hostname," all -u user --become -m copy -a ...
マイクD

@MikeD:上記の変更はどのように見えますか?
erik.weathers

1
-i 'host,'有効な構文のようなものはありますか?コマンドを読むとき、そのような句読点を失うのは簡単だと思います。(読者にとっては、シェルではないにしても。)
mwfearnley

1
@mwfearnley:確かに、シェルはor -i 'host,'と同じように処理します。一般的に、これらの呼び出しを困難なものにしないために、できる限り短くすることを好みますが、明確にするために必要と思われるように、冗長かつ明示的にすることをお勧めします。-i host,-i "host,"
erik.weathers

2
枠を超えて考える方法 Ansibleの
優れた

12

を実行するとsudo su、作成したファイルはすべてrootによって所有されますが、デフォルトでは、sshまたはscpを使用してrootとして直接ログインすることはできません。scpでsudoを使用することもできないため、ファイルは使用できません。これを修正するには、ファイルの所有権を主張します。

ユーザー名がdimitriであると仮定すると、このコマンドを使用できます。

sudo chown -R dimitri:dimitri /home/dimitri

それ以降、他の回答で述べたように、「Ubuntu」の方法はルートログインではなくsudoを使用することです。これは便利なパラダイムであり、セキュリティ上の大きな利点があります。


私はどのような方法このソリューションを使用していますが、私は自分のファイルシステムへのフルアクセスを得ることができれば、私は入力したくないものをsudo chow ...一つ一つのディレクトリ:S
ディミトリスSapikas

2
利便性を渡すために、すべてのシステムファイルの所有権をユーザーに変更することはお勧めしません。これにより、発生する可能性のあるユーザースペースのバグがシステムのセキュリティを大幅に侵害する可能性があります。SCPによって変更または更新する必要のあるファイルの所有権を変更することをお勧めしますが、他のすべてをルートが所有しているようにします(本来のように)。そうは言っても、-Rin chownはそのディレクトリの所有権、およびすべての子ファイルとディレクトリを再帰的に変更するように指示します。
トログナンダー

うーん....それはうまく機能しているようです、ありがとう!申し訳ありませんが、私は
投票

11

かもしれ最良の方法は、使用することですrsyncCygwinの / cwRsync SSH経由でWindowsでの)?

たとえば、所有者がいるファイルをアップロードするにはwww-data

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

あなたの場合、ルート権限が必要な場合、コマンドは次のようになります。

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

参照してください:sudoのを使ってリモートサーバにscpコマンド


5

PuTTYの代わりにOpenSSHツールを使用する場合scpは、サーバーでファイル転送を開始することでこれを実現できますsudosshdローカルマシンでデーモンが実行されていることを確認してください。ではssh -R、サーバーをあなたのマシンに連絡する方法を与えることができます。

あなたのマシンで:

ssh -R 11111:localhost:22 REMOTE_USERNAME@SERVERNAME

サーバーにログインすることに加えて、これはサーバーのポート11111で行われたすべての接続をマシンのポート22(あなたsshdがリッスンしているポート)に転送します。

サーバーで、次のようにファイル転送を開始します。

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

1

このトピックに触発されて書いたスクリプトを使用できます。

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

しかし、これにはいくつかのクレイジーなものが必要です(これはスクリプトによって自動的に行われます)

  1. ファイルの送信先サーバーは、ソースコンピューターへのssh接続の確立中にパスワードを要求しなくなります
  2. サーバーにsudoプロンプトがないことが必要なため、sudoはユーザーのリモートマシンでパスワードを要求しなくなりました

スクリプトは次のとおりです。

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

@ブライアムええ、確かに、リンクは申し訳ありませんが、スクリプトはかなり長く、それが理由でした:)
test30

1

ssh、sudo、tarなどを組み合わせて、rootとしてログインできず、ユーザーにファイルにアクセスする権限がない場合でも、サーバー間でファイルを転送できます。これは少し厄介なので、これを支援するスクリプトを作成しました。スクリプトは次の場所にありますhttps : //github.com/sigmunau/sudoscp

またはここ:

#!/ bin / bash
res = 0
from = $ 1
to = $ 2
シフト
シフト
files = "$ @"
if test -z "$ from" -o -z "$ to" -o -z "$ files"
それから
    echo "使用法:$ 0(ファイル)*"
    echo "例:$ 0 server1 server2 / usr / bin / myapp"
    1番出口
fi

read -s -p "パスワードを入力:" sudopassword
エコー ""
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]
それから
    echo "失敗!" >&2
    echo "$ from output:">&2
    cat $ temp1>&2
    エコー "">&2
    echo "$ to output:">&2
    cat $ temp2>&2
    res = 1
fi

rm $ temp1 $ temp2
$ resを終了

Ask Ubuntuへようこそ。答えにスクリプトを含めていただけますか?ありそうもないことはわかっていますが、githubリポジトリが削除されたりURLが変更されたりすると、答えは無効になります。スクリプトを直接インクルードし、githubリポジトリをソースとして残すことをお勧めします。
マイケルリンドマン

0

これは、ファイルをtar経由で転送するが、リモートホスト上のsudoへのパスワードの受け渡しもサポートするWillie Wheelerの回答の修正版です。

(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の-Sオプションです。sudoのmanページから:

-S、--stdinプロンプトを標準エラーに書き込み、端末デバイスを使用する代わりに標準入力からパスワードを読み取ります。パスワードの後に​​改行文字を続ける必要があります。

ここで、実際にtarの出力をsshにパイプし、sshのstdinをtarのstdoutにリダイレクトし、対話式端末からsudoにパスワードを渡す方法を削除します。(リモートエンドでsudoのASKPASS機能を使用できますが、それは別の話です。)パスワードを事前にキャプチャし、サブシェルでこれらの操作を実行してtar出力に追加することで、sudoにパスワードを取得できますサブシェルをsshに。これには、パスワードが含まれる環境変数を対話型シェルに残さないという利点もあります。

プロンプトを表示するために-pオプションを指定して 'read'を実行しなかったことにお気づきでしょう。これは、sudoからのパスワードプロンプトが、sshを介してインタラクティブシェルのstderrに便利に戻されるためです。「パイプの右側のssh内でsudoが実行されている場合、sudoはどのように実行されますか?」複数のコマンドを実行し、1つの出力を別のコマンドにパイプすると、親シェル(この場合は対話型シェル)は、前のコマンドを実行した直後にシーケンス内の各コマンドを実行します。パイプの背後にある各コマンドが実行されると、親シェルは左側の標準出力を右側の標準入力にアタッチ(リダイレクト)します。出力は、プロセスを通過するときに入力になります。

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

インタラクティブシェルはPID 7168、サブシェルはPID 7969、sshプロセスはPID 7970です。

唯一の欠点は、sudoがプロンプトを送り返す前にreadが入力を受け入れることです。高速接続と高速リモートホストでは、これに気付くことはありませんが、どちらかが遅い場合は気付くかもしれません。遅延しても、プロンプトを入力する機能には影響しません。入力を開始した後に表示される場合があります。

注:デモ用にローカルマシンに「remote_Host」のホストファイルエントリを追加しただけです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.