sftpコマンドを非対話形式で実行


はじめに

SFTPコマンドは、基本は対話形式ですが、batch modeやヒアドキュメントを使えば、非対話形式で実行することもできます。セキュリティの都合上、システム間のファイル連携を、SFTPサーバ経由でする、といったことは、今でもよくある話です。今回は、一番面倒な、パスフレーズ付きの秘密鍵を使った、公開鍵認証方式でいきます。

また、今更な話題ですが、opensshの開発チームが、scpは古くて使いづらく、sftpかrsyncを使うのを推奨するというのを、2019年4月に出しています。

The scp protocol is outdated, inflexible and not readily fixed. We
recommend the use of more modern protocols like sftp and rsync for
file transfer instead.

この流れは続いてるらしく、scpからsftpへの置き換えを検討しているようです。

A near-future release of OpenSSH will switch scp(1) from using the
legacy scp/rcp protocol to using SFTP by default.

サーバ間のファイルのやりとりは、sftpかrsyncのどちらかに今後はなっていくと思われます。

事前準備

パスフレーズつきの秘密鍵

いまどきは、ed25519で作成したいものです。

$ ssh-keygen -t ed25519 
...
Enter passphrase (empty for no passphrase): 
Enter same passphrase again:

そうもいかない場合は、RSAの4096bitでいきましょう。

ssh-keygen -t rsa -b 4096 

パスフレーズを標準出力するシェルスクリプト

下記のようなものを作成しておきます。

askpass.sh
#!/usr/bin/env bash

echo "${鍵作成時に入力したパスフレーズ}"

もちろん、実行権限をつけます

chmod +x askpass.sh

ssh-agent + ssh-add + SSH_ASKPASS

  • ssh-agentを起動
  • ssh-addで、作成した秘密鍵を登録
  • パスフレーズの入力は、SSH_ASKPASSに、パスフレーズを出力するスクリプトのパスを設定
  • sftpコマンドが終わったら、ssh-agentを停止
$ eval `ssh-agent`
$ DISPLAY=":0.0" SSH_ASKPASS=askpass.sh setsid ssh-add id_ed25519 </dev/null
$ sftp ${sftp_user}@${sftp_server}

sftp> 
...
sftp> quit

$ ssh-agent -k

これで、秘密鍵のパスフレーズ入力が、対話なしでできるようになりました。
あとは、sftpサーバ上で実行するコマンドの部分です。これはヒアドキュメントを使えばいいです。

sftpコマンドを使ったシェルスクリプトは、下記のようになります。

sample_sftp.sh
#!/usr/bin/env bash
set -euo pipfail

sftp_user=...
sftp_server=...

eval `ssh-agent`
DISPLAY=":0.0" SSH_ASKPASS=askpass.sh setsid ssh-add ~/.ssh/id_ed25519 </dev/null
sftp ${sftp_user}@${sftp_server} << EOF
put local_file /dst
put local_file2 /dst
get /from/remote_file
quit
EOF

参考