Amazon S3のバケット名にドットを使ってしまいhttps通信が出来ない環境を作ってしまった,S3のダウンロードファイル名を指定できるライブラリがなくて困っている

Amazon S3のバケット名にドットを使ってしまいました

aws :: Stackage Serverパッケージでpre signed urlを作る方法はさっぱりわかりませんでした.そんな機能ないのかも.

pre signed urlを作る機能だけにs3-signer :: Stackage Serverを使うことにしました.

作ってみたら上手く動かない,https証明書エラーが発生します.web上のドキュメントではみんな普通にhttpsアクセスできてるのになんでだろう…と思って調べてたらとんでもない失態を犯していることに気がついてしまいました.

SSL と共に仮想ホスティング形式のバケットを使用した場合、SSL ワイルドカード証明書は、ピリオドを含まないバケットのみと一致します。この問題を回避するには、HTTP を使用するか、または独自の証明書検証ロジックを記述します。 バケット名にピリオド (「.」) は使用しないことをお勧めします。

バケットの制約と制限 - Amazon Simple Storage Service

なるほどそれで我々のS3だけhttpsアクセス出来ないのか…名前をつける時に警告を出して欲しかった.

code.rock: S3のバケット名はよく考えて命名しましょう!にある通りhttps://s3-[region].amazonaws.com/[bucket]/の形式ならアクセスできるらしいですが,s3-signerもaws cliもhttps://[bucket].s3.amazonaws.com/でURLを生成するので設定してたバケット名ではアクセスできない.

とりあえず開発向けのバケット名に含まれるドットをハイフンに変えてやれば上手く動きました.

バケット名は変更できないので本番向けのバケット名を変更するには新しくバケット作って全てsyncする必要があるんですよねーダウンタイムが長くなるし他に設定あるかもしれないから変更漏れ起きそうで嫌ですね…

s3-signerにpull request出して書き換えるのもあり?s3-signer/URL.hs at master · dmjio/s3-signerbaseUrlを対応形式に書き換えてやれば良さそうかな,と思ったんですが.ダメですね.

なんでダメかというと,S3で使えるURL一覧 - Qiitaなどを見るとわかるんですが,バケット名がホストではなくパスに含まれてるとリージョン情報がURLに必要なのでそのまま書き換えは出来ないんですよ.

パス形式の URL では、バケット名は(リージョン固有のエンドポイントを使用しない限り)ドメインの一部にはなりません。(例: 米国東部 (バージニア北部) リージョンエンドポイント、http://s3.amazonaws.com/bucket リージョン固有のエンドポイント、http://s3-aws-region.amazonaws.com/bucket

パス形式の URL では、使用するエンドポイントはバケットが存在するリージョンと一致している必要があります。たとえば、バケットが 南米 (サンパウロ) リージョンにある場合は、http://s3-sa-east-1.amazonaws.com/bucket エンドポイントを使用する必要があります。バケットが米国東部 (バージニア北部) リージョンにある場合は、http://s3.amazonaws.com/bucket エンドポイントを使用する必要があります。

バケットはパス形式の URL と仮想ホスト形式の URL を使用してアクセスできるため、DNS 準拠のバケット名を使用してバケットを作成することをお勧めします。詳細については、「バケットの制約と制限」を参照してください。

Amazon S3 バケットの使用 - Amazon Simple Storage Service

公式サイトを見るとバケット名がホストに含まれてるとDNS振り分けがその時点で出来るからリージョンが不要になるけどパス指定だとリージョン情報を別途で求めることがわかりますよね.

やはり本番向けのバケットもドットをハイフンなどに変更したほうが良さそうですね…

S3のダウンロードファイル名が指定できない

response-content-dispositionオプションが動かない

を参考にしてresponse-content-dispositionをURLに指定してダウンロードファイル名を変更しようとしましたが,何故か全然動きません.ファイル名が指定されないとかそういう次元ではなく,response-content-dispositionを指定するとファイル自体にアクセスできなくなります.

調査した結果,URLパラメータが変わると署名が変わることがわかりました.署名されたURLにresponse-content-dispositionをつけ足すという方式を取っていたから,ダメだったんですね.

レスポンスヘッダー値を上書きするクエリ文字列パラメーターを指定するリクエストの場合は(GET Object を参照)、クエリ文字列パラメーターとそれらの値を追加します。これらのパラメーター値は署名時にエンコードする必要はありませんが、リクエストの実行時にはエンコードする必要があります。GET リクエストのクエリ文字列パラメーターには、response-content-type、response-content-language、response-expires、response-cache-control、response-content-disposition、response-content-encoding があります。

REST リクエストの署名と認証 - Amazon Simple Storage Service

s3-signerをforkして,response-content-disposition用のオプションを付け足さないとダメでしょうね…

自分で作ったほうが早いまであるかと思って読んでたけど結構面倒くさい.やはり改造した方が良さそうですね.

読んでて思ったけどもしかしたらawsパッケージのsignQueryでこれ可能なんじゃないか,今度もう一度試してみますか…と思ったけど,複雑なawsパッケージを読み解くよりはs3-signerをforkした方が良さそうですね.

aのdownload属性を指定して解決できない

色々と面倒くさいので,a要素のdownload属性にファイル名を指定して解決しようとしました.しかし,これは同一オリジンじゃないと動かないので,S3にリダイレクトしてホスティングしようとしてる今回の用途では当然動きませんでした.