Skip to content

Commit

Permalink
feat(events): EventBus.grantPutEventsTo method for granular grants (#…
Browse files Browse the repository at this point in the history
…13429)

Right now EventBus has a static method `grantPutEvents()` which grants PutEvents to all EventBridge buses in the account.

Adding a `grantPutEventsTo()` method to the IEventBus interface that grants PutEvents to the specific event bus.
We are also deprecating `grantPutEvents()` in favor to `grantAllPutEvents()` which has the same behavior.

Closes #11228.

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
DaWyz authored Mar 9, 2021
1 parent f5a6647 commit 122a232
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 60 deletions.
14 changes: 14 additions & 0 deletions packages/@aws-cdk/aws-events/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,17 @@ bus.archive('MyArchive', {
retention: cdk.Duration.days(365),
});
```

## Granting PutEvents to an existing EventBus

To import an existing EventBus into your CDK application, use `EventBus.fromEventBusArn` or `EventBus.fromEventBusAttributes`
factory method.

Then, you can use the `grantPutEventsTo` method to grant `event:PutEvents` to the eventBus.

```ts
const eventBus = EventBus.fromEventBusArn(this, 'ImportedEventBus', 'arn:aws:events:us-east-1:111111111:event-bus/my-event-bus');

// now you can just call methods on the eventbus
eventBus.grantPutEventsTo(lambdaFunction);
```
31 changes: 31 additions & 0 deletions packages/@aws-cdk/aws-events/lib/event-bus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ export interface IEventBus extends IResource {
* @param props Properties of the archive
*/
archive(id: string, props: BaseArchiveProps): Archive;

/**
* Grants an IAM Principal to send custom events to the eventBus
* so that they can be matched to rules.
*
* @param grantee The principal (no-op if undefined)
*/
grantPutEventsTo(grantee: iam.IGrantable): iam.Grant;
}

/**
Expand Down Expand Up @@ -137,6 +145,14 @@ abstract class EventBusBase extends Resource implements IEventBus {
archiveName: props.archiveName,
});
}

public grantPutEventsTo(grantee: iam.IGrantable): iam.Grant {
return iam.Grant.addToPrincipal({
grantee,
actions: ['events:PutEvents'],
resourceArns: [this.eventBusArn],
});
}
}

/**
Expand Down Expand Up @@ -177,6 +193,7 @@ export class EventBus extends EventBusBase {
* so that they can be matched to rules.
*
* @param grantee The principal (no-op if undefined)
* @deprecated use grantAllPutEvents instead
*/
public static grantPutEvents(grantee: iam.IGrantable): iam.Grant {
// It's currently not possible to restrict PutEvents to specific resources.
Expand All @@ -188,6 +205,20 @@ export class EventBus extends EventBusBase {
});
}

/**
* Permits an IAM Principal to send custom events to EventBridge
* so that they can be matched to rules.
*
* @param grantee The principal (no-op if undefined)
*/
public static grantAllPutEvents(grantee: iam.IGrantable): iam.Grant {
return iam.Grant.addToPrincipal({
grantee,
actions: ['events:PutEvents'],
resourceArns: ['*'],
});
}

private static eventBusProps(defaultEventBusName: string, props?: EventBusProps) {
if (props) {
const { eventBusName, eventSourceName } = props;
Expand Down
70 changes: 70 additions & 0 deletions packages/@aws-cdk/aws-events/test/test.event-bus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,76 @@ export = {

test.done();
},

'can grant PutEvents using grantAllPutEvents'(test: Test) {
// GIVEN
const stack = new Stack();
const role = new iam.Role(stack, 'Role', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});

// WHEN
EventBus.grantAllPutEvents(role);

// THEN
expect(stack).to(haveResource('AWS::IAM::Policy', {
PolicyDocument: {
Statement: [
{
Action: 'events:PutEvents',
Effect: 'Allow',
Resource: '*',
},
],
Version: '2012-10-17',
},
Roles: [
{
Ref: 'Role1ABCC5F0',
},
],
}));

test.done();
},
'can grant PutEvents to a specific event bus'(test: Test) {
// GIVEN
const stack = new Stack();
const role = new iam.Role(stack, 'Role', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});

const eventBus = new EventBus(stack, 'EventBus');

// WHEN
eventBus.grantPutEventsTo(role);

// THEN
expect(stack).to(haveResource('AWS::IAM::Policy', {
PolicyDocument: {
Statement: [
{
Action: 'events:PutEvents',
Effect: 'Allow',
Resource: {
'Fn::GetAtt': [
'EventBus7B8748AA',
'Arn',
],
},
},
],
Version: '2012-10-17',
},
Roles: [
{
Ref: 'Role1ABCC5F0',
},
],
}));

test.done();
},
'can archive events'(test: Test) {
// GIVEN
const stack = new Stack();
Expand Down
24 changes: 17 additions & 7 deletions packages/@aws-cdk/aws-lambda-destinations/lib/event-bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,25 @@ export class EventBridgeDestination implements lambda.IDestination {
* Returns a destination configuration
*/
public bind(_scope: Construct, fn: lambda.IFunction, _options?: lambda.DestinationOptions): lambda.DestinationConfig {
// deduplicated automatically
events.EventBus.grantPutEvents(fn); // Cannot restrict to a specific resource
if (this.eventBus) {
this.eventBus.grantPutEventsTo(fn);

return {
destination: this.eventBus.eventBusArn,
};
}

const existingDefaultEventBus = _scope.node.tryFindChild('DefaultEventBus');
let eventBus = (existingDefaultEventBus as events.EventBus) || events.EventBus.fromEventBusArn(_scope, 'DefaultEventBus', Stack.of(fn).formatArn({
service: 'events',
resource: 'event-bus',
resourceName: 'default',
}));

eventBus.grantPutEventsTo(fn);

return {
destination: this.eventBus && this.eventBus.eventBusArn || Stack.of(fn).formatArn({
service: 'events',
resource: 'event-bus',
resourceName: 'default',
}),
destination: eventBus.eventBusArn,
};
}
}
75 changes: 25 additions & 50 deletions packages/@aws-cdk/aws-lambda-destinations/test/destinations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,56 +47,12 @@ test('event bus as destination', () => {
{
Action: 'events:PutEvents',
Effect: 'Allow',
Resource: '*',
},
],
Version: '2012-10-17',
},
});
});

test('event bus as destination defaults to default event bus', () => {
// WHEN
new lambda.Function(stack, 'Function', {
...lambdaProps,
onSuccess: new destinations.EventBridgeDestination(),
});

// THEN
expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', {
DestinationConfig: {
OnSuccess: {
Destination: {
'Fn::Join': [
'',
[
'arn:',
{
Ref: 'AWS::Partition',
},
':events:',
{
Ref: 'AWS::Region',
},
':',
{
Ref: 'AWS::AccountId',
},
':event-bus/default',
Resource: {
'Fn::GetAtt': [
'EventBus7B8748AA',
'Arn',
],
],
},
},
},
});

expect(stack).toHaveResource('AWS::IAM::Policy', {
PolicyDocument: {
Statement: [
{
Action: 'events:PutEvents',
Effect: 'Allow',
Resource: '*',
},
},
],
Version: '2012-10-17',
Expand Down Expand Up @@ -215,7 +171,26 @@ test('lambda payload as destination', () => {
{
Action: 'events:PutEvents',
Effect: 'Allow',
Resource: '*',
Resource: {
'Fn::Join': [
'',
[
'arn:',
{
Ref: 'AWS::Partition',
},
':events:',
{
Ref: 'AWS::Region',
},
':',
{
Ref: 'AWS::AccountId',
},
':event-bus/default',
],
],
},
},
],
Version: '2012-10-17',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,26 @@
{
"Action": "events:PutEvents",
"Effect": "Allow",
"Resource": "*"
"Resource": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":events:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":event-bus/default"
]
]
}
},
{
"Action": "lambda:InvokeFunction",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,26 @@
{
"Action": "events:PutEvents",
"Effect": "Allow",
"Resource": "*"
"Resource": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":events:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":event-bus/default"
]
]
}
}
],
"Version": "2012-10-17"
Expand Down Expand Up @@ -289,7 +308,26 @@
{
"Action": "events:PutEvents",
"Effect": "Allow",
"Resource": "*"
"Resource": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":events:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":event-bus/default"
]
]
}
}
],
"Version": "2012-10-17"
Expand Down

0 comments on commit 122a232

Please sign in to comment.