Skip to content

Commit d015cc1

Browse files
authored
feat(Issue#791) - CDK Sample: Event Bridge mesh with CDK (#1153)
* initial commit * created single producer and consumer solution * added images and updated README * added images in README.md * added background in README.md * added appName for all resources * moved to single-consumer directory * added multiple consumers solution * clean up un-used files * remove test dir * added instructions of how to deploy * added single-consumer solution in python * added multiple-consumer solution in python * added optional cdk bootsrap step for multiple consumer deployment && upgrade cdk.json accounts ids * added design diagram in python * updated README.md * Fix: remove unused test command * Fix: remove unused test command * Doc: update shell language for code blocks * Update README.md
1 parent a66e398 commit d015cc1

File tree

22 files changed

+793
-0
lines changed

22 files changed

+793
-0
lines changed

python/eventbridge-mesh/README.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# CDK Python Sample: Event Bridge mesh with CDK
2+
3+
![Language-Support: Stable](https://img.shields.io/badge/language--support-stable-success.svg?style=for-the-badge)
4+
5+
## Description:
6+
A CDK way to set up a Event Bridge Mesh(Cross-Account), where you relay the messages from one Event Bridge in a producer account to another Event Bridge in a consumer account
7+
8+
## Backgroud:
9+
This is a CDK application that implements cross-account event routing using Amazon EventBridge. It's designed for enterprise scenarios where:
10+
11+
- Teams work in separate AWS accounts (producer and consumer)
12+
- Consumer teams need autonomy to manage their event processing
13+
- Event routing changes shouldn't require coordination with producer teams
14+
15+
## Solution:
16+
17+
### Single consumer
18+
![architecture](./images/single-consumer.png)
19+
20+
### Multiple consumers
21+
![architecture](./images/multi-consumers.png)
22+
23+
24+
## Instructions
25+
26+
### CDK bootstrapping
27+
To deploy the stacks in different accounts, you need to bootstrap the CDKToolkit with trust flag. Assuming you will run `cdk deploy` command from account ID: `123456789012`, and deploys producer stack to account ID: `111111111111`, and consumer stack to account ID: `222222222222`
28+
29+
1. In account: `111111111111`, run the below command:
30+
```
31+
cdk bootstrap aws://111111111111/us-east-1 \
32+
--trust 123456789012 \
33+
--cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess
34+
```
35+
36+
2. In account: `222222222222`, run the below command:
37+
```
38+
cdk bootstrap aws://222222222222/us-east-1 \
39+
--trust 123456789012 \
40+
--cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess
41+
```
42+
43+
3. (Optional: Only do this step, when you deploys multiple consumers solution) In account: `333333333333`, run the below command:
44+
```
45+
cdk bootstrap aws://333333333333/us-east-1 \
46+
--trust 123456789012 \
47+
--cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess
48+
```
49+
50+
### Deploy Single consumer solution:
51+
1. Run: `cd single-consumer`
52+
2. Change the values of `producerAccountId` and `consumerAccountId` in `cdk.json`
53+
3. Install and configure the CDK: https://docs.aws.amazon.com/CDK/latest/userguide/install_config.html
54+
4. Make sure you use a role or user has proper permission in account ID: `123456789012`, and run below commands:
55+
```shell
56+
npm run build
57+
58+
cdk ls
59+
60+
cdk synth
61+
62+
cdk deploy --all
63+
```
64+
65+
### Deploy Multiple consumers solution:
66+
1. Run: `cd multiple-consumer`
67+
2. Change the values of `producerAccountId`, `consumer1AccountId`, and `consumer2AccountId` in `cdk.json`
68+
3. Install and configure the CDK: https://docs.aws.amazon.com/CDK/latest/userguide/install_config.html
69+
4. Make sure you use a role or user has proper permission in account ID: `123456789012`, and run below commands:
70+
```shell
71+
npm run build
72+
73+
cdk ls
74+
75+
cdk synth
76+
77+
cdk deploy --all
78+
```
Loading
Loading
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#!/usr/bin/env python3
2+
from aws_cdk import (
3+
aws_events as events,
4+
aws_events_targets as targets,
5+
aws_logs as logs,
6+
aws_iam as iam,
7+
App, Stack, Environment
8+
)
9+
from constructs import Construct
10+
11+
class ProducerStack(Stack):
12+
def __init__(self, scope: Construct, id: str, *,
13+
app_name: str,
14+
consumer_accounts: list[str],
15+
**kwargs) -> None:
16+
super().__init__(scope, id, **kwargs)
17+
18+
# Create the EventBus
19+
producer_event_bus = events.EventBus(
20+
self, f"{app_name}-producer-event-bus"
21+
)
22+
23+
# Create rules for each consumer account
24+
for index, consumer_account_id in enumerate(consumer_accounts):
25+
# Create rule to forward events to consumer account
26+
rule = events.Rule(
27+
self,
28+
f"{app_name}-forward-to-consumer-{index + 1}-rule",
29+
event_bus=producer_event_bus,
30+
event_pattern=events.EventPattern(
31+
source=['com.myapp.events']
32+
)
33+
)
34+
35+
# Add target to forward to consumer account's event bus
36+
consumer_bus = events.EventBus.from_event_bus_arn(
37+
self,
38+
f"{app_name}-consumer-{index + 1}-event-bus",
39+
f"arn:aws:events:{Stack.of(self).region}:{consumer_account_id}:event-bus/default"
40+
)
41+
rule.add_target(targets.EventBus(consumer_bus))
42+
43+
44+
class ConsumerStack(Stack):
45+
def __init__(self, scope: Construct, id: str, *,
46+
app_name: str,
47+
consumer_name: str,
48+
producer_account_id: str,
49+
**kwargs) -> None:
50+
super().__init__(scope, id, **kwargs)
51+
52+
# Create or reference the consumer event bus
53+
consumer_event_bus = events.EventBus(
54+
self, f"{app_name}-{consumer_name}-event-bus"
55+
)
56+
57+
# Add policy to allow producer account to put events
58+
consumer_event_bus.add_to_resource_policy(iam.PolicyStatement(
59+
sid="allowProducerAccount",
60+
effect=iam.Effect.ALLOW,
61+
principals=[iam.AccountPrincipal(producer_account_id)],
62+
actions=["events:PutEvents"],
63+
resources=[consumer_event_bus.event_bus_arn]
64+
))
65+
66+
# Create consumer rules
67+
consumer_rule = events.Rule(
68+
self,
69+
f"{app_name}-{consumer_name}-rule",
70+
event_bus=consumer_event_bus,
71+
event_pattern=events.EventPattern(
72+
source=['com.myapp.events'],
73+
detail_type=['specific-event-type']
74+
)
75+
)
76+
77+
# Add target (e.g., CloudWatch)
78+
log_group = logs.LogGroup(
79+
self, f"{app_name}-{consumer_name}-logs"
80+
)
81+
consumer_rule.add_target(targets.CloudWatchLogGroup(log_group))
82+
83+
84+
app = App()
85+
86+
# Get context values
87+
app_name = app.node.try_get_context("appName")
88+
region = app.node.try_get_context("region")
89+
producer_account_id = app.node.try_get_context("producerAccountId")
90+
consumer1_account_id = app.node.try_get_context("consumer1AccountId")
91+
consumer2_account_id = app.node.try_get_context("consumer2AccountId")
92+
93+
# Create producer stack
94+
producer_stack = ProducerStack(
95+
app, f"{app_name}-producer-stack",
96+
app_name=app_name,
97+
consumer_accounts=[consumer1_account_id, consumer2_account_id],
98+
env=Environment(
99+
account=producer_account_id,
100+
region=region
101+
)
102+
)
103+
104+
# Create consumer 1 stack
105+
consumer1_stack = ConsumerStack(
106+
app, f"{app_name}-consumer1-stack",
107+
app_name=app_name,
108+
consumer_name="consumer1",
109+
producer_account_id=producer_account_id,
110+
env=Environment(
111+
account=consumer1_account_id,
112+
region=region
113+
)
114+
)
115+
116+
# Create consumer 2 stack
117+
consumer2_stack = ConsumerStack(
118+
app, f"{app_name}-consumer2-stack",
119+
app_name=app_name,
120+
consumer_name="consumer2",
121+
producer_account_id=producer_account_id,
122+
env=Environment(
123+
account=consumer2_account_id,
124+
region=region
125+
)
126+
)
127+
128+
app.synth()
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"app": "python3 app.py",
3+
"context": {
4+
"appName": "eventbridge-mesh",
5+
"region": "us-east-1",
6+
"producerAccountId": "111111111111",
7+
"consumer1AccountId": "222222222222",
8+
"consumer2AccountId": "333333333333"
9+
}
10+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
aws-cdk-lib==2.186.0
2+
constructs>=10.0.0,<11.0.0
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#!/usr/bin/env python3
2+
from aws_cdk import (
3+
aws_events as events,
4+
aws_events_targets as targets,
5+
aws_logs as logs,
6+
aws_iam as iam,
7+
App, Stack, Environment
8+
)
9+
from constructs import Construct
10+
11+
class ProducerStack(Stack):
12+
def __init__(self, scope: Construct, id: str, *,
13+
app_name: str,
14+
consumer_account_id: str,
15+
**kwargs) -> None:
16+
super().__init__(scope, id, **kwargs)
17+
18+
# Create the EventBus
19+
producer_event_bus = events.EventBus(
20+
self, f"{app_name}-producer-event-bus"
21+
)
22+
23+
# Create rule to forward events to consumer account
24+
rule = events.Rule(
25+
self, f"{app_name}-forward-to-consumer-rule",
26+
event_bus=producer_event_bus,
27+
event_pattern=events.EventPattern(
28+
source=['com.myapp.events']
29+
)
30+
)
31+
32+
# Add target to forward to consumer account's event bus
33+
consumer_bus = events.EventBus.from_event_bus_arn(
34+
self,
35+
'ConsumerEventBus',
36+
f"arn:aws:events:{Stack.of(self).region}:{consumer_account_id}:event-bus/default"
37+
)
38+
rule.add_target(targets.EventBus(consumer_bus))
39+
40+
# Optional: Add CloudWatch target for monitoring
41+
log_group = logs.LogGroup(self, f"{app_name}-producer-logs")
42+
rule.add_target(targets.CloudWatchLogGroup(log_group))
43+
44+
45+
class ConsumerStack(Stack):
46+
def __init__(self, scope: Construct, id: str, *,
47+
app_name: str,
48+
producer_account_id: str,
49+
**kwargs) -> None:
50+
super().__init__(scope, id, **kwargs)
51+
52+
# Create or reference the consumer event bus
53+
consumer_event_bus = events.EventBus(
54+
self, f"{app_name}-consumer-event-bus"
55+
)
56+
57+
# Add policy to allow producer account to put events
58+
consumer_event_bus.add_to_resource_policy(iam.PolicyStatement(
59+
sid="allowProducerAccount",
60+
effect=iam.Effect.ALLOW,
61+
principals=[iam.AccountPrincipal(producer_account_id)],
62+
actions=["events:PutEvents"],
63+
resources=[consumer_event_bus.event_bus_arn]
64+
))
65+
66+
# Create consumer rules
67+
consumer_rule = events.Rule(
68+
self, f"{app_name}-consumer-rule",
69+
event_bus=consumer_event_bus,
70+
event_pattern=events.EventPattern(
71+
source=['com.myapp.events'],
72+
detail_type=['specific-event-type']
73+
)
74+
)
75+
76+
# Add target (e.g., CloudWatch)
77+
log_group = logs.LogGroup(self, f"{app_name}-consumer-logs")
78+
consumer_rule.add_target(targets.CloudWatchLogGroup(log_group))
79+
80+
81+
app = App()
82+
83+
# Get context values
84+
app_name = app.node.try_get_context("appName")
85+
region = app.node.try_get_context("region")
86+
producer_account_id = app.node.try_get_context("producerAccountId")
87+
consumer_account_id = app.node.try_get_context("consumer1AccountId")
88+
89+
# Create producer stack
90+
producer_stack = ProducerStack(
91+
app, f"{app_name}-producer-stack",
92+
app_name=app_name,
93+
consumer_account_id=consumer_account_id,
94+
env=Environment(
95+
account=producer_account_id,
96+
region=region
97+
)
98+
)
99+
100+
# Create consumer stack
101+
consumer_stack = ConsumerStack(
102+
app, f"{app_name}-consumer-stack",
103+
app_name=app_name,
104+
producer_account_id=producer_account_id,
105+
env=Environment(
106+
account=consumer_account_id,
107+
region=region
108+
)
109+
)
110+
111+
app.synth()
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"app": "python3 app.py",
3+
"context": {
4+
"appName": "eventbridge-mesh",
5+
"region": "us-east-1",
6+
"producerAccountId": "111111111111",
7+
"consumer1AccountId": "222222222222"
8+
}
9+
10+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
aws-cdk-lib==2.186.0
2+
constructs>=10.0.0,<11.0.0
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
*.js
2+
!jest.config.js
3+
*.d.ts
4+
node_modules
5+
6+
# CDK asset staging directory
7+
.cdk.staging
8+
cdk.out
9+
10+
package-lock.json
11+

0 commit comments

Comments
 (0)