Skip to content
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

chore(s3): readme update with mixing L1 and L2 bucket policy #31437

Merged
merged 5 commits into from
Sep 13, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions packages/aws-cdk-lib/aws-s3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,117 @@ const bucket = new s3.Bucket(this, 'MyBucket', {
});
```

The above code will create a new bucket policy if none exists or update the
existing bucket policy to allow access log delivery.

However, there could be an edge case if the `accessLogsBucket` also defines a bucket
policy resource using the L1 Construct. Although the mixing of L1 and L2 Constructs is not
recommended, there are no mechanisms in place to prevent users from doing this at the moment.

```ts
const bucketName = "my-favorite-bucket-name";
GavinZZ marked this conversation as resolved.
Show resolved Hide resolved
const accessLogsBucket = new s3.Bucket(this, 'AccessLogsBucket', {
objectOwnership: s3.ObjectOwnership.BUCKET_OWNER_ENFORCED,
bucketName,
});

// Creating a bucket policy using L1
const bucketPolicy = new s3.CfnBucketPolicy(this, "BucketPolicy", {
bucket: bucketName,
policyDocument: {
Statement: [
{
Action: 's3:*',
Effect: 'Deny',
Principal: {
AWS: '*',
},
Resource: [
accessLogsBucket.bucketArn,
`${accessLogsBucket.bucketArn}/*`
],
},
],
Version: '2012-10-17',
},
});

// 'serverAccessLogsBucket' will create a new L2 bucket policy
// to allow log delivery and overwrite the L1 bucket policy.
const bucket = new s3.Bucket(this, 'MyBucket', {
serverAccessLogsBucket: accessLogsBucket,
serverAccessLogsPrefix: 'logs',
});
```

The above example uses the L2 Bucket Construct with the L1 CfnBucketPolicy Construct. However,
when `serverAccessLogsBucket` is set, a new L2 Bucket Policy resource will be created
which overwrites the permissions defined in the L1 Bucket Policy causing unintended
behaviours.

As noted above, we highly discourage the mixed usage of L1 and L2 Constructs. The recommended
approach would to define the bucket policy using `addToResourcePolicy` method.

```ts
const accessLogsBucket = new s3.Bucket(this, 'AccessLogsBucket', {
objectOwnership: s3.ObjectOwnership.BUCKET_OWNER_ENFORCED,
});

accessLogsBucket.addToResourcePolicy(
new iam.PolicyStatement({
actions: ['s3:*'],
resources: [accessLogsBucket.bucketArn, accessLogsBucket.arnForObjects('*')],
principals: [new iam.AnyPrincipal()],
})
)

const bucket = new s3.Bucket(this, 'MyBucket', {
serverAccessLogsBucket: accessLogsBucket,
serverAccessLogsPrefix: 'logs',
});
```

Alternatively, users can use the L2 Bucket Policy Construct
`BucketPolicy.fromCfnBucketPolicy` to wrap around `CfnBucketPolicy` Construct. This will allow the subsequent bucket policy generated by `serverAccessLogsBucket` usage to append to the existing bucket policy instead of overwriting.

```ts
const bucketName = "my-favorite-bucket-name";
const accessLogsBucket = new s3.Bucket(this, 'AccessLogsBucket', {
objectOwnership: s3.ObjectOwnership.BUCKET_OWNER_ENFORCED,
bucketName,
});

const bucketPolicy = new s3.CfnBucketPolicy(this, "BucketPolicy", {
bucket: bucketName,
policyDocument: {
Statement: [
{
Action: 's3:*',
Effect: 'Deny',
Principal: {
AWS: '*',
},
Resource: [
accessLogsBucket.bucketArn,
`${accessLogsBucket.bucketArn}/*`
],
},
],
Version: '2012-10-17',
},
});

// Wrap L1 Construct with L2 Bucket Policy Construct. Subsequent
// generated bucket policy to allow access log delivery would append
// to the current policy.
s3.BucketPolicy.fromCfnBucketPolicy(bucketPolicy);

const bucket = new s3.Bucket(this, 'MyBucket', {
serverAccessLogsBucket: accessLogsBucket,
serverAccessLogsPrefix: 'logs',
});
```

## S3 Inventory

An [inventory](https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-inventory.html) contains a list of the objects in the source bucket and metadata for each object. The inventory lists are stored in the destination bucket as a CSV file compressed with GZIP, as an Apache optimized row columnar (ORC) file compressed with ZLIB, or as an Apache Parquet (Parquet) file compressed with Snappy.
Expand Down
Loading