-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
s3: can't enable bucket public access #26559
Comments
related to #25983 |
Trying to write a very basic construct that deploys a simple website on S3, haven't managed to make it work even with some explicit setting of object ownership and access control. Keep getting Access Denied as the bucket policy does not allow for Put actions. Code used to work before: export class S3Website extends Construct {
public readonly websiteBucket: s3.Bucket;
constructor(scope: Construct, id: string, props: IS3WebsiteProps) {
super(scope, id);
// ----------------------------------------------------
// - S3 Bucket -
// ----------------------------------------------------
this.websiteBucket = new s3.Bucket(this, "Bucket", {
// ⚙️ bucket config
versioned: true,
// 🌐 Website config
blockPublicAccess: {
blockPublicAcls: false,
blockPublicPolicy: false,
ignorePublicAcls: false,
restrictPublicBuckets: false,
},
publicReadAccess: true,
objectOwnership: s3.ObjectOwnership.OBJECT_WRITER,
accessControl: s3.BucketAccessControl.PUBLIC_READ,
websiteIndexDocument: "index.html",
websiteErrorDocument: "error.html",
// What happens when I delete the stack?
removalPolicy: cdk.RemovalPolicy.DESTROY,
autoDeleteObjects: true,
});
const deployment = new s3deploy.BucketDeployment(this, "DeployWebsite", {
sources: [props.websiteFilesPath],
destinationBucket: this.websiteBucket,
contentLanguage: "en",
accessControl: s3.BucketAccessControl.PUBLIC_READ,
});
}
} |
I seem to have achieved this for a brand new bucket by using policy rather than ACL: const bucket = new s3.Bucket(this, id, {
...,
blockPublicAccess: {
blockPublicAcls: true,
ignorePublicAcls: true,
restrictPublicBuckets: false,
blockPublicPolicy: false,
}
})
bucket.addToResourcePolicy(
new PolicyStatement({
actions: ['s3:GetObject'],
effect: Effect.ALLOW,
principals: [new StarPrincipal()],
resources: [bucket.arnForObjects('*')],
})
) |
I managed to make it work by going to the Amazon S3 Settings page and disabling the account level public access block. main.ts #!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import * as path from "path";
import { S3Website } from "../lib/s3-website/website";
import { Construct } from "constructs";
import * as s3deploy from "aws-cdk-lib/aws-s3-deployment";
export class MyStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Provision S3 Website
const website = new S3Website(this, "website-deployment", {
websiteFilesPath: s3deploy.Source.asset(path.join(__dirname, "website-files")),
});
new cdk.CfnOutput(this, 'website-url', {
value: website.websiteBucket.bucketWebsiteUrl
})
}
}
const app = new cdk.App();
const stack = new MyStack(app, 'S3WebsiteStack', {}); /lib/s3-webiste/website.ts import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import * as s3 from "aws-cdk-lib/aws-s3";
import * as s3deploy from "aws-cdk-lib/aws-s3-deployment";
import { readFileSync } from "fs";
import * as path from "path";
export interface IS3WebsiteProps {
readonly websiteFilesPath: s3deploy.ISource;
}
export class S3Website extends Construct {
public readonly websiteBucket: s3.Bucket;
constructor(scope: Construct, id: string, props: IS3WebsiteProps) {
super(scope, id);
// ----------------------------------------------------
// - S3 Bucket -
// ----------------------------------------------------
this.websiteBucket = new s3.Bucket(this, "Bucket", {
versioned: true,
blockPublicAccess: {
blockPublicAcls: false,
blockPublicPolicy: false,
ignorePublicAcls: false,
restrictPublicBuckets: false,
},
publicReadAccess: true,
objectOwnership: s3.ObjectOwnership.BUCKET_OWNER_ENFORCED,
websiteIndexDocument: "index.html",
websiteErrorDocument: "error.html",
removalPolicy: cdk.RemovalPolicy.DESTROY,
autoDeleteObjects: true,
});
const deployment = new s3deploy.BucketDeployment(this, "DeployWebsite", {
sources: [props.websiteFilesPath],
destinationBucket: this.websiteBucket,
contentLanguage: "en",
});
}
} |
I'd be interested to know if this is good practice or not, and if others that have gotten it to work have also done so by disabling the account-level blocks. I haven't been able to get the '100% works' solution in the OP to work for me. I'm extra confused as my IAM role in the cli has AdministratorAccess. |
I just came across this problem, for a bucket already created without public access (nor any specification in the CDK for blocks). On checking my account level blocks, these were all disabled (apparently by default but I've used Amplify to deploy websites before on this account so possible that prompted me to disable the account blocks at some point). @robdmoore's comment worked for me, but the Note that I didn't try to enable public access for the entire bucket, only for a key prefix, e.g. |
I seem to have achieved this with
const bucket = new s3.Bucket(this.scope, 'FrontendBucket', {
bucketName: `${this.props.suffixName}-mimic-frontend`,
removalPolicy: cdk.RemovalPolicy.DESTROY,
encryption: s3.BucketEncryption.S3_MANAGED,
websiteIndexDocument: 'index.html',
objectOwnership: s3.ObjectOwnership.OBJECT_WRITER,
accessControl: s3.BucketAccessControl.PUBLIC_READ,
blockPublicAccess: {
blockPublicAcls: false,
blockPublicPolicy: false,
ignorePublicAcls: false,
restrictPublicBuckets: false,
},
publicReadAccess: true,
cors: [
{
allowedOrigins: ['*'],
allowedMethods: [s3.HttpMethods.GET],
allowedHeaders: ['*'],
exposedHeaders: [],
maxAge: 3000
}
],
lifecycleRules: [
{
abortIncompleteMultipartUploadAfter: cdk.Duration.days(7)
}
]
}); |
this is what worked for me: "aws-cdk": "^2.135.0" const bucket = new s3.Bucket(this.scope, 'bucket-id', {
bucketName: 'bucket-name',
removalPolicy: cdk.RemovalPolicy.DESTROY,
encryption: s3.BucketEncryption.S3_MANAGED,
websiteIndexDocument: 'index.html', // <- optional
objectOwnership: s3.ObjectOwnership.OBJECT_WRITER,
// accessControl: s3.BucketAccessControl.PUBLIC_READ, <-- NO
blockPublicAccess: {
blockPublicAcls: false,
blockPublicPolicy: false,
ignorePublicAcls: false,
restrictPublicBuckets: false,
},
// publicReadAccess: true, <-- NO
cors: [
{
allowedOrigins: ['*'],
allowedMethods: [s3.HttpMethods.GET,s3.HttpMethods.HEAD],
allowedHeaders: ['*'],
exposedHeaders: [],
maxAge: 3000
}
],
lifecycleRules: [
{
abortIncompleteMultipartUploadAfter: cdk.Duration.days(7)
}
]
});
// Use this instead of accessControl and publicReadAccess above
const public_policy = new iam.PolicyStatement({
actions: ['s3:GetObject'],
effect: iam.Effect.ALLOW,
principals: [new iam.AnyPrincipal()],
resources: [bucket.arnForObjects('*')],
});
bucket.addToResourcePolicy(public_policy); |
I'm thinking this may be a regression of the cdk, being that you and I both hit this on the same day. |
Right after posting my workaround, i stepped my new bucket back to a private one (defaults), and put a cloudfront distro in front of it. The distro in my use case was probably a better move anyway, but its interesting to see all the variation on this issue. |
I ran into this issue while trying to get a simple frontend app running in an s3 bucket. The band-aid workaround I found was doing an initial run without the const bucket = new Bucket(this, 'MyBucket', {
websiteIndexDocument: 'index.html',
blockPublicAccess: {
blockPublicPolicy: false,
blockPublicAcls: false,
ignorePublicAcls: false,
restrictPublicBuckets: false,
},
// publicReadAccess: true,
}); Then after it successfully completed, I reran the deploy with const bucket = new Bucket(this, 'MyBucket', {
websiteIndexDocument: 'index.html',
blockPublicAccess: {
blockPublicPolicy: false,
blockPublicAcls: false,
ignorePublicAcls: false,
restrictPublicBuckets: false,
},
publicReadAccess: true,
}); |
make it work with const createS3Bucket = (scope: Construct, uploaderUserArn: string): cdk.aws_s3.Bucket => {
const bucket = new s3.Bucket(scope, prefixResource('Bucket'), {
- accessControl: s3.BucketAccessControl.PRIVATE,
+ blockPublicAccess: {
+ blockPublicAcls: false,
+ blockPublicPolicy: false,
+ ignorePublicAcls: false,
+ restrictPublicBuckets: false,
+ },
cors: [
{
allowedMethods: [s3.HttpMethods.GET, s3.HttpMethods.HEAD],
allowedOrigins: ['*'],
},
],
+ websiteIndexDocument: 'index.html',
});
// allow user to upload files to S3 bucket
bucket.grantPut(new iam.ArnPrincipal(uploaderUserArn));
+
+ // allow anyone to read
+ bucket.grantRead(new iam.AnyPrincipal());
return bucket;
}
|
Describe the bug
#25358 introduced the major changes for S3 in April 2023 but it's still unclear to customers how to setup a S3 bucket with public access enabled for some use cases like static website hosting.
Expected Behavior
As #25358 (comment) suggested, this should work:
Current Behavior
It would fail with this error but sometimes it deploys successfully.
I guess this could be a bug from cloudformation as it does not always fail.
Another alternative is to deploy with
accessControl: BucketAccessControl.PUBLIC_READ
commented off.And re-deploy with
accessControl
enabled. This will 100% work.I guess the cloudformation handler probably can't handle this well when both
accessControl
andobjectOwnership
are enabled.Reproduction Steps
See current behavior.
Possible Solution
See current behavior. This might be a CFN bug.
Additional Information/Context
The synth output for the Bucket resource
CDK CLI Version
2.88.0
Framework Version
No response
Node.js Version
v18.15.0
OS
mac os x
Language
Typescript
Language Version
No response
Other information
No response
The text was updated successfully, but these errors were encountered: