時折、リモートサーバにある"ログインユーザでは読み取りができないファイル"をそのままローカルにコピーしたいことがある。 ssh経由でファイルをコピーするといえばscpがよく使われる方法だと思うが、残念ながらscpではリモートサーバ側でsudoを使ってroot権限でファイルを読み込んだりといった事はできない。 さて、じゃどうすればいいのだろうか。

こういったとき、sudoをNOPASSWDで実行可能な状態であれば、単体のファイルであればsshコマンドからsudoを使ってcatで、ディレクトリごとであれば一度tarでアーカイブ化してローカルでそのまま展開させる事ができる。 なお、RHEL系のデフォルトではsudo実行には擬似端末が必要になる(AWSやAzureのCentOSイメージでは手が加えてある様子)のだが、catコマンドはsshコマンド実行時に-ttの付与しておけば良いのだが、tarに関しては擬似端末を利用してのssh越しの実行ができない。 このため、/etc/sudoersにてrequirettyを無効化しておく必要があるので注意。

ssh -t user@host 'sudo cat RemoteFile.path' > LocalFile.path # 単体ファイルの場合
ssh user@host 'sudo tar -C RemoteSourceDir czf - .' | tar -C LocalDestinationDir -xzf - # ディレクトリの場合
blacknon@BS-PUB-DEVELOP:~$ ssh -t test@BS-PUB-CENT7-01 'cat /var/log/secure'
cat: /var/log/secure: 許可がありません
Connection to bs-pub-cent7-01 closed.
blacknon@BS-PUB-DEVELOP:~$ ssh -t test@BS-PUB-CENT7-01 'sudo cat /var/log/secure' > ./secure
Connection to bs-pub-cent7-01 closed.
blacknon@BS-PUB-DEVELOP:~$ tail secure
Jun 12 11:30:58 BS-PUB-CENT7-01 sudo: pam_unix(sudo:auth): auth could not identify password for [test]
Jun 12 11:30:58 BS-PUB-CENT7-01 sshd[21013]: Received disconnect from 172.28.0.171: 11: disconnected by user
Jun 12 11:30:58 BS-PUB-CENT7-01 sshd[21010]: pam_unix(sshd:session): session closed for user test
Jun 12 11:31:01 BS-PUB-CENT7-01 sshd[21118]: Accepted publickey for test from 172.28.0.171 port 46934 ssh2: RSA 81:0c:f5:73:11:2e:e7:d7:8d:4c:fd:b5:cc:3d:40:f5
Jun 12 11:31:03 BS-PUB-CENT7-01 sshd[21118]: pam_unix(sshd:session): session opened for user test by (uid=0)
Jun 12 11:31:04 BS-PUB-CENT7-01 sshd[21121]: Received disconnect from 172.28.0.171: 11: disconnected by user
Jun 12 11:31:04 BS-PUB-CENT7-01 sshd[21118]: pam_unix(sshd:session): session closed for user test
Jun 12 11:31:06 BS-PUB-CENT7-01 sshd[21138]: Accepted publickey for test from 172.28.0.171 port 46936 ssh2: RSA 81:0c:f5:73:11:2e:e7:d7:8d:4c:fd:b5:cc:3d:40:f5
Jun 12 11:31:08 BS-PUB-CENT7-01 sshd[21138]: pam_unix(sshd:session): session opened for user test by (uid=0)
Jun 12 11:31:09 BS-PUB-CENT7-01 sudo:    test : TTY=pts/2 ; PWD=/home/test ; USER=root ; COMMAND=/bin/cat /var/log/secure
blacknon@BS-PUB-DEVELOP:~$ ssh  test@BS-PUB-CENT7-01 'sudo tar -C /var/log -czf - .' | tar -C ./testLogDir/ -xzf -
blacknon@BS-PUB-DEVELOP:~$ ls testLogDir/
anaconda       cron-20170604       lastlog            messages-20170529  secure-20170604   tuned
audit          cron-20170612       maillog            messages-20170604  secure-20170612   wpa_supplicant.log
boot.log       dmesg               maillog-20160306   messages-20170612  spooler           wtmp
btmp           dmesg.old           maillog-20170529   nginx              spooler-20160306  wtmp.bk
btmp-20170601  firewalld           maillog-20170604   ppp                spooler-20170529  yum.log
cron           grubby              maillog-20170612   secure             spooler-20170604
cron-20160306  grubby_prune_debug  messages           secure-20160306    spooler-20170612
cron-20170529  httpd               messages-20160306  secure-20170529    tallylog

なお、この時sudo実行時にパスワードが必要な場合、以下のように標準入力から受付けさせるようにする。 この際標準エラー出力を/dev/nullに吐かせないと、sudoのパスワード入力プロンプトがリダイレクト先に出力されてしまうので注意。 (サンプルでは、量が多くなるのでtailで取得している)

