Cloudfront提供通过AWS CDK Python为S3存储桶起源创建的Access拒绝响应,而无需公共访问 [英] Cloudfront give Access denied response created through AWS CDK Python for S3 bucket origin without public Access

查看:114
本文介绍了Cloudfront提供通过AWS CDK Python为S3存储桶起源创建的Access拒绝响应,而无需公共访问的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用适用于S3存储桶的AWS CDK创建了Cloud Front Web分发,而无需公共访问。
能够创建Origin访问身份,并进行部署,但是部署成功后,我在浏览器上的访问被拒绝。

Created Cloud Front web distribution with AWS CDK for S3 bucket without public access. Able to create Origin access identity, and deploy but on successful deploy i get access denied response on browser.

授予对存储桶的读取权限将设置为No,将其手动设置为Yes,一切都会正常运行,但是此设置需要通过AWS CDK和python实现。
下面是我的代码。

Grant Read Permissions on Bucket from Origin settings will be set to No, setting this to Yes manually everything will work fine, but this setting needs to be achieved through AWS CDK and python. Below is my code.

from aws_cdk import aws_cloudfront as front, aws_s3 as s3

class CloudFrontStack(core.Stack):        
    def __init__(self, scope: core.Construct, idx: str, **kwargs) -> None:
        super().__init__(scope, idx, **kwargs)

        bucket = s3.Bucket.from_bucket_name(self, 'CloudFront',bucket_name="bucket_name")

        oia = aws_cloudfront.OriginAccessIdentity(self, 'OIA', comment="Created By CDK")
        bucket.grant_read(oia)

        s3_origin_source = aws_cloudfront.S3OriginConfig(s3_bucket_source=bucket, origin_access_identity=oia)

        source_config = aws_cloudfront.SourceConfiguration(s3_origin_source=s3_origin_source,
                                                           origin_path="bucket_path",
                                                           behaviors=[aws_cloudfront.Behavior(is_default_behavior=True)])

        aws_cloudfront.CloudFrontWebDistribution(self, "cloud_front_name",
                                                 origin_configs=[source_config],
                                                 comment='Cloud Formation created',
                                                 default_root_object='index.html')

我还尝试了向as添加权限

I also tried adding the permissions to the as below but still no luck.

policyStatement = aws_iam.PolicyStatement()
policyStatement.add_resources()

policyStatement.add_actions('s3:GetBucket*');
policyStatement.add_actions('s3:GetObject*');
policyStatement.add_actions('s3:List*');
policyStatement.add_resources(bucket.bucket_arn);
policyStatement.add_canonical_user_principal(oia.cloud_front_origin_access_identity_s3_canonical_user_id);
code_bucket.add_to_resource_policy(policyStatement);


推荐答案

我试图模仿这一点,并且能够集成Cloudfront成功分发到私有S3存储桶。但是,我将TS用于堆栈。我敢肯定,将下面的代码与Python版本关联起来会很容易。假设在 dist

I tried to mimic this and was able to integrate Cloudfront distribution to a private S3 bucket successfully. However, I used TS for my stack. I am sure it will be easy to correlate below code to Python version. Assume there is an index.html file in dist

aws-cdk v1.31.0(截至2020年3月29日)

import { App, Stack, StackProps } from '@aws-cdk/core';
import { BucketDeployment, Source } from '@aws-cdk/aws-s3-deployment';
import { CloudFrontWebDistribution, OriginAccessIdentity } from '@aws-cdk/aws-cloudfront';
import { BlockPublicAccess, Bucket, BucketEncryption } from '@aws-cdk/aws-s3';

export class HelloCdkStack extends Stack {
  constructor(scope: App, id: string, props?: StackProps) {
    super(scope, id, props);

    const myFirstBucket = new Bucket(this, 'MyFirstBucket', {
      versioned: true,
      encryption: BucketEncryption.S3_MANAGED,
      bucketName: 'cdk-example-bucket-for-test',
      websiteIndexDocument: 'index.html',
      blockPublicAccess: BlockPublicAccess.BLOCK_ALL
    });

    new BucketDeployment(this, 'DeployWebsite', {
      sources: [Source.asset('dist')],
      destinationBucket: myFirstBucket
    });

    const oia = new OriginAccessIdentity(this, 'OIA', {
      comment: "Created by CDK"
    });
    myFirstBucket.grantRead(oia);

    new CloudFrontWebDistribution(this, 'cdk-example-distribution', {
      originConfigs: [
        {
          s3OriginSource: {
            s3BucketSource: myFirstBucket,
            originAccessIdentity: oia
          },
          behaviors: [
            { isDefaultBehavior: true }
          ]
        }
      ]
    });
  }
}

== 更新 = = [没有Web托管的S3存储桶]

这里是一个示例,其中S3用作没有Web托管的原始服务器。

Here is an example where S3 is used as an Origin without Web hosting. It works as expected.

import { App, Stack, StackProps } from '@aws-cdk/core';
import { BucketDeployment, Source } from '@aws-cdk/aws-s3-deployment';
import { CloudFrontWebDistribution, OriginAccessIdentity } from '@aws-cdk/aws-cloudfront';
import { BlockPublicAccess, Bucket, BucketEncryption } from '@aws-cdk/aws-s3';

