署名付きURLを生成して検証する
目標
署名付きURLを作り、使ってみて、期限切れにしてみながら、バイトをアプリサーバーに通さず、アクセス権限だけを委任する方式を手に馴染ませます。
なぜ重要なのか
ユーザーのファイルのダウンロードをアプリサーバーが中継する実装は、小規模ではうまく動きます。問題は、500MBの動画100個が同時にリクエストされたときです。アプリサーバーが50GBを中継しながら、ワーカーがふさがり、帯域幅がアプリサーバーのスペックに閉じ込められ、バッファリングを間違えるとOOMが起きます。署名付きURLは、この構造をひっくり返します。アプリは権限を判断して、数バイトの署名付きURLだけを作り、実際の転送は、クライアントとストレージの間で直接行われます。ステップ7でURLを分解してみると、なぜこれが安全なのかが見えてきます。署名はシークレットキーで作られていますが、シークレットキー自体は、URLのどこにもありません。そのため、URLが漏れても、そのオブジェクト、その操作、その有効期限までしか露出しません。
ステップ
s3://lab-media/private/secret.txtに、/opt/fixtures/s3/readme.txtをアップロードしてください。- 署名なしで
curl -o /dev/null -w '%{http_code}' http://127.0.0.1:9000/lab-media/private/secret.txtを実行し、/root/ps/anon.txtにstatus=403を書いてください。 /root/ps/presign.pyで、有効期限300秒の署名付きGET URLを作り、/root/ps/get_url.txtに1行で保存してください。URLにX-Amz-SignatureとX-Amz-Expiresが含まれている必要があります。- そのURLでダウンロードして、
/root/ps/downloaded.txtを作成してください。元と内容が同じである必要があります。 - 有効期限1秒のURLを作り、3秒待ってから使ってください。
/root/ps/expired.txtにstatus=403を書きます。 - 有効期限300秒の署名付きPUT URLで、
/opt/fixtures/s3/sales.csvをs3://lab-media/upload/direct.csvにアップロードしてください。aws --profile local s3api head-objectで、存在を確認します。 /root/ps/sig.mdにMarkdownの表を書いてください。行の見出しは、X-Amz-Algorithm、X-Amz-Credential、X-Amz-Date、X-Amz-Expires、X-Amz-SignedHeaders、X-Amz-Signatureの6つで、各行にそのパラメーターの意味を書きます。ファイルにシークレットキーの値が入っていてはいけません。
参考
- 資格情報は
/opt/fixtures/s3/creds.envのS3_*の値で、awsプロファイルlocalは、s3-basicsのステップ1と同じ方法で作ります。 aws s3 presignもURLを作りますが、CLI v1は既定が古い署名(SigV2、Signature=)なので、X-Amz-*の項目が出ません。このラボは、署名バージョンを固定できるboto3で作ります。- URLをシェルで使うときは、必ず引用符で囲んでください。
&がバックグラウンド実行と解釈されます。 - 有効期限は、短いほど安全です。ダウンロードは数分、アップロードは数十分が普通です。
- よくあるミス1: 署名付きPUTに、サイズとContent-Typeの制限をかけないこと。クライアントが何でもアップロードできるようになります。
- よくあるミス2: 署名付きURLをログにそのまま残すこと。有効期限が切れるまで、誰でも使えます。
非公開オブジェクトを用意する
s3://lab-media/private/secret.txtに、/opt/fixtures/s3/readme.txtをアップロードしてください。
前のラボのバケットをそのまま使うか、新しく作ります。既定のバケットは、匿名アクセスが塞がれています。
匿名アクセスが拒否されることを確認する
署名なしでcurl -o /dev/null -w '%{http_code}' http://127.0.0.1:9000/lab-media/private/secret.txtを実行し、/root/ps/anon.txtにstatus=403を書いてください。
署名なしで、そのままURLにアクセスしてみます。ステータスコードが何かを記録してください。
署名付きGET URLを作る
/root/ps/presign.pyで、有効期限300秒の署名付きGET URLを作り、/root/ps/get_url.txtに1行で保存してください。URLにX-Amz-SignatureとX-Amz-Expiresが含まれている必要があります。
有効期限を一緒に指定します。URLに、署名に関するクエリパラメーターが付いていれば正常です。
署名付きURLで実際にダウンロードしてみる
そのURLでダウンロードして、/root/ps/downloaded.txtを作成してください。元と内容が同じである必要があります。
引用符で囲まないと、シェルがアンパサンドをバックグラウンド実行と解釈します。
期限切れのURLが拒否されることを確認する
有効期限1秒のURLを作り、3秒待ってから使ってください。/root/ps/expired.txtにstatus=403を書きます。
ごく短い有効期限で作り、少し待ってから使ってみます。拒否のステータスコードを記録してください。
署名付きPUTで直接アップロードする
有効期限300秒の署名付きPUT URLで、/opt/fixtures/s3/sales.csvをs3://lab-media/upload/direct.csvにアップロードしてください。aws --profile local s3api head-objectで、存在を確認します。
クライアントがストレージに直接アップロードします。アプリサーバーを経由しないことが核心です。
署名の要素を分析する
/root/ps/sig.mdにMarkdownの表を書いてください。行の見出しは、X-Amz-Algorithm、X-Amz-Credential、X-Amz-Date、X-Amz-Expires、X-Amz-SignedHeaders、X-Amz-Signatureの6つで、各行にそのパラメーターの意味を書きます。ファイルにシークレットキーの値が入っていてはいけません。
URLのクエリパラメーターを分解して、それぞれがどんな制約かを書きます。シークレットキーがURLにないことを確認してください。