【30分で動かすシリーズ】「パスワードは後ほど別メールでお送ります」がめんどくさいのでなんとかしてみる

記事タイトルとURLをコピーする

世間におおっぴらにできないファイルをメールで送るとき、パスワード付きzipで固めてメールで添付して送った後、別のメールでそのzipのパスワードを送るって良くあるかと思います。
安全性とか語りだすとキリがないのですが、ひとまずめんどくさい。
もう少しラクができないかと考えてみました。

いわゆる今日の8

ファイルの受け渡しの相手が決まっているなら予めパスワードを決めておいて、メールには書かない、zipを添付して送るだけという運用も有効でしょう。
「本日の日付」や「予め合言葉のように固有の文言を決めておく」です。
別メールでパスワードをいちいち送らなくて良いのでラクになります。とはいえ、「今月は2016年4月だから」と「201604」のような簡単なパスワードだと、今日びCPUやGPUのパワーで簡単に破られかねません。
パスワードを忘れた人や途中からプロジェクトに参画した人に「パスワードはこれ」と教えるのもめんどくさい。
とはいえ、「パスワードがばれないように」と複雑なパスワードにすると、覚えきれません。どこかにメモしてしまうかもしれません。
ひとまず、追加の設備等を特に必要とせず、さして費用もかからず、パスワードを別メールすることもメモすることも不要になる方法を考えてみました。

Amazon S3でファイル共有

Amazon S3はいわゆるインターネット用のストレージサービスです。クラウド上にファイルをアップして、ダウンロードできる、クラウド上にファイルをどんどん溜め込めるサービスです。
これにファイルをアップして「ここにアップしたから」と知らせればラクになりそうです。Amazon S3安いし。
S3でラクになるにはちょっと最初に苦労が伴います。あ、苦労はちょっとです。
S3にファイルのアップ、ダウンロードするのはちょっと大変ですので、ここの部分を最初にちょっと苦労して後々ラクにします。

後々ラクになるための最初にちょっと苦労する

Amazon S3にはアップしたファイルの在り処を署名付きURLにするという機能があります。
この機能で発行したURLを知らせてダウンロードしてもらえれば良いわけです。
S3にファイルをアップするのはAWS CLI(コマンドラインツール)で比較的簡単にできます。
ただし、「署名付きURLを発行する」というのがコマンドラインツールではできません。
APIはあり、各種言語でAPIを発行するプログラムを書く必要があります。
というわけで、ざっと書いてみます。

#coding:utf-8

import argparse
import os
from boto.s3.connection import S3Connection
from boto.s3.key import Key
import boto.s3.lifecycle

parser = argparse.ArgumentParser()
parser.add_argument('-b','--bucket', help='Name of your S3 Bucket', required=True)
parser.add_argument('-o','--object', help='Name of the object + prefix in your bucket', required=True)
parser.add_argument('-d','--day', type=int, help='Expirery in days Default = 1', default=1)
parser.add_argument('-p','--profile', help='AWS account profile')
args =  vars(parser.parse_args())


try:
    s3 = S3Connection(profile_name=args['profile'])

    # Create bucket
    s3.create_bucket(args['bucket'])

    # Upload file to created bucket
    bucket = s3.get_bucket(args['bucket'])
    k = Key(bucket)
    k.key = os.path.basename(args['object'])
    k.set_contents_from_filename(args['object'])

    # Generate signed URL
    url = s3.generate_url(
        args['day'] * 60 * 60 * 24,
        'GET',
        args['bucket'],
        k.key,
        response_headers={
            'response-content-type': 'application/octet-stream'
        }
    )
    print url

    # Set lifecycle expiration to created bucket
    lifecycle = boto.s3.lifecycle.Lifecycle()
    lifecycle.add_rule(args['bucket'], '', 'Enabled', args['day'])
    bucket.configure_lifecycle(lifecycle)

except:
    print 'Something odd happened'
    import traceback
    traceback.print_exc()

コマンドラインオプションで、どこのバケット(-b)に、どのファイル(-o)を何日間有効(-d)にするか、使うAWSアカウントは何か(-p)を指定します。

実行してみます。

$ python s3up.py -b meet-the-serverworks -o ./Meet-the-Serverworks.jpeg -d 1 -p maeda-dev
https://meet-the-serverworks.s3.amazonaws.com/Meet-the-Serverworks.jpeg?Signature=OIp7TqGhYBz9vqrCRdvm8cijERU%3D&Expires=1464794075&AWSAccessKeyId=AKIXXXXXXXXXXXXXXXXX&response-content-type=application/octet-stream

このように表示されたURLをダウンロードして欲しい人に伝えればよいわけです。
ちなみにバケットやオブジェクトに何かアクセス権限を付加する必要はありません。
URLの「?」より前の部分だけを指定してもダウンロードできません。
有効期限が過ぎるとエラーが表示されダウンロードできません。
「Expires=1464794075」の数字の部分が有効期限を示します。いわゆるUNIX時間で期限を示していますが、ここを書換えて有効期限をごまかしても有効期限が過ぎればダウンロードできません。
ライフサイクルの「1日経ったら…」の1日はUTC 0:00で丸められます。日本時間だとUTC +9、午前9時です。

終わりに

S3にアップして相手にURLを教えれば良いので、パスワードを設定して、メールに添付して、別のメールでパスワードを教えて…という手間がなくなりラクになりました。
ややこしいURLですので安全性もある程度担保されそうです。「知らない者は探さない」です。