aws s3 presignで署名付きURL(presigned URL)を生成すると、期限付きでダウンロードできるURLをその場で作れる。
URLを受け取った相手にAWSアカウントは不要で、期限が過ぎればURLは自動的に使えなくなる。

基本的な使い方

aws s3 presignにS3のURIを渡すと署名付きURLを出力する。

$ aws s3 presign s3://<bucket-name>/<object-key>

実行例

$ aws s3 presign s3://example-bucket/path/to/report.pdf
https://example-bucket.s3.ap-northeast-1.amazonaws.com/path/to/report.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20260731%2Fap-northeast-1%2Fs3%2Faws4_request&X-Amz-Date=20260731T222635Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=089d9f242e031bbe70caf246719c15e8577d7fb0362d04654befb78d974b9d81

出力されたURLはブラウザで開くか、curlでダウンロードできる。

$ curl -o report.pdf "https://example-bucket.s3.ap-northeast-1.amazonaws.com/path/to/report.pdf?X-Amz-Algorithm=..."

URLには&が含まれるため、シェルで扱う際はダブルクォートで囲む。
クォートを付けないとシェルが&をバックグラウンド実行として解釈してしまう。

有効期限を指定する

--expires-inで有効期限を秒数で指定する。
指定しない場合のデフォルトは3600秒(1時間)である。

5分だけ有効なURLを生成する例

$ aws s3 presign s3://example-bucket/path/to/report.pdf --expires-in 300

指定できる最大値は604800秒(7日)である。

$ aws s3 presign s3://example-bucket/path/to/report.pdf --expires-in 604800

URLに含まれるパラメータ

生成されたURLのクエリ文字列には署名情報が含まれる。

パラメータ内容
X-Amz-Algorithm署名アルゴリズム。AWS4-HMAC-SHA256固定
X-Amz-Credential署名に使ったアクセスキーID、日付、リージョン、サービス名
X-Amz-Date署名した日時(UTC)
X-Amz-Expires有効期限の秒数
X-Amz-SignedHeaders署名対象のヘッダー
X-Amz-Signature署名
X-Amz-Security-Token一時的な認証情報を使った場合のセッショントークン

URLが失効する時刻はX-Amz-DateX-Amz-Expires秒を足した時刻である。
起点は配布した時刻ではなく生成した時刻である。あらかじめ生成しておくと、相手が受け取った時点では残り時間が減っている。

期限切れのURLにアクセスした場合

期限を過ぎたURLにアクセスするとAccessDeniedが返る。

$ curl "https://example-bucket.s3.ap-northeast-1.amazonaws.com/path/to/report.pdf?X-Amz-Algorithm=..."
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Request has expired</Message><X-Amz-Expires>1</X-Amz-Expires><Expires>2026-07-31T22:27:50Z</Expires><ServerTime>2026-07-31T22:27:53Z</ServerTime><RequestId>CWMH4K7B9JN5DNF2</RequestId><HostId>...</HostId></Error>

Expiresが失効時刻、ServerTimeがアクセスした時刻である。

なお、期限の判定はHTTPリクエストの時点で行われる。
大きなファイルのダウンロード中に期限を過ぎても、そのダウンロードは継続する。

最大値を超える期限を指定した場合

--expires-inに604800より大きい値を指定してもコマンドはエラーにならず、URLを生成する。
aws s3 presignはAWSへのリクエストを送らず、手元で署名を計算するだけのためである。

$ aws s3 presign s3://example-bucket/path/to/report.pdf --expires-in 604801
https://example-bucket.s3.ap-northeast-1.amazonaws.com/path/to/report.pdf?...&X-Amz-Expires=604801&...

生成されたURLは使えず、アクセスした時点でエラーになる。

<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AuthorizationQueryParametersError</Code><Message>X-Amz-Expires must be less than a week (in seconds); that is, the given X-Amz-Expires must be less than 604800 seconds</Message><RequestId>X8SGEPH74TFFJZYY</RequestId><HostId>...</HostId></Error>

エラーメッセージは604800未満と読めるが、604800ちょうどは受け付けられる。

コマンドが成功してもURLが有効とは限らないため、配布する前に自分でアクセスして動作を確認しておくとよい。

一時的な認証情報では7日間有効なURLを作れない

署名付きURLは、生成に使った認証情報が失効した時点で無効になる。
--expires-inに7日を指定していても、認証情報の期限が先に来ればそちらが優先される。

認証情報URLの有効期間
IAMユーザーのアクセスキー最大7日
STSの一時的な認証情報(AssumeRoleなど)セッションの期限まで(デフォルト1時間)
EC2インスタンスプロファイルロールの認証情報の期限まで(おおむね6時間)
ECSタスクロールロールの認証情報の期限まで(1〜6時間)

IAM Identity Center(旧AWS SSO)やaws sts assume-roleで得た認証情報も一時的な認証情報にあたる。
これらの認証情報で生成したURLは、X-Amz-Security-Tokenパラメータを含む。
指定した期限より早くURLが使えなくなる場合は、まず認証情報の種類を確認するとよい。

長期間有効なURLが必要な場合はIAMユーザーのアクセスキーで生成する。
ただし期限を長くするほど、URLが流出した際に悪用される期間も長くなる。共有に必要な期間だけを指定する。

リージョンの指定

署名にはリージョンが含まれるため、バケットのあるリージョンを指定して生成する。
プロファイルのデフォルトリージョンとバケットのリージョンが異なる場合は--regionで明示する。

$ aws s3 presign s3://us-east-1-bucket/path/to/report.pdf --region us-east-1

リージョンが一致しない場合、生成されるURLも別リージョンのエンドポイントを指すため、アクセス時にPermanentRedirectなどのエラーになる。

権限はURLを生成した人のものになる

署名付きURLは、生成したIAMユーザーやIAMロールの権限でリクエストする。
s3:GetObjectの権限を持たない状態で生成したURLは、アクセスすると403を返す。
コマンドが成功してもダウンロードできるとは限らない。

また、URLを持っている人は誰でもファイルをダウンロードできる。
期限内であれば何度でも使えるうえ、転送されたURLも同じように機能する。
URLそのものが鍵として働くため、パスワードと同等の扱いで共有する。

より厳しく制限したい場合は、バケットポリシーのs3:signatureAge条件で署名からの経過時間を制限したり、aws:SourceIpでアクセス元を制限したりできる。

ダウンロード専用である

aws s3 presignで生成できるのはGET用のURLのみである。
アップロード用のPUTのURLはAWS CLIでは生成できず、boto3のgenerate_presigned_urlのようなSDKの機能を利用する。

参考