将策略分配给 S3 存储桶以便仅供 CloudFront 分配使用
Assigning policy to S3Bucket in order to be used only by a CloudFront Distribution
此脚本展示了我如何创建 CloudFront 原始访问身份、一个将保存我的 web 应用程序的存储桶以及我如何分配存储桶策略以仅允许从 CloudFront 分配访问该存储桶。
在这种情况下,真正令人惊讶(和烦人)的事实是 如果我在 Eclipse 中逐行调试它,那么这段代码是有效的,但是如果我尝试启动它没有逐行执行(即在策略分配之后设置断点),然后出现以下异常...
希望有人能帮忙!
String myBucket = transferManager.getAmazonS3Client().createBucket(new CreateBucketRequest("my-bucket-name")).getName();
CloudFrontOriginAccessIdentity myOAI = cloudFrontClient.createCloudFrontOriginAccessIdentity(
new CreateCloudFrontOriginAccessIdentityRequest().withCloudFrontOriginAccessIdentityConfig(
new CloudFrontOriginAccessIdentityConfig().withCallerReference(UUID.randomUUID().toString()).withComment("myOAI"))).getCloudFrontOriginAccessIdentity();
//*ATTEMPT 1: Using canonical user Id*
transferManager.getAmazonS3Client().setBucketPolicy(myBucketName, new Policy().
withId("MyPolicyForCloudFrontPrivateContent").
withStatements(new Statement(Effect.Allow).
withId("Grant CloudFront Origin Identity access to support private content").
withActions(S3Actions.GetObject).
withPrincipals(new Principal("CanonicalUser:" + myOAI.getS3CanonicalUserId())).
withResources(new S3ObjectResource(myBucketName,"*"))).toJson());
//*ATTEMPT 2: Using OAI id*
transferManager.getAmazonS3Client().setBucketPolicy(myBucketName, new Policy().
withId("MyPolicyForCloudFrontPrivateContent").
withStatements(new Statement(Effect.Allow).
withActions(S3Actions.GetObject).
withPrincipals(new Principal("arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity " + myOAI.getId())).
withResources(new S3ObjectResource(myBucketName,"*"))).toJson());
//*ATTEMP 3: HARDCODING THE POLICY*
String myPolicy = "{\"Version\":\"2012-10-17\",\"Id\":\"PolicyForCloudFrontPrivateContent\",\"Statement\":[{\"Sid\":\" Grant a CloudFront Origin Identity access to support private content\",\"Effect\":\"Allow\",\"Principal\":{\"CanonicalUser\":\"" + myOAI.getS3CanonicalUserId() + "\"},\"Action\":\"s3:GetObject\",\"Resource\":\"arn:aws:s3:::" + myBucketName + "/*\"}]}";
transferManager.getAmazonS3Client().setBucketPolicy(myBucketName, myPolicy);
//*ERROR MESSAGE*
Exception in thread "main" com.amazonaws.services.s3.model.AmazonS3Exception: Invalid principal in policy (Service: Amazon S3; Status Code: 400; Error Code: MalformedPolicy; Request ID: XXXXXXXXXXXXX), S3 Extended Request ID: YYYYYYYYYYYYYYYYYYYYYY+XXXXXXXXXXXXXXXXXXXXXXX=
at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:1088)
at com.amazonaws.http.AmazonHttpClient.executeOneRequest(AmazonHttpClient.java:735)
at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:461)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:296)
at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:3737)
at com.amazonaws.services.s3.AmazonS3Client.setBucketPolicy(AmazonS3Client.java:2372)
at com.myapp.services.DeploymentService.applyVersion(DeploymentService.java:234)
at com.myapp.services.DeploymentService.launch(DeploymentService.java:3553)
at com.myapp.EntryPoint.main(EntryPoint.java:35)
发现问题...
当您创建 Cloudfront Origin Access Identity (OAI) 并尝试立即将其分配到存储桶策略时,似乎会出现错误,因为新的 OAI 更改不会立即传播。
一个有效的解决方法是实施重试条件策略:
class CloudFrontRetryCondition implements RetryCondition {
@Override
public boolean shouldRetry(AmazonWebServiceRequest originalRequest, AmazonClientException exception, int retriesAttempted) {
if(exception instanceof AmazonS3Exception) {
final AmazonS3Exception s3Exception = (AmazonS3Exception) exception;
return s3Exception.getStatusCode() == 400 &&
s3Exception.getErrorCode().equals("MalformedPolicy") &&
s3Exception.getErrorMessage().equals("Invalid principal in policy") &&
s3Exception.getAdditionalDetails().get("Detail").contains("arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity");
} else {
return false;
}
}
}
此脚本展示了我如何创建 CloudFront 原始访问身份、一个将保存我的 web 应用程序的存储桶以及我如何分配存储桶策略以仅允许从 CloudFront 分配访问该存储桶。
在这种情况下,真正令人惊讶(和烦人)的事实是 如果我在 Eclipse 中逐行调试它,那么这段代码是有效的,但是如果我尝试启动它没有逐行执行(即在策略分配之后设置断点),然后出现以下异常...
希望有人能帮忙!
String myBucket = transferManager.getAmazonS3Client().createBucket(new CreateBucketRequest("my-bucket-name")).getName();
CloudFrontOriginAccessIdentity myOAI = cloudFrontClient.createCloudFrontOriginAccessIdentity(
new CreateCloudFrontOriginAccessIdentityRequest().withCloudFrontOriginAccessIdentityConfig(
new CloudFrontOriginAccessIdentityConfig().withCallerReference(UUID.randomUUID().toString()).withComment("myOAI"))).getCloudFrontOriginAccessIdentity();
//*ATTEMPT 1: Using canonical user Id*
transferManager.getAmazonS3Client().setBucketPolicy(myBucketName, new Policy().
withId("MyPolicyForCloudFrontPrivateContent").
withStatements(new Statement(Effect.Allow).
withId("Grant CloudFront Origin Identity access to support private content").
withActions(S3Actions.GetObject).
withPrincipals(new Principal("CanonicalUser:" + myOAI.getS3CanonicalUserId())).
withResources(new S3ObjectResource(myBucketName,"*"))).toJson());
//*ATTEMPT 2: Using OAI id*
transferManager.getAmazonS3Client().setBucketPolicy(myBucketName, new Policy().
withId("MyPolicyForCloudFrontPrivateContent").
withStatements(new Statement(Effect.Allow).
withActions(S3Actions.GetObject).
withPrincipals(new Principal("arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity " + myOAI.getId())).
withResources(new S3ObjectResource(myBucketName,"*"))).toJson());
//*ATTEMP 3: HARDCODING THE POLICY*
String myPolicy = "{\"Version\":\"2012-10-17\",\"Id\":\"PolicyForCloudFrontPrivateContent\",\"Statement\":[{\"Sid\":\" Grant a CloudFront Origin Identity access to support private content\",\"Effect\":\"Allow\",\"Principal\":{\"CanonicalUser\":\"" + myOAI.getS3CanonicalUserId() + "\"},\"Action\":\"s3:GetObject\",\"Resource\":\"arn:aws:s3:::" + myBucketName + "/*\"}]}";
transferManager.getAmazonS3Client().setBucketPolicy(myBucketName, myPolicy);
//*ERROR MESSAGE*
Exception in thread "main" com.amazonaws.services.s3.model.AmazonS3Exception: Invalid principal in policy (Service: Amazon S3; Status Code: 400; Error Code: MalformedPolicy; Request ID: XXXXXXXXXXXXX), S3 Extended Request ID: YYYYYYYYYYYYYYYYYYYYYY+XXXXXXXXXXXXXXXXXXXXXXX=
at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:1088)
at com.amazonaws.http.AmazonHttpClient.executeOneRequest(AmazonHttpClient.java:735)
at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:461)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:296)
at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:3737)
at com.amazonaws.services.s3.AmazonS3Client.setBucketPolicy(AmazonS3Client.java:2372)
at com.myapp.services.DeploymentService.applyVersion(DeploymentService.java:234)
at com.myapp.services.DeploymentService.launch(DeploymentService.java:3553)
at com.myapp.EntryPoint.main(EntryPoint.java:35)
发现问题...
当您创建 Cloudfront Origin Access Identity (OAI) 并尝试立即将其分配到存储桶策略时,似乎会出现错误,因为新的 OAI 更改不会立即传播。
一个有效的解决方法是实施重试条件策略:
class CloudFrontRetryCondition implements RetryCondition {
@Override
public boolean shouldRetry(AmazonWebServiceRequest originalRequest, AmazonClientException exception, int retriesAttempted) {
if(exception instanceof AmazonS3Exception) {
final AmazonS3Exception s3Exception = (AmazonS3Exception) exception;
return s3Exception.getStatusCode() == 400 &&
s3Exception.getErrorCode().equals("MalformedPolicy") &&
s3Exception.getErrorMessage().equals("Invalid principal in policy") &&
s3Exception.getAdditionalDetails().get("Detail").contains("arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity");
} else {
return false;
}
}
}