Connecting Accounts with AWS EventBridge
Creating an Event-First System Topology of Autonomous Subsystems
In a previous post, here, I discussed how I use AWS EventBridge and AWS Kinesis together to create an EventHub. In this post, I will cover how I use AWS EventBridge to connect the event hubs in different AWS accounts to create an event-first system topology of autonomous subsystems.
Event-First System Topology
The overarching theme of all my posts (such as here, here, here & here) is the creation of autonomous services, with fortified boundaries, that have the resilience to continue operating even when related upstream and downstream services are failing. We fortify their boundaries with bulkheads by performing all inter-service communication with asynchronous events. Services produce events as their state changes and they consume upstream events and cache needed data, so that they never have to ask another service for information.
As a system grows larger it is necessary to carry this theme to the next level and create autonomous subsystems. Each autonomous subsystem is a collection of closely related autonomous services and maintains its own event hub. We can then create arbitrarily complex systems, by combining these subsystems in a simple fractal pattern, without degenerating into a microservices death star.
Autonomous subsystems are fortified with two kinds of bulkheads: cloud accounts and external domain events.
Each subsystem lives in a separate cloud account, because an account forms a natural bulkhead that limits the blast radius of mistakes made within it.
Within a subsystem the autonomous services exchange internal domain events. The backwards compatibility of these event types is only guaranteed within the subsystem.
Each subsystems produces a set of external domain events that contain the information they are willing to share and support. This hides the internal dirty laundry of a subsystem and provides stronger backward compatibility guarantees to downstream subsystems. [The robustness principle is employed for all event types when changes are needed, as discussed here.]
The External Service Gateway (ESG) pattern is employed to perform the necessary transformations and AWS EventBridge rules are used to forward the external domain events to the event hubs of downstream subsystems. Downstream subsystems route the incoming events to an ingress stream where ESG services can form an anti-corruption layer that transforms the events into the internal domain event types of the specific subsystem.
The following is a deeper dive into the details.
Upstream Autonomous Subsystem
The following diagram depicts the egress flow of external domain events from an upstream subsystem (i.e. account).
- Autonomous services produce internal domain events to their account’s event hub.
- One or more ESG services consume the internal domain events and transform them into external domain events that contain the information that the subsystem is willing to share with other subsystems.
- One or more egress rules are defined to relay the external domain events to downstream event hubs.
Here is an egress rule that routes all external domain events to one or more downstream accounts. The ESG services set the source
field to external
to simplify the routing rules. Add a target for each downstream bus.
EgressEventRule:
Type: AWS::Events::Rule
Properties:
EventBusName:
Ref: Bus
EventPattern:
source:
- external
State: ENABLED
Targets:
- Id: EgressY
Arn: arn:aws:events:us-east-1:123456789012:event-bus/${opt:stage}-event-hub-bus
RoleArn:
Fn::GetAtt: [ BusRole, Arn ]
Here is an example of a security policy that grants the upstream account permission to route events to one or more downstream accounts. Add a resource arn for each downstream bus.
BusRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: events.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: egress
PolicyDocument:
Statement:
- Effect: Allow
Action:
- events:PutEvents
Resource:
- arn:aws:events:us-east-1:123456789012:event-bus/${opt:stage}-event-hub-bus
Downstream Autonomous Subsystem
The following diagram depicts the ingress flow of external domain events to a downstream subsystem (i.e. account).
- A downstream event hub receives events from an upstream subsystem (i.e. account)
- The external domain events are routed to an ingress stream to isolate them from internal domain event flows.
- One or more ESG services consume the external domain events and transform them into internal domain events for further processing.
- The bus routes the internal domain events to the internal streams per usual.
Note: The ingress stream is optional. If the volume is low then it may not be necessary. I often start with out it and add it as needed. I sometimes exclude it in lower environments to cut cost.
Permissions must be configured in both accounts to establish an agreement of trust before the events can be sent and received. Here is an example of an event bus policy that grants an upstream account X permission to route events to this account Y. Create a policy for each upstream account.
EventBusPolicyForSubsystemX:
Type: AWS::Events::EventBusPolicy
Properties:
EventBusName:
Ref: Bus
Action: events:PutEvents
Principal: 123456789012
StatementId: SubsystemX
Here is a rule that routes all incoming external domain events to the ingress stream.
IngressStreamEventRule:
Type: AWS::Events::Rule
Properties:
EventBusName:
Ref: Bus
EventPattern:
source:
- external
State: ENABLED
Targets:
- Id: IngressStream
Arn:
Fn::GetAtt: [ IngressStream, Arn ]
RoleArn:
Fn::GetAtt: [ BusRole, Arn ]
KinesisParameters:
PartitionKeyPath: $.detail.partitionKey
InputPath: $.detail
Recap
Autonomous subsystems enable autonomous organizations/teams to accelerate their pace of innovation by minimizing and controlling the coordination and communication that is necessary between upstream and downstream organizations/teams. Using separate accounts and external domain events as a bulkhead gives each organization their own isolated environment to experiment in. AWS EventBridge provides the glue to connect these autonomous subsystems into an arbitrarily complex event-first topology, without devolving into a microservices death star.
A full event-hub kick-start service is available here.
For more thoughts on serverless and cloud-native checkout the other posts in this series and my books: Software Architecture Patterns for Serverless Systems, Cloud Native Development Patterns and Best Practices and JavaScript Cloud Native Development Cookbook.