Я попытался имитировать c это и смог успешно интегрировать дистрибутив Cloudfront в частную корзину S3. Тем не менее, я использовал TS для своего стека. Я уверен, что будет легко соотнести приведенный ниже код с Python версией. Предположим, есть файл index.html
в dist
aws -cdk v1.31.0 (последний по состоянию на 29 марта 2020 г.)
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 }
]
}
]
});
}
}
== Обновление == [корзина S3 без веб-хостинга]
Вот пример, где S3 используется в качестве источника без веб-хостинга. Работает как положено.
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 Bucket импортируется вместо создания в том же стеке]
Когда мы ссылаемся на существующую корзину S3, проблему можно воссоздать.
Причина :
Причина проблемы root находится здесь, в этой строке кода . autoCreatePolicy
всегда будет false
для импортированной корзины S3 . Чтобы заставить addResourcePolicy
работать, либо импортированный сегмент должен уже иметь существующую политику Bucket, чтобы можно было добавлять новые операторы политики, либо вручную создавать новый BucketPolicy и добавлять операторы политики. В приведенном ниже коде я вручную создал политику сегмента и добавил необходимые инструкции политики. Это очень близко к проблеме github # 941 , но тонкое различие между созданием сегмента в стеке и импортом уже созданного сегмента.
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 }
]
}
]
});
}
}