To see an implementation in action, check this repo.
When you create the
S3Client service object without specifying credentials, it will use the one available from the environment. In the case of Lambda, that will be the execution role assigned to the function. This means the S3 service object that is created this way has all the permissions the Lambda function has, which is usually more than the absolute necessary to sign URLs.
For example, let's say there is a bucket where users can download files from using signed URLs. But that bucket can also contain other files the users are not supposed to see. As an illustration, files under
/user/ can be downloaded while files under other prefixes, such as
/logs/, are not available.
But since the function might need permission to read the entire bucket, it has more permissions than what is absolutely necessary to sign URLs. And this violates the principle of least privilege.
Of course, the backend can check that only files with the prefix
/user/ are signed and denies everything else. But if there is a mistake in that code, a malicious user might gain access to files they are not supposed to download. It would be a more secure setup if the signer entity has only permissions to get objects under the
The solution is to use a separate role instead of the execution role. In this case, permissions can be configured independently and if there is a bug in the backend code that can be exploited to sign objects outside the allowed prefix, the resulting signed URL would be unusable because the S3 service rejects it.