ローカルのファイルを暗号化しながらリモートに保存する
Posted on 2019/01/13 in tech
そもそも論
シェルを書くなら標準入出力ベースで考えるのがスマートだと思うのです。
極論いうと
$ cat hoge.txt
みたいなのは
$ cat < hoge.txt
と書こう、みたいな。
流石に cat
でこんなことはしないけれど、
- 読み込みは標準入力
- 出力は標準出力
をベースとして考えるのが、シェラー1の道第一歩だと思うのです。
ローカルのファイルをリモートサーバに保存したい。
たまたまそれなりなサイズの嫁2動画ファイルが手元にあって、いいアーカイブ場所を探してたときに、いい感じに容量が有り余ってるレンタルサーバがあった。
......これはもう ここに置くしかない でしょう。
ただ、レンタルサーバというのは基本管理者(サービス提供者)が自由にアクセス・閲覧できるサーバである。 そこにプライベートなものを置くのは多少なり抵抗があるので、 暗号化したい 。
対象ファイル
ファイルというかディレクトリ。ビデオカメラで撮影したデータを SD カード経由で取り込み、 そのままのディレクトリ階層で保存したい。
ここでは単純に hoge
,foo
,bar
の 3 つのディレクトリを保存することを考える。
$ ls
hoge foo bar
保存先は ssh 接続可能なリモートサーバ。
保存先のディレクトリは backup
としましょう。~/.ssh/config
設定済なら以下のような感じ。
$ ssh remote
# ここからリモートサーバ
$ ls
backup # ここに保存する
scp
でいうとこの remote:backup
で表されるパスに保存する感じ。
保存方法
ざっくりこれらを使ってリモートに保存する。
- ssh
- リモートサーバに置く
- openssl
- 暗号化する
- tar
- アーカイブする
なお、動画ファイルは圧縮済3なので、圧縮処理は行わない。
手間の多い保存方法
1 個 1 個頑張る。
$ tar cf hoge.tar hoge
$ openssl enc -e -aes-256-cbc -in hoge.tar -out hoge.tar.enc
$ scp hoge.tar.enc remote:backup
$ tar cf foo.tar foo
$ openssl enc -e -aes-256-cbc -in foo.tar -out foo.tar.enc
$ scp foo.tar.enc remote:backup
$ tar cf bar.tar bar
$ openssl enc -e -aes-256-cbc -in bar.tar -out bar.tar.enc
$ scp bar.tar.enc remote:backup
疲れた。
for
を使う
先程の保存方法は
tar
でアーカイブ化openssl
で暗号化scp
でリモートサーバへ保存
の繰り返しなので、for
を使って記述できる。
$ for d in *; do \
tar -cf $d.tar $d; \
openssl enc -e -aes-256-cbc -in $d.tar -out $d.tar.enc -pass pass:p@ssw0rd; \
scp $d.tar.enc remote:backup \
done
上記のように、openssl
に -pass
オプションをつけることで、プロンプトからパスワードをいちいち入力する手間を省くことができる。
ある程度これで楽にはなったけど、ゴミファイルが残る。
$ ls
hoge
hoge.tar
hoge.tar.enc
foo
foo.tar
foo.tar.enc
bar
bar.tar
bar.tar.enc
rm *.tar*
すればいい話だが、このディレクトリ 1 つあたり 10 GB とかある。
単純にローカルに 3 倍のバッファ容量が必要になるってエコロジーではない。スマートにいきたい。
シェルを使うなら標準入出力を駆使せよ
で、そもそも論に戻ります。
そもそも openssl
になんで -in
と -out
ってオプションがあると思います?(煽り)
$ openssl enc -e -aes-256-cbc -in hogefile -out hogefile.enc
オプションがないとファイルを読み込めない? 書き出せない?
違う。これらは飽くまで オプション です。
デフォルトは標準入出力
通常、伝統的なコマンドはデフォルトとして 標準入力から読み込み4、標準出力に出力する ように実装されているものがほとんど(grep, awk, sed...)。
openssl enc
の場合は 標準入力を暗号化して標準出力に出力する。
(「標準出力に出力」って別のよい言い方ないだろうか)
だから、-in
や -out
がなくても、こう書ける。
$ openssl enc -e -aes-256-cbc < hogefile > hogefile.enc
何がいいのか
基本的にコマンドは 標準入出力を扱う ことを知っていれば、上のコマンドは 初見で何しているのかが直感的にわかる んですよ。
そして、シェルを扱う上で必須の パイプ を駆使すれば、コマンドの組み合わせで柔軟に処理を記述できる。
リモートに一発で置く
つまり、 ディレクトリは暗号化しながらリモートに一発でおける。
$ for d in *; do \
tar -c $d | \ # アーカイブして
pv -s $(du -sb $d | awk '{print $1}') | \ # 進捗表示しながら(なくてもよい)
openssl enc -e -aes-256-cbc -pass pass:p@ssw0rd | \ # 暗号化して
ssh remote "cat > backup/$d.tar.enc" ; \ # リモートに保存
done
tar -c $d
はあえて tar -cf - $d
とは書かなかった5。実は tar
は tar -c file
だけでアーカイブデータを標準出力に吐いてくれる。6 7
pv
コマンドは cat
にデータの処理状況を表示する機能がついたものだと思えばいい。Pipe Viewer の略で pv
らしい。
-s
オプションで進捗データ全体のサイズをバイトで指定できるので、du -sb $d | awk '{print $1}'
で8ディレクトリのバイトサイズを取得している。
まとめ
標準入出力つかおう。
参考
-
いま思いついた造語。シェルを巧みに書くひと。 ↩
-
3次元でリアルです。ダンスの舞台とか健全な動画です。 ↩
-
MPEG や MOV などは、動画に適した圧縮方法で圧縮済なので、これを gzip 化などするとかえって容量が増えたりする ↩
-
引数がある場合は、標準入力ではなく引数に指定されたファイルを読み込む場合が多い。 ↩
-
多くのコマンドで
-
は標準入力もしくは標準出力を表す。 ↩ -
BSD 系だとうまくいかないこともあったので、
-f
オプションを使ったやり方も大事。 ↩ -
逆に、
tar -x
は標準入力からアーカイブデータを読み込んで展開してくれる(tar -xf -
としなくてもよい)。 ↩ -
BSD 系は
du
に-b
(バイト表示)オプションが使えなかった。Mac なら coreutils をインストール(brew install coreutils
)して、gdu -sb
とできる。 ↩