I wanted to use Cli to generate upload commands for curl.
aws s3api put-object
succeeds, but this bash script prints “SignatureDoesNotMatch”:
bucket=somebucket
region=eu-central-1
key=/some.dat
file=aaa.txt
url=$(aws s3 presign "s3://${bucket:?}${key:?}" --region "${region:?}" --expires-in 600); url=${url%$'r'} # chomp possible CR
echo "$url"
curl -v --upload-file "${file:?}" "$url"
I even made a java program that uses software.amazon.awssdk
package and prints the curl command. The commands only differ by the order of URL params and the value of X-Amz-Signature=
, but the command produced by java succeeds:
$ curl -v --upload-file "aaa.txt" "https://somebucket.s3.eu-central-1.amazonaws.com/some.dat?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240605T103314Z&X-Amz-SignedHeaders=host&X-Amz-Expires=599&X-Amz-Credential=xxx%2F20240605%2Feu-central-1%2Fs3%2Faws4_request&X-Amz-Signature=xxxxxxxxx"
...
< HTTP/1.1 200 OK
I already checked my clock, tried an explicit --endpoint-url
argument, but it didn’t help.
public static void main(final String[] args) throws Exception {
final AwsBasicCredentials awsBasicCreds = AwsBasicCredentials.create(args[0], args[1]);
final StaticCredentialsProvider awsCredentialsProvider =
software.amazon.awssdk.auth.credentials.StaticCredentialsProvider.create(awsBasicCreds);
final String regionAsString = args[2];
final String bucket = args[3];
final String key = args[4];
final PresignedPutObjectRequest presignedPutObjectRequest =
makePresignedPutObjectRequest(regionAsString, bucket, key, awsCredentialsProvider);
final URL url = presignedPutObjectRequest.url();
System.out.print("curl -v --upload-file "" + args[5] + """);
for (final Entry<String, List<String>> pair : presignedPutObjectRequest
.httpRequest()
.headers()
.entrySet()) {
final String header = pair.getKey();
for (final String value : pair.getValue()) {
// The headers aren't needed after all
// System.out.print(" -H "" + header + ": " + value + "" ");
}
}
System.out.println(" "" + url + """);
}
public static PresignedPutObjectRequest makePresignedPutObjectRequest(
final String regionAsString,
final String bucket,
final String key,
final AwsCredentialsProvider awsCredentialsProvider) {
final Region region = Region.of(regionAsString);
final PutObjectRequest req = PutObjectRequest.builder().bucket(bucket).key(key).build();
final PutObjectPresignRequest putObjectPresignRequest =
PutObjectPresignRequest
.builder()
.signatureDuration(Duration.ofSeconds(600))
.putObjectRequest(req)
.build();
try (
final S3Presigner presigner =
S3Presigner
.builder()
.region(region)
.credentialsProvider(awsCredentialsProvider)
.build()) {
return presigner.presignPutObject(putObjectPresignRequest);
}
}