export class CloudfrontS3Stack extends Stack {
  constructor(scope: App, id: string, props?: StackProps) {
    super(scope, id, props);

    // Create bucket (which is not a static website host), encrypted AES-256 and block all public access
    // Only Cloudfront access to S3 bucket
    const testBucket = new Bucket(this, 'TestS3Bucket', {
      encryption: BucketEncryption.S3_MANAGED,
      bucketName: 'cdk-static-asset-dmahapatro',
      blockPublicAccess: BlockPublicAccess.BLOCK_ALL
    });

    // Create Origin Access Identity to be use Canonical User Id in S3 bucket policy
    const originAccessIdentity = new OriginAccessIdentity(this, 'OAI', {
      comment: "Created_by_dmahapatro"
    });
    testBucket.grantRead(originAccessIdentity);

    // Create Cloudfront distribution with S3 as Origin
    const distribution = new CloudFrontWebDistribution(this, 'cdk-example-distribution', {
      originConfigs: [
        {
          s3OriginSource: {
            s3BucketSource: testBucket,
            originAccessIdentity: originAccessIdentity
          },
          behaviors: [
            { isDefaultBehavior: true }
          ]
        }
      ]
    });

    // Upload items in bucket and provide distribution to create invalidations
    new BucketDeployment(this, 'DeployWebsite', {
      sources: [Source.asset('dist')],
      destinationBucket: testBucket,
      distribution,
      distributionPaths: ['/images/*.png']
    });
  }
}

== 更新 = = [导入了S3存储桶,而不是在同一堆栈中创建]

当我们引用现有的S3存储桶时,可以重新创建问题。

When we refer to an existing S3 bucket the issue can be recreated.

原因

问题的根本原因在于在此代码行 autoCreatePolicy 对于导入的S3存储桶而言,始终为 false
要使 addResourcePolicy 工作,导入的存储桶必须已经有一个现有的存储桶策略,以便可以附加新的策略语句,或者手动创建新的存储桶策略并添加政策声明。在下面的代码中,我手动创建了存储桶策略并添加了所需的策略语句。这非常接近 github问题#941 ,但两者之间的细微差别是在堆栈中创建存储桶与导入已创建的存储桶。

Reason:
The root cause of the issue lies here in this line of code. autoCreatePolicy will always be false for an imported S3 bucket. To make addResourcePolicy work either the imported bucket has to already have an existing Bucket policy so that the new policy statements can be appended or manually create new BucketPolicy and add the policy statements. In the below code I have manually created the bucket policy and add the required policy statements. This is very close to the github issue #941 but the subtle difference is between creating a bucket in the stack vs importing an already created bucket.

import { App, Stack, StackProps } from '@aws-cdk/core';
import { CloudFrontWebDistribution, OriginAccessIdentity } from '@aws-cdk/aws-cloudfront';
import { Bucket, BucketPolicy } from '@aws-cdk/aws-s3';
import { PolicyStatement } from '@aws-cdk/aws-iam';

export class CloudfrontS3Stack extends Stack {
  constructor(scope: App, id: string, props?: StackProps) {
    super(scope, id, props);

    const testBucket = Bucket.fromBucketName(this, 'TestBucket', 'dmahapatro-personal-bucket');

    // Create Origin Access Identity to be use Canonical User Id in S3 bucket policy
    const originAccessIdentity = new OriginAccessIdentity(this, 'OAI', {
      comment: "Created_by_dmahapatro"
    });

    // This does not seem to work if Bucket.fromBucketName is used
    // It works for S3 buckets which are created as part of this stack
    // testBucket.grantRead(originAccessIdentity);

    // Explicitly add Bucket Policy 
    const policyStatement = new PolicyStatement();
    policyStatement.addActions('s3:GetBucket*');
    policyStatement.addActions('s3:GetObject*');
    policyStatement.addActions('s3:List*');
    policyStatement.addResources(testBucket.bucketArn);
    policyStatement.addResources(`${testBucket.bucketArn}/*`);
    policyStatement.addCanonicalUserPrincipal(originAccessIdentity.cloudFrontOriginAccessIdentityS3CanonicalUserId);

    // testBucket.addToResourcePolicy(policyStatement);

    // Manually create or update bucket policy
    if( !testBucket.policy ) {
      new BucketPolicy(this, 'Policy', { bucket: testBucket }).document.addStatements(policyStatement);
    } else {
      testBucket.policy.document.addStatements(policyStatement);
    }

    // Create Cloudfront distribution with S3 as Origin
    const distribution = new CloudFrontWebDistribution(this, 'cdk-example-distribution', {
      originConfigs: [
        {
          s3OriginSource: {
            s3BucketSource: testBucket,
            originAccessIdentity: originAccessIdentity
          },
          behaviors: [
            { isDefaultBehavior: true }
          ]
        }
      ]
    });
  }
}

这篇关于Cloudfront提供通过AWS CDK Python为S3存储桶起源创建的Access拒绝响应,而无需公共访问的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