Skip to content

Commit

Permalink
Cross account bucket access
Browse files Browse the repository at this point in the history
  • Loading branch information
jonife committed Feb 9, 2024
1 parent 2e4067b commit d381a90
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 8 deletions.
25 changes: 25 additions & 0 deletions packages/aws-cdk-lib/aws-lambda-event-sources/test/s3.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,31 @@ describe('S3EventSource', () => {
},
],
},
test('Cross account buckect access', () => {
// GIVEN
const app = new cdk.App();
const stack = new cdk.Stack(app, 'stack');
const fn = new TestFunction(stack, 'Fn');

let accountB = '1234567';
//WHEN
const foreignBucket =
s3.Bucket.fromBucketAttributes(stack, 'ImportedBucket', {
bucketArn: 'arn:aws:s3:::some-bucket-not-in-this-account',
// The account the bucket really lives in
account: accountB,
});

// This will generate the IAM bindings
fn.addEventSource(new sources.S3EventSource(foreignBucket as s3.Bucket,
{ events: [s3.EventType.OBJECT_CREATED] }));

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', {
'Principal': 's3.amazonaws.com',
'SourceAccount': '1234567',
'SourceArn': 'arn:aws:s3:::some-bucket-not-in-this-account',
});
});
});

2 changes: 1 addition & 1 deletion packages/aws-cdk-lib/aws-s3-notifications/lib/lambda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class LambdaDestination implements s3.IBucketNotificationDestination {

if (bucket.node.tryFindChild(permissionId) === undefined) {
this.fn.addPermission(permissionId, {
sourceAccount: Stack.of(bucket).account,
sourceAccount: bucket.account || Stack.of(bucket).account,
principal: new iam.ServicePrincipal('s3.amazonaws.com'),
sourceArn: bucket.bucketArn,
// Placing the permissions node in the same scope as the s3 bucket.
Expand Down
20 changes: 13 additions & 7 deletions packages/aws-cdk-lib/aws-s3/lib/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ export interface IBucket extends IResource {
*/
policy?: BucketPolicy;

/**
* The account bucket belongs to.
*/
readonly account?: string;

/**
* Adds a statement to the resource policy for a principal (i.e.
* account/role/service) to perform actions on this bucket and/or its
Expand Down Expand Up @@ -1754,6 +1759,7 @@ export class Bucket extends BucketBase {
public readonly bucketWebsiteNewUrlFormat = attrs.bucketWebsiteNewUrlFormat ?? false;
public readonly encryptionKey = attrs.encryptionKey;
public readonly isWebsite = attrs.isWebsite ?? false;
public readonly account = attrs.account;
public policy?: BucketPolicy = undefined;
protected autoCreatePolicy = false;
protected disallowPublicAccess = false;
Expand Down Expand Up @@ -1967,11 +1973,11 @@ export class Bucket extends BucketBase {

if (props.serverAccessLogsBucket instanceof Bucket) {
props.serverAccessLogsBucket.allowLogDelivery(this, props.serverAccessLogsPrefix);
// It is possible that `serverAccessLogsBucket` was specified but is some other `IBucket`
// that cannot have the ACLs or bucket policy applied. In that scenario, we should only
// setup log delivery permissions to `this` if a bucket was not specified at all, as documented.
// For example, we should not allow log delivery to `this` if given an imported bucket or
// another situation that causes `instanceof` to fail
// It is possible that `serverAccessLogsBucket` was specified but is some other `IBucket`
// that cannot have the ACLs or bucket policy applied. In that scenario, we should only
// setup log delivery permissions to `this` if a bucket was not specified at all, as documented.
// For example, we should not allow log delivery to `this` if given an imported bucket or
// another situation that causes `instanceof` to fail
} else if (!props.serverAccessLogsBucket && props.serverAccessLogsPrefix) {
this.allowLogDelivery(this, props.serverAccessLogsPrefix);
} else if (props.serverAccessLogsBucket) {
Expand Down Expand Up @@ -2225,7 +2231,7 @@ export class Bucket extends BucketBase {
function parseLifecycleRule(rule: LifecycleRule): CfnBucket.RuleProperty {
const enabled = rule.enabled ?? true;
if ((rule.expiredObjectDeleteMarker)
&& (rule.expiration || rule.expirationDate || self.parseTagFilters(rule.tagFilters))) {
&& (rule.expiration || rule.expirationDate || self.parseTagFilters(rule.tagFilters))) {
// ExpiredObjectDeleteMarker cannot be specified with ExpirationInDays, ExpirationDate, or TagFilters.
throw new Error('ExpiredObjectDeleteMarker cannot be specified with expiration, ExpirationDate, or TagFilters.');
}
Expand Down Expand Up @@ -2350,7 +2356,7 @@ export class Bucket extends BucketBase {
}

if (accessControlRequiresObjectOwnership && this.objectOwnership === ObjectOwnership.BUCKET_OWNER_ENFORCED) {
throw new Error (`objectOwnership must be set to "${ObjectOwnership.OBJECT_WRITER}" when accessControl is "${this.accessControl}"`);
throw new Error(`objectOwnership must be set to "${ObjectOwnership.OBJECT_WRITER}" when accessControl is "${this.accessControl}"`);
}

return {
Expand Down

0 comments on commit d381a90

Please sign in to comment.