question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

aws-cloudfront: easily support Origin Access Identity for S3 buckets

See original GitHub issue

Currently it doesn’t seem possible to do this without creating a CloudFrontOriginAccessIdentityResource and then creating a ‘Canonical User’ policy fragment.

Here’s the Java version:

        Bucket bucket = new Bucket(this, "Bucket", BucketProps.builder()
                .build());

        CloudFrontOriginAccessIdentityResource identityResource = new CloudFrontOriginAccessIdentityResource(this, "OAI", CloudFrontOriginAccessIdentityResourceProps.builder()
                .withCloudFrontOriginAccessIdentityConfig(new CloudFrontOriginAccessIdentityResource.CloudFrontOriginAccessIdentityConfigProperty.Builder()
                        .withComment("A comment")
                        .build()
                )
                .build());

        CloudFrontWebDistribution webDistribution = new CloudFrontWebDistribution(this, "CloudFront", CloudFrontWebDistributionProps.builder()
                .withViewerProtocolPolicy(ViewerProtocolPolicy.RedirectToHTTPS)
                .withPriceClass(PriceClass.PriceClass100)
                .withHttpVersion(HttpVersion.HTTP2)
                .withDefaultRootObject("")
                .withOriginConfigs(Collections.singletonList(
                        SourceConfiguration.builder()
                                .withBehaviors(Collections.singletonList(
                                        Behavior.builder()
                                                .withAllowedMethods(CloudFrontAllowedMethods.ALL)
                                                .withDefaultTtlSeconds(60)
                                                .withIsDefaultBehavior(true)
                                                .withForwardedValues(DistributionResource.ForwardedValuesProperty.builder()
                                                        .withCookies(DistributionResource.CookiesProperty.builder()
                                                                .withWhitelistedNames(Arrays.asList(
                                                                        "csrftoken",
                                                                        "sessionid",
                                                                        "messages"
                                                                ))
                                                                .withForward("whitelist")
                                                                .build())
                                                        .withQueryString(true)
                                                        .build())
                                                .build()
                                ))
                                .withS3OriginSource(S3OriginConfig.builder()
                                        .withS3BucketSource(bucket)
                                        .withOriginAccessIdentity(identityResource)
                                        .build())
                                .withOriginHeaders(new HashMap<String, String>() {{
                                    put("X-CloudFront-Forwarded-Proto", "https");
                                }})
                                .build()
                ))
                .build());

        class CanonicalUserPrincipal extends AccountPrincipal {
            private String canonicalUserId;

            private CanonicalUserPrincipal(String canonicalUserId) {
                this.canonicalUserId = canonicalUserId;
            }

            @Override
            public PrincipalPolicyFragment policyFragment() {
                return new PrincipalPolicyFragment(new HashMap<String,String>() {{
                    put("CanonicalUser", canonicalUserId);
                }});
            }
        }

        PolicyDocument document = new PolicyDocument();
        document.addStatement(new PolicyStatement()
                .addPrincipal(new CanonicalUserPrincipal(identityResource.getCloudFrontOriginAccessIdentityS3CanonicalUserId()))
                .addAction("s3:GetObject")
                .addResource("arn:aws:s3:::" + bucket.getBucketName() + "/*")
        );

        new BucketPolicyResource(this, "BucketPolicy", BucketPolicyResourceProps.builder()
                .withBucket(bucket.getBucketName())
                .withPolicyDocument(document)
                .build());

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:7
  • Comments:11 (9 by maintainers)

github_iconTop GitHub Comments

11reactions
dsandorcommented, Jul 27, 2019

FYI, I got this working by changing the policy statement I was creating to this:

    const policyStatement = new iam.PolicyStatement();
    policyStatement.addActions('s3:GetBucket*');
    policyStatement.addActions('s3:GetObject*');
    policyStatement.addActions('s3:List*');
    policyStatement.addResources(sourceBucket.bucketArn);
    policyStatement.addResources(`${sourceBucket.bucketArn}/*`);
    policyStatement.addCanonicalUserPrincipal(cloudFrontOia.attrS3CanonicalUserId);

    sourceBucket.addToResourcePolicy(policyStatement);

To match what the CDK was doing in other parts I added the bucketArn and the bucketArn with /*. I also changed the addArnPrincipal to addCanonicalUserPrincipal. This now properly creates a CloudFront distribution that has access to the bucket.

I created a class to make this easier called StaticWebsiteStack that lets you pass in some variables and it does all the magic needed to create the bucket, the Cloud Front distro and the bucket policy for a static website. It also supports versioning. The code is here with an example website (look in the /aws directory): https://github.com/dsandor/cdk-static-website

9reactions
rix0rrrcommented, Oct 17, 2018

Agreed. Passing the S3 bucket should do all this work.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Restricting access to an Amazon S3 origin - Amazon CloudFront
If your origin is an Amazon S3 bucket configured as a website endpoint, you must set it up with CloudFront as a custom...
Read more >
Cloudfront Origin Access Identity (OAI): How to use it? - StormIT
1. Log in to the CloudFront Console. · 2. Click on “Create Distribution”. · 3. Select S3 bucket as origin domain, choose “Yes...
Read more >
Securing S3 with Origin Access Identity (OAI) via CloudFront
In my introductory AWS CloudFront article, it was explained how we can secure native and custom origins via CloudFront. Out of those methods, ......
Read more >
How Origin Access Identity works - Advanced Web Machinery
The Origin Access Identity (OAI) is the primary way to make CloudFront access private content stored in S3. Without it, CloudFront is like...
Read more >
Creating an S3 bucket policy that allows access to Cloudfront ...
Details here: Using an Origin Access Identity to Restrict Access to Your Amazon S3 Content - Amazon CloudFront.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found