CloudShellからassumed-roleの認証情報で7日間有効なS3署名付きURLは作れません

CloudShellからassumed-roleの認証情報で7日間有効なS3署名付きURLは作れません

2026.05.31

はじめに

かつまたです。

CloudShell から S3署名付き URLを--expires-in に最大値の 7 日を指定したのに、実際の有効期限はそれより短かった場面に遭遇しました。
この事象に要因や回避策を調査してみたのでご紹介します。

事象

CloudShell 上で、対象オブジェクトに対して 7 日有効を期待して署名 URL を発行しました。

aws s3 presign s3://my-bucket/report.csv --expires-in 604800

発行された URL は問題なく開けるのですが、配布からしばらく経過(完全に7日未満)すると、アクセス時に次のような ExpiredToken エラーが返るようになりました。

<Error>
  <Code>ExpiredToken</Code>
  <Message>The provided token has expired.</Message>
</Error>

--expires-in には 604800 秒を指定しているにもかかわらず、実際には数時間程度で失効していました。S3 バケットのライフサイクルやバケットポリシーには、有効期限を縛るような設定は入れていません。

原因

Presigned URL の有効期限は、--expires-in で指定した値と、署名に使った認証情報そのものの有効期限のうち、早く到来する方で打ち切られルようでした。

CloudShell は IAM ロールを引き受けた一時認証情報で動作しています。

aws sts get-caller-identity --query Arn --output text
arn:aws:sts::123456789012:assumed-role/xxxxxxxx/xxxxxxxx

この一時認証情報で署名すると、URL のクエリ文字列に X-Amz-Security-Token が含まれます。S3 はアクセス時にこのトークンの有効性を確認するため、セッションが失効した時点で URL も無効になります。AssumeRole のセッションはデフォルトで 1 時間(最大でもロールの MaxSessionDuration まで)のため、7 日を指定しても 1 時間で切れていた、というわけです。

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/using-presigned-url.html

対応内容

期待する有効期限を確保するには、署名に使う認証情報の有効期限を、欲しい URL 有効期限以上にする必要があります。2つの方法を試してみました。

1. AssumeRole のセッション有効期限を延ばす

一時認証情報のまま、ロールのセッション時間を延ばす方法です。対象ロールの MaxSessionDuration を必要な長さまで引き上げます。上限は 12 時間(43200 秒)です。

aws iam update-role --role-name <ロール> --max-session-duration 43200

そのうえで aws sts assume-role--duration-seconds に同じ長さを指定して認証情報を取得し、その認証情報で署名します。

2. IAM ユーザーの長期アクセスキーで署名する(7 日まで)

一時認証情報ではなく IAM ユーザーのアクセスキーで署名します。SigV4 では、IAM ユーザーの認証情報で署名した URL は最大 7 日まで有効です。

なお、アクセスキーはセキュリティ推奨されないため、最小権限及び、利用時の一時作成などを推奨します。

以下のように Cloudshell 上でアクセスキーを指定し、URLを作成していきます。

AWS_ACCESS_KEY_ID=AKIAxxxxxxxxxxxxxxxx \
AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
AWS_SESSION_TOKEN= \
aws s3 presign s3://my-bucket/report.csv --expires-in 604800

動作確認

発行した URL の有効性は GET で確認します。aws s3 presign はデフォルトで GET メソッドを含めて署名するため、curl -I(HEAD)では署名不一致で 403 になります。検証は GET で行ってください。

curl -s -o /dev/null -w "HTTP %{http_code}\n" "$URL"

HTTP 200 が返れば有効です。

おわりに

ご覧いただきありがとうございました。

CloudShell や踏み台の assumed-role でそのまま aws s3 presign を実行すると、--expires-in をいくら大きくしてもセッション失効で URL が切れてしまいます。これは S3 側の設定ではなく、署名に使った認証情報の有効期限に縛られる SigV4 の仕様です。

12 時間程度で足りるなら AssumeRole のセッション延長で、7 日有効が必要なら IAM ユーザーの長期キーで署名、と使い分けるのがおすすめです。同じ事象で URL が早く切れて困っている方の参考になれば幸いです。

クラスメソッドオペレーションズ株式会社について

クラスメソッドグループのオペレーション企業です。
運用・保守開発・サポート・情シス・バックオフィスの専門チームが、IT・AIをフル活用した「しくみ」を通じて、お客様の業務代行から課題解決や高付加価値サービスまでを提供するエキスパート集団です。
当社は様々な職種でメンバーを募集しています。
「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、クラスメソッドオペレーションズ株式会社 コーポレートサイト をぜひご覧ください。
※2026年1月 アノテーション㈱から社名変更しました

この記事をシェアする

関連記事