【AWS】presigned URLsを使おうとしたらSignatureDoesNotMatchが出たときの対処
AWSのファイルストレージであるS3(Simple Storage Service)には一時的にユーザーにアップロードやファイル閲覧が出来るようになる、presigned URLs(署名付きURL)を発行する機能が存在します。
このpresigned URLsの発行にあたっては、色々な先駆者の方々が記事を書いてくださっていますが、この発行されたpresigned URLsを使う側の記事は殆ど見当たらずに詰まってしましいました。
SignatureDoesNotMatchというエラー
「SignatureDoesNotMatch」というエラーが出ました。返却されたURLそのまま使ったのに署名が適切じゃないとかどういうことやねん。 ということで四苦八苦していました。
いくつか失敗するパターンが有るようなので、列挙しておこうと思います。 にしても親切じゃないエラーです…
エラーが起きる原因と対処方法
署名のバージョンが不適切
署名のバージョンがv4 でないと上手く動かないことがあるようです。 こちらはURLを発行する際に指定をするものとなりますので、発行するプログラムを担当している人に確認しましょう。
こんな感じで指定を行います。
# https://boto3.amazonaws.com/v1/documentation/api/1.9.42/guide/s3.html#generating-presigned-urls
import boto3
from botocore.client import Config
# Get the service client with sigv4 configured
s3 = boto3.client('s3', config=Config(signature_version='s3v4'))
# Generate the URL to get 'key-name' from 'bucket-name'
url = s3.generate_presigned_url(
ClientMethod='get_object',
Params={
'Bucket': 'bucket-name',
'Key': 'key-name'
}
)
https://github.com/aws/aws-sdk-js/issues/902
なお、署名のバージョンを2020年6月時点では、v4はデフォルトではないようです。
なお、こちらの記事によるとダウンロード(GET)用のURLではエラーが出ず、アップロード(PUT)用URLではエラーが出るとのことです。なんだそれ…
有効期限の設定がよりも先に期限切れになってしまっている
AWSが公式に記事を出してくれていますが、有効期限を待たずにURLが失効されてしまうことがあります。
- AWS Identity and Access Management (IAM) インスタンスプロファイル: 最大 6 時間有効
- AWS Security Token Service (STS): 最大 36 時間有効 (AWS アカウントユーザーや IAM ユーザーの認証情報など、永続的認証情報を使用して署名した場合)
- IAM ユーザー: 最大 7 日間有効 (AWS 署名バージョン 4 を使用した場合)
詳細は以下の記事をご参照下さい。
https://aws.amazon.com/jp/premiumsupport/knowledge-center/presigned-url-s3-bucket-expiration/
ヘッダにContent-Typeの指定がない
私が今回苦しんだのはこれでした。
Pythonのrequestsモジュールを使用してputしていたのですが、明示的にcontent-typeを指定していないことが原因でした。 これでエラーがSignatureDoesNotMatchなので、中々たどり着けませんでした…。
なので、以下のような形でヘッダにContent-Typeを指定してあげることで解決しました。
with open(csv_path, mode='rb') as f:
res_put = requests.put(
url=preSignedUrl,
data=f,
headers={'Content-Type': 'text/csv'}
)
ここらへんまとまったドキュメント見つからなかったのですが、どこかにあるのでしょうか…。 もしあるのであればぜひ教えて頂きたいです。。