ssh -t user@host 'echo Password |sudo -S cat RemoteFile.path 2>/dev/null' > LocalFile.path # パイプで渡す場合
ssh -t user@host 'sudo -S cat RemoteFile.path 2>/dev/null' > LocalFile.path # プロンプト等出ないが、そのままパスワードを入力
ssh user@host 'echo Password | sudo -S tar -C RemoteSourceDir -czf - . 2>/dev/null' | tar -C LocalDestinationDir -xzf - # パスワードをパイプで渡してディレクトリごと取得する場合
blacknon@BS-PUB-DEVELOP:~$ ssh -t blacknon@BS-PUB-UBUNTU-01.blacknon.local 'sudo -S tail -5 /var/log/syslog 2>/dev/null' > tail_test3.log
blacknon@bs-pub-ubuntu-01.blacknon.local's password:
Connection to bs-pub-ubuntu-01.blacknon.local closed.
blacknon@BS-PUB-DEVELOP:~$ cat tail_test3.log
Jun 13 00:07:50 BS-PUB-UBUNTU-01 systemd[1]: Started Session 3347 of user blacknon.
Jun 13 00:08:10 BS-PUB-UBUNTU-01 systemd[1]: Started Session 3348 of user blacknon.
Jun 13 00:08:33 BS-PUB-UBUNTU-01 systemd[1]: Started Session 3349 of user blacknon.
Jun 13 00:10:13 BS-PUB-UBUNTU-01 systemd[1]: Started Session 3350 of user blacknon.
Jun 13 00:10:27 BS-PUB-UBUNTU-01 systemd[1]: Started Session 3351 of user blacknon.
blacknon@BS-PUB-DEVELOP:~$
blacknon@BS-PUB-DEVELOP:~$ ssh -t blacknon@BS-PUB-UBUNTU-01.blacknon.local 'echo Password | sudo -S tail -5 /var/log/syslog 2>/dev/null' > tail_test3.log
blacknon@bs-pub-ubuntu-01.blacknon.local's password:
Connection to bs-pub-ubuntu-01.blacknon.local closed.
blacknon@BS-PUB-DEVELOP:~$ cat tail_test3.log
Jun 13 00:10:48 BS-PUB-UBUNTU-01 sm-mta[29803]: v57LUkgo005932: to=<root@BS-PUB-UBUNTU-01.BLACKNON.LOCAL>, delay=4+17:40:01, xdelay=00:00:00, mailer=local, pri=61410000, dsn=4.0.0, stat=Operating system error
Jun 13 00:10:48 BS-PUB-UBUNTU-01 sm-mta[29825]: v57LP2gm005928: Warning: program /usr/sbin/sensible-mda unsafe: No such file or directory
Jun 13 00:10:48 BS-PUB-UBUNTU-01 sm-mta[29825]: v57LP2gm005928: SYSERR(root): Cannot exec /usr/sbin/sensible-mda: No such file or directory
Jun 13 00:10:48 BS-PUB-UBUNTU-01 sm-mta[29803]: v57LP2gm005928: to=<root@BS-PUB-UBUNTU-01.BLACKNON.LOCAL>, ctladdr=<root@BS-PUB-UBUNTU-01.BLACKNON.LOCAL> (0/0), delay=4+17:45:46, xdelay=00:00:00, mailer=local, pri=61501361, dsn=4.0.0, stat=Operating system error
Jun 13 00:10:52 BS-PUB-UBUNTU-01 systemd[1]: Started Session 3352 of user blacknon.
blacknon@BS-PUB-DEVELOP:~$ ssh -i testkey blacknon@BS-PUB-UBUNTU-01.blacknon.local 'echo Password | sudo -S tar -C /var/log -czf - . 2>/dev/null' | tar -C ./testLogDir2 -xzf -
blacknon@BS-PUB-DEVELOP:~$ ls -a testLogDir2
.                      auth.log       dmesg.1.gz     faillog         mail.err.1     syslog.1
..                     auth.log.1     dmesg.2.gz     fontconfig.log  mail.err.2.gz  syslog.2.gz
alternatives.log       auth.log.2.gz  dmesg.3.gz     fsck            mail.err.3.gz  syslog.3.gz
alternatives.log.1     auth.log.3.gz  dmesg.4.gz     installer       mail.err.4.gz  syslog.4.gz
alternatives.log.2.gz  auth.log.4.gz  dpkg.log       kern.log        mail.log       syslog.5.gz
alternatives.log.3.gz  boot.log       dpkg.log.1     kern.log.1      mail.log.1     syslog.6.gz
alternatives.log.4.gz  bootstrap.log  dpkg.log.2.gz  kern.log.2.gz   mail.log.2.gz  syslog.7.gz
alternatives.log.5.gz  btmp           dpkg.log.3.gz  kern.log.3.gz   mail.log.3.gz  unattended-upgrades
apport.log             btmp.1         dpkg.log.4.gz  kern.log.4.gz   mail.log.4.gz  upstart
apport.log.1           dist-upgrade   dpkg.log.5.gz  landscape       maltrail       wtmp
apport.log.2.gz        dmesg          dpkg.log.6.gz  lastlog         mysql          wtmp.1
apt                    dmesg.0        dpkg.log.7.gz  mail.err        syslog