我用的 ServiceAccount 关联的 IAM Role 做的 k8s 应用内的授权。使用的 aws-java-sdk v1 的版本客户端。 这样 Presign 一个 S3 文件:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Date;
import com.amazonaws.SDKGlobalConfiguration;
import com.amazonaws.auth.WebIdentityTokenCredentialsProvider;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
public class S3Signer{
static{
System.setProperty(SDKGlobalConfiguration.ENABLE_S3_SIGV4_SYSTEM_PROPERTY, "true");
}
public static String generateUrl(AmazonS3 amazonS3, String bucketName, String key) {
GeneratePresignedUrlRequest urlRequest = new GeneratePresignedUrlRequest(bucketName,key);
// 1 hour expiration time
urlRequest.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60));
URL url = amazonS3.generatePresignedUrl(urlRequest);
return url.toString();
}
public static void main(String[] args) {
String region = args[0];
String roleArn = args[1];
String sessionName = args[2];
String tokenFile = args[3];
String bucketName = args[4];
String key = args[5];
AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard().withRegion(region);
System.out.println("roleArn:"+ roleArn + " tokenFile:" + tokenFile + " sessionName:" + sessionName);
builder.withCredentials(WebIdentityTokenCredentialsProvider.builder()
.roleArn(roleArn)
.webIdentityTokenFile(tokenFile)
.roleSessionName(sessionName)
.build());
AmazonS3 s3 = builder.build();
String location = s3.getBucketLocation(bucketName);
System.out.println("bucket location:" + location + " bucket: " + bucketName);
s3.putObject(bucketName,"hello.txt", "hello world");
System.out.println(generateUrl(s3, bucketName, key));
}
}
如果你有遇到下面这个 AuthorizationQueryParametersError 错误,
<Error>
<Code>AuthorizationQueryParametersError</Code>
<Message>X-Amz-Algorithm only supports "AWS4-HMAC-SHA256 and AWS4-ECDSA-P256-SHA256"</Message>
<RequestId>EHCHR1687MYQKZZD</RequestId>
<HostId>xlywJTkA5oqp/9sA6VaVKqYwGEDKpK2AS5EK2R6DVpioNZUGJS3I97lWFAKAxNVYfHVMCJ4RDZM=</HostId>
</Error>
这个错误说明签名得到了 AWS3 的参数,算法不支持,需要使用 S4的算法。加上签名的代码:
System.setProperty(SDKGlobalConfiguration.ENABLE_S3_SIGV4_SYSTEM_PROPERTY, "true");
如果遇到下面的 UnauthorizedAccess 错误信息,提示 You are not authorized to perform this operation:
<Error>
<Code>UnauthorizedAccess</Code>
<Message>You are not authorized to perform this operation</Message>
<RequestId>MCRMH7258TQ6ATXG</RequestId>
<HostId>D7WNA1djj5eHh3oA2x6Sj7ef7ke2R3VxX4DyB+uiNsOXQHmQaLI/MzTO/mQqIQ9wWIfi3wyFY8A=</HostId>
</Error>
依次检查:
1.权限是否正确。 比如用 IAM Role 的话,检查 环境变量中是否有正确的信息
kubectl exec my-application-deplyoment-67f8d677f5-ztw7z env | grep AWS
比如我的信息
AWS_REGION=cn-northwest-1
AWS_ROLE_ARN=arn:aws-cn:iam::xxxx:role/my-cluster-addon-iamserviceaccount-al-Role1-abcd
AWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount/token
AWS_DEFAULT_REGION=cn-northwest-1
2.检查授权策略是否包含了 S3 的访问权限。
3.如果是在中国区,默认访问不了 80, 443 端口的 URL。需要上传 ICP 备案信息之后才可以正常访问到。 参考:amazon web services - You are not authorized to perform this operation - Stack Overflow
如果读取 token 遇到错误, 参考:
https://github.com/aws/aws-sdk-java-v2/issues/1470s
使用 aws 2.0 SDK 签名 S3 URL:
1Example usage for com.amazonaws.services.s3.model GeneratePresignedUrlRequest GeneratePresignedUrlRequest
https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/s3/src/main/java/com/example/s3/GetObjectPresignedUrl.java
AWS Java SDK 2.0 create a presigned URL for a S3 object | Newbedev
[Solved] Java Can't access S3 PreSigned URL due to authorization - Code Redirect