この記事は ドワンゴ Advent Calendar 2016 20日目です。
ある日、私は広大な領域が狭くなっていることに気づいた
私は12TBのストレージを3年程前に導入しました。導入当初は「もうこれでストレージを購入する必要は無いな」と思うぐらいの無限の領域に見えていたのですが、そのストレージの容量が最近底をつきつつあります。「人間とはあればあれだけ使ってしまうものなのだな」と感慨深くなりながらも、この状況を放っておくわけにはいきません。新しいストレージを購入しようと計画するわけですが、最近は大容量HDDがすっかり安くなったとはいえ「これも欲しい、あれも欲しい」と要求を追加していくとすぐに6桁価格になってしまい、かなり躊躇してしまうわけです。
ふと冷静になるために立ち止まってみると、最近ではクラウドストレージが大容量かつ低価格になりつつあるということが見えてきました。よく売られている安価なWindowsタブレットについているOfficeにはOneDriveの1TB領域もついてますし、Amazon DriveにいたってはUnlimitedプランでは容量無制限で13800円とストレージを構成するHDDの価格と冗長化、年間の電気代、その他心配事を考えるとかなりお手軽に感じます。クラウドストレージをつかううえで障壁となってくるアップロード制限は、このようなクラウドストレージの利用に合わせてプロバイダによっては(http://www.ocn.ne.jp/info/rules/qualityimprovement/)廃止の方向に向いつつあるようにも見えます。
クラウドストレージを利用するうえでの不安
これはクラウドストレージにほとんどのファイルをアップロードするのが良いのでは無いだろうかと思いましたが、ふと漠然とした不安が頭をよぎりました。よくあるクラウドストレージは便利なことにファイルを簡単に共有することができます。これは非常に便利な機能ではありますが、同時に操作ミスやその他の問題で意図せずファイルがインターネット上に公開されてしまう可能性を否定することができません。インターネットを経由して預けている以上、このような心配はどうしても考えてしまいます。
そのような懸念を解消するためにクラウドストレージに対応した一部のサードパーティクライアントでは内容を暗号化するようなオプションがあります。しかし多くはWindowsクライアントであって、MacやLinuxでのクライアントは少ないようでした。
クラウドストレージにちょっとだけ内容を読みにくくして保存したい
そこで「MacとLinuxで使える内容をちょっとだけ読みにくくして保存するクラウドストレージクライアント」を自分で作ってみることにしました。これによってファイルが意図せず公開されてしまっても中身はパッと見ることはできません。
今回はFUSE(Filesystem in Userspace)という仕組みを利用しました。これはファイルアクセスの際にユーザーが独自に用意したプログラムを呼び出し処理を行うことができる仕組みです。FUSEはカーネルとの橋渡しを行い、独自に用意したプログラムはユーザー空間で動作させることができ、仮想ファイルシステムなどを実装際によく利用される仕組みです。FUSEでマウントすれば、OSの標準的なファイル入出力でやりとりすることができるようになるうえ、Linuxを始めとしたUNIX系OSとMac OSなどで動作します。
FUSEから呼び出す任意のプログラムは、CやPythonなどで書くことができますが今回は自身の習熟度の関係からPythonとfusepy(https://github.com/terencehonles/fusepy)を利用しました。このプログラムには各システムコール毎に行う処理の内容を記述します。今回書いた内容はファイルの内容をBASE64で符号化した後に指定したパスワードとXORをかけてS3に保存するようにしました。XORは暗号化と復号化で同じ処理で済む点であったり仕組みが単純なため採用しました。コードは こちらです。
利用方法
https://github.com/hirokikana/s3-encfs-fuse からコードをcloneした後、まずは下記を用意します。
- AmazonWebSerivceのアクセスキーとシークレットアクセスキー
- Amazon S3の任意のバケット
それぞれを用意する方法は別のまとまった情報に任せるとして、上記がある前提で話を進めます。
まずは下記のような設定ファイル(s3.conf)を用意します。
[aws]
key=XXXXXXXXXXXXXXXXXXX
secret_key=XXXXXXXXXXXXXXXXXXXXXX
bucket_name=BUCKET_NAME
[core]
encrypt_password=ENCRYPT_PASSWORD
awsセクションのkey/secret_key/bucket_nameはそれぞれ事前に準備したアクセスキーとシークレットキー、そして任意のバケットの名前です。ファイルはここに保存されるようになります。coreセクションのencrypt_passwordはファイル読み書きの際にXORする文字列を指定します。この文字列を知らない場合はファイルの内容を読むことは出来ません。
設定ファイルを用意することができたら、s3-encfs-fuse.pyを実行します。
$ python s3-encfs-fuse.py /path/to/mountpoint
第2引数にはマウントする場所を指定します。ここで指定したパスにS3がマウントされます。この状態で下記のようにファイルの読み書きができるか確認します。
$ echo abcde > /path/to/mountpoint/test
$ cat /path/to/mountpoint/test
abcde
この状態でAmazon S3から直接ダウンロードし中身を確認してみると異なる内容になっていることがわかるはずです。
今後の課題
ここまででS3にちょっと読みにくい形で保存することができました。しかしながら実用にはかなり課題が残っています。
- まともに使えるパフォーマンスではない
- 40KBぐらいの画像を開くのに20秒ぐらいかかった
- システムコールの回数分HTTPSリクエストをするうえ、Keep-Aliveに対応していないため効率がとても悪いように見える
- しかしながら、そもそもexampleにあったMemoryに保存するプログラムでもそれほどパフォーマンスが出てなかったのでそもそもパフォーマンスが出ない可能性もある
- 大容量ファイルの読み書きはできない
- BASE64する際に内容をメモリに展開するようにしているので大きなファイルを読み書きするとたぶん落ちる
- BASE64エンコードだと空間効率が悪い
- BASE64エンコードする分、元ファイルより余分に容量を消費してしまう
- S3以外のクラウドストレージしていない
- S3は従量課金制なので大量に保存するとそれなりに費用がかかりそう
- 最終的には定額・容量無制限のAmazon Driveに書き込みたいけど、そもそもAmazon DriveがAPIを提供しているのか(US版はAPIがあるようですが)確認するところから始める必要がある
私の予定ではAdventCalendar当日までにはもう少し実用的になっている予定だったのですが、私の力不足によりこのような食べ散らかした海鮮丼みたいな状況になっているものを紹介するような形となってしまいました。とはいえ、自分自身が誰よりも早く使えるようなってほしいと思っているのでそれほど遠く無い時期には課題をクリアした形のものを紹介できればと思います。
Tweet