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): use bucket policy instead of ACL for logging access control #20898

Closed
wants to merge 3 commits into from

Conversation

otaviomacedo
Copy link
Contributor

@otaviomacedo otaviomacedo commented Jun 28, 2022

As of December 2021 AWS recommends using bucket policies instead of ACLs for logging access control.

In addition to adding the bucket policy, this change also sets the object ownership to BUCKET_OWNER_ENFORCED, effectively disabling ACLs.

Fixes #19603.


All Submissions:

Adding new Unconventional Dependencies:

  • This PR adds new unconventional dependencies following the process described here

New Features

  • Have you added the new feature to an integration test?
    • Did you use yarn integ to deploy the infrastructure and generate the snapshot (i.e. yarn integ without --dry-run)?

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

@gitpod-io
Copy link

gitpod-io bot commented Jun 28, 2022

@github-actions github-actions bot added the p2 label Jun 28, 2022
@aws-cdk-automation aws-cdk-automation requested a review from a team June 28, 2022 09:44
@mergify mergify bot added the contribution/core This is a PR that came from AWS. label Jun 28, 2022
Copy link
Contributor

@corymhall corymhall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the policy need to be added to the source bucket if the access logs are configured to be sent to the source bucket?

this.addToResourcePolicy(new PolicyStatement({
principals: [new ServicePrincipal('logging.s3.amazonaws.com')],
actions: ['s3:PutObject'],
conditions: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this also include the condition:

"StringEquals": {
                    "aws:SourceAccount": "SOURCE-ACCOUNT-ID"
                }

https://docs.aws.amazon.com/AmazonS3/latest/userguide/enable-server-access-logging.html

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

Does the policy need to be added to the source bucket if the access logs are configured to be sent to the source bucket?

I think so. Otherwise, the service principal wouldn't have permission to write the logs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is being done today.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if I understand... today the LOG_DELIVERY_WRITE ACL is applied to the target bucket. If it happens that the source and target are the same, then the ACL is applied to the source bucket. By the same logic, this change applies the policy to the source bucket if source and target are the same.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a comment that tries to clarify.

@corymhall
Copy link
Contributor

@otaviomacedo another thing I just thought of is I wonder if customers might be using a centralized access log bucket. Not all access logs support the BUCKET_OWNER_ENFORCED ACL (for example CloudFront)

@github-actions github-actions bot added effort/medium Medium work item – several days of effort feature-request A feature should be added or improved. p1 and removed p2 labels Jun 29, 2022
@otaviomacedo
Copy link
Contributor Author

@otaviomacedo another thing I just thought of is I wonder if customers might be using a centralized access log bucket. Not all access logs support the BUCKET_OWNER_ENFORCED ACL (for example CloudFront)

In that case, the logging bucket is created without setting the objectOwnership or the serverAccessLogsBucket properties:

private renderLogging(props: DistributionProps): CfnDistribution.LoggingProperty | undefined {
if (!props.enableLogging && !props.logBucket) { return undefined; }
if (props.enableLogging === false && props.logBucket) {
throw new Error('Explicitly disabled logging but provided a logging bucket.');
}
const bucket = props.logBucket ?? new s3.Bucket(this, 'LoggingBucket', {
encryption: s3.BucketEncryption.S3_MANAGED,
});
return {
bucket: bucket.bucketRegionalDomainName,
includeCookies: props.logIncludesCookies,
prefix: props.logFilePrefix,
};
}

2 similar comments
@otaviomacedo
Copy link
Contributor Author

@otaviomacedo another thing I just thought of is I wonder if customers might be using a centralized access log bucket. Not all access logs support the BUCKET_OWNER_ENFORCED ACL (for example CloudFront)

In that case, the logging bucket is created without setting the objectOwnership or the serverAccessLogsBucket properties:

private renderLogging(props: DistributionProps): CfnDistribution.LoggingProperty | undefined {
if (!props.enableLogging && !props.logBucket) { return undefined; }
if (props.enableLogging === false && props.logBucket) {
throw new Error('Explicitly disabled logging but provided a logging bucket.');
}
const bucket = props.logBucket ?? new s3.Bucket(this, 'LoggingBucket', {
encryption: s3.BucketEncryption.S3_MANAGED,
});
return {
bucket: bucket.bucketRegionalDomainName,
includeCookies: props.logIncludesCookies,
prefix: props.logFilePrefix,
};
}

@otaviomacedo
Copy link
Contributor Author

@otaviomacedo another thing I just thought of is I wonder if customers might be using a centralized access log bucket. Not all access logs support the BUCKET_OWNER_ENFORCED ACL (for example CloudFront)

In that case, the logging bucket is created without setting the objectOwnership or the serverAccessLogsBucket properties:

private renderLogging(props: DistributionProps): CfnDistribution.LoggingProperty | undefined {
if (!props.enableLogging && !props.logBucket) { return undefined; }
if (props.enableLogging === false && props.logBucket) {
throw new Error('Explicitly disabled logging but provided a logging bucket.');
}
const bucket = props.logBucket ?? new s3.Bucket(this, 'LoggingBucket', {
encryption: s3.BucketEncryption.S3_MANAGED,
});
return {
bucket: bucket.bucketRegionalDomainName,
includeCookies: props.logIncludesCookies,
prefix: props.logFilePrefix,
};
}

@corymhall
Copy link
Contributor

In that case, the logging bucket is created without setting the objectOwnership or the serverAccessLogsBucket properties:

I'm more meaning if you did something like this

const centralLoggingBucket = new s3.Bucket(this, 'Logging');

new s3.Bucket(this, 'SomeOtherBucket', {
  serverAccessLogsBucket: centralLoggingBucket,
  serverAccessLogsPrefix: 'someotherbucket',
});

new cloudfront.Distribution(this, 'Distro', {
  logBucket: centralLoggingBucket,
  logFilePrefix: 'cloudfront',
});

@otaviomacedo
Copy link
Contributor Author

@corymhall I see. Re-reading the documentation, I realised that it strongly suggests the use of BUCKET_OWNER_ENFORCED for object ownership, but it's not mandatory. Removed.

@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildv2Project1C6BFA3F-wQm2hXv2jqQv
  • Commit ID: fab78e2
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository


// Enforce AWS Foundational Security Best Practice
if (props.enforceSSL) {
this.enforceSSLStatement();
}

if (props.serverAccessLogsBucket instanceof Bucket) {
props.serverAccessLogsBucket.allowLogDelivery();
props.serverAccessLogsBucket.allowLogDelivery(this, Stack.of(this).account, props.serverAccessLogsPrefix);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where we setup the log delivery policy/acl, but it only gets done if the user passes in a bucket to serverAccessLogsBucket. If a user provides serverAccessLogsPrefix but does not provide serverAccessLogsBucket, then access logs are sent to the source bucket. Does it need to be something like

if (props.serverAccessLogsBucket instanceof Bucket) {
  ...
} else if (props.serverAcessLogsPrefix && !props.serverAccessLogsBucket) {
  this.allowLogDelivery(this, Stack.of(this).account, props.serverAccessLogsPrefix);
}

It's not being done today so it could be a bug or it could be that you don't need to grant access to allow access logs to be written to the same bucket?


this.accessControl = BucketAccessControl.LOG_DELIVERY_WRITE;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be added back then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think so, which means that this change adds no value. Closing the PR until CloudFront (and possibly other services) catches up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution/core This is a PR that came from AWS. effort/medium Medium work item – several days of effort feature-request A feature should be added or improved. p1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

(aws_s3): serverAccessLogsBucket should use Bucket Policy instead of Bucket ACL
3 participants