[Boto3] オプトインリージョンに作成したS3バケットにAPIアクセスする際にはリージョンを指定しなければいけない

こんにちは。サービス開発室の武田です。オプトインリージョンのS3バケットをAPI操作する際にはリージョン指定をしましょう。
2024.03.28

こんにちは。サービス開発室の武田です。

ある日S3バケットにアクセスしているシステムのログに次のエラーが記録されていました。

botocore.exceptions.ClientError: An error occurred (IllegalLocationConstraintException) when calling the GetBucketLogging operation: The eu-south-1 location constraint is incompatible for the region specific endpoint this request was sent to.

見慣れないエラーですが、メッセージに出ているeu-south-1は欧州(ミラノ)リージョンです。eu-south-1ってそういえばオプトインリージョンだね!とすぐに気付いた方はAWSお詳しいですね!

このシステムはboto3を利用して処理をしているのですが、東京リージョンのクライアントを作成して各処理を実行していました。イメージとしては次のようなものです。

client = boto3.client("s3")
result = client.get_bucket_logging(Bucket=bucket_name)
print(result)

ほとんどのバケットはこの処理が動くわけですが、前述したようにオプトインリージョンのバケットを指定した場合エラーとなってしまいました。どうやらオプトインリージョンのバケットにアクセスする際には、当該リージョンのクライアントを作成する必要があるようです。

ではバケットのリージョンはどのように取得するかといえば、get_bucket_location()を使用します。検証したところ、このメソッドはオプトインリージョンのバケットを指定しても動きました。

そんなわけで、先ほどのコードをオプトインリージョンが対象となっても動くようにするには、次のように改修すればよさそうです。

client = boto3.client("s3")

try:
    result = client.get_bucket_logging(Bucket=bucket_name)
except botocore.exceptions.ClientError as e:
    if e.response["Error"]["Code"] != "IllegalLocationConstraintException":
        raise e

    region = client.get_bucket_location(Bucket=bucket_name)["LocationConstraint"]
    optin_client = boto3.client("s3", region_name=region)
    result = optin_client.get_bucket_logging(Bucket=bucket_name)

print(result)

まとめ

オプトインリージョンはデフォルトで有効化されているリージョンと細かい部分で差がありますね。見つけ次第細かく改善していきましょう。