AWS Certified CloudOps Engineer - Associate
EventBridge Fundamentals
Learn how EventBridge routes events: the event envelope, default and custom buses, the exact-match rules of event pattern evaluation, target permissions, and input transformation.
- Distinguish an event from a metric and explain which detection problems need each
- Identify the fields of the EventBridge event envelope and write an event pattern that matches them
- Explain how pattern matching evaluates arrays, leaf nodes, and absent fields
- Compare the default event bus, custom event buses, and partner event buses
- Choose between an IAM execution role and a resource-based policy for a target
- Reshape an event with the input transformer before it reaches a target
A CloudWatch alarm can reboot the one instance its dimensions point at. It cannot do this: when any instance tagged Environment=prod enters the stopped state, open a Systems Manager OpsItem, start a runbook that captures the console output, and notify the owning team. There is no number to threshold here. Nothing rises or falls. Something simply happened, once, to one resource, and several things need to occur because of it.
That is the gap EventBridge fills. It is the router that sits between things that happen in your account and the things that should run in response.
Events are facts; metrics are numbers
This boundary is worth getting right before anything else, because half of the diagnostic questions in this domain turn on it.
A metric is a time series of numbers. CPUUtilization on an instance is 4% at 09:00 and 71% at 09:01. Alarms exist to watch that series and decide when the numbers have gone bad for long enough to matter.
An event is a JSON document describing something that occurred, delivered once, near the moment it occurred. An instance changed state. An EBS snapshot finished. Someone called AuthorizeSecurityGroupIngress. An AWS Health notification opened for a Region. None of these are numbers, so no alarm can watch them.
Test yourself with a fast rule: if a human would describe the situation with a verb in the past tense, it is an event. If they would describe it with a number and a comparison, it is a metric.
The two connect, and the exam likes the connection. A CloudWatch alarm changing state is itself an event on the default bus (aws.cloudwatch, detail-type CloudWatch Alarm State Change). So the answer to "my alarm needs to trigger a five-step repair" is almost always: keep the alarm, and let EventBridge match its state-change event and start the workflow.
The event envelope
Every event has the same outer structure, with the service-specific payload nested inside detail. Here is a real EC2 state-change event:
{
"version": "0",
"id": "6a7e8feb-b491-4cf7-a9f1-bf3703467718",
"detail-type": "EC2 Instance State-change Notification",
"source": "aws.ec2",
"account": "111122223333",
"time": "2017-12-22T18:43:48Z",
"region": "us-west-1",
"resources": [
"arn:aws:ec2:us-west-1:123456789012:instance/i-1234567890abcdef0"
],
"detail": {
"instance-id": "i-1234567890abcdef0",
"state": "terminated"
}
}
The two fields you will write patterns against constantly are source (which service or application emitted this, aws.* for AWS services) and detail-type (which kind of event this is within that source). Everything specific to the event lives under detail, and its shape is defined by the emitting service.
Two details about resources catch people out. AWS API call events sourced from CloudTrail often have nothing in resources at all, so a pattern that filters on it will never match. And global services such as IAM and Route 53 exist only in US East (N. Virginia), so their API call events are available only in that Region. A rule in eu-west-1 waiting for an IAM policy change will wait forever.
Event buses: default, custom, partner
An event bus is a router that receives events and offers them to the rules attached to it. There are three kinds, and the distinction is not cosmetic.
The default event bus exists in every account and Region, and it is where AWS services deliver their events. This is not configurable. When an EC2 instance changes state, that event goes to the default bus of that account, full stop.
A custom event bus is one you create. Your own applications publish to it with PutEvents, and you can forward events from one bus to another (including across accounts and Regions) by making a bus the target of a rule. Custom buses exist so that application events do not have to share a rule namespace with the AWS service traffic, and so you can attach a resource-based policy that lets specific other accounts publish to it.
A partner event bus receives events from a SaaS provider through a partner event source you associate with it.
The misconception to kill now: creating a custom bus does not move AWS service events onto it. If a scenario says "isolate our application events from AWS service noise," a custom bus is right. If a scenario says "receive S3 events on our custom bus," the honest answer is that they arrive on the default bus and you forward them.
Quotas worth remembering: 100 event buses per account per Region, 300 rules per event bus in most Regions, and 5 targets per rule (that last one is not adjustable).
Rules: the pattern is the filter
A rule has a filter and a list of targets. The filter is either an event pattern (match events by content) or a schedule expression (fire on a cron or rate expression). It is one or the other.
The pattern has the same shape as the event it matches, which is the design decision that makes patterns readable. This pattern selects EC2 instance terminations:
{
"source": ["aws.ec2"],
"detail-type": ["EC2 Instance State-change Notification"],
"detail": {
"state": ["terminated"]
}
}
Three separate requirements, all of which must hold.
How pattern matching actually works
Four rules govern every pattern you will ever write or debug. Learn them here and most "my rule does not fire" problems become a 30-second diagnosis.
Matching is a subset test. Every field you name must match. Every field you omit is ignored. So {"source": ["aws.ecs"]} matches every ECS event on the bus. This is the mechanism behind rules that turn out to fire hundreds of times a day: the pattern was under-specified, not wrong.
An array means OR. "state": ["stopped", "terminated"] matches either value. To require two conditions, name two fields, which is an implicit AND. There is a related trap: if you write the same key twice in one pattern, EventBridge uses only the last reference and silently ignores the first.
Matching is exact, character for character. Most AWS services treat : and / in an ARN as interchangeable. EventBridge does not. If the event carries instance/i-0abc and your pattern says instance:i-0abc, nothing matches, and nothing tells you why.
Comparison operators work on leaf nodes only. $or and anything-but are the two exceptions.
Those operators are the second half of pattern fluency:
| Operator | Example | Meaning |
|---|---|---|
prefix | "Region": [{"prefix": "us-"}] | value starts with |
suffix | "FileName": [{"suffix": ".png"}] | value ends with |
anything-but | "state": [{"anything-but": "initializing"}] | value is anything else |
numeric | "Price": [{"numeric": [">", 10, "<=", 20]}] | numeric range |
exists | "state": [{"exists": true}] | field present or absent |
cidr | "sourceIPAddress": [{"cidr": "10.0.0.0/24"}] | IP in range |
equals-ignore-case | "Name": [{"equals-ignore-case": "alice"}] | case-insensitive equality |
wildcard | "FileName": [{"wildcard": "dir/*.png"}] | * matches any characters |
$or | "$or": [{"Location": ["NY"]}, {"Day": ["Monday"]}] | OR across different fields |
Two constraints on the last two. wildcard is supported in event bus rules but not in pipe filters, and each event bus allows only 30 rules containing wildcards, a quota you cannot raise. And an $or that expands to more than 1,000 rule combinations is rejected with InvalidEventPatternException; the combination count is the product of the argument counts of every $or array in the pattern.
An event pattern is capped at 2,048 characters by default.
The single most useful debugging habit here is the EventBridge Sandbox in the console (or the TestEventPattern API). Paste a real event, paste your pattern, get a yes or no. It costs nothing and it settles arguments that otherwise take an afternoon.
Targets and the two permission models
Up to 5 targets per rule. The list is long, and the ones that matter for remediation are Lambda, SNS, SQS, Step Functions, Systems Manager Automation, Systems Manager Run Command, Systems Manager OpsItem, Incident Manager response plans, ECS tasks, API destinations, and other event buses. Some targets do not receive the event at all: EC2 RebootInstances, StopInstances, and TerminateInstances treat the event purely as a trigger for that API call.
Permissions work one of two ways, and knowing which applies to which target is exam material.
An IAM execution role. You set RoleArn on the target, the role's trust policy allows events.amazonaws.com to assume it, and its permission policy grants the action the target needs. This is how most targets work, and it is the only option for targets such as Systems Manager Automation and ECS.
A resource-based policy on the target. For Lambda, SNS, and SQS, if no execution role is configured, EventBridge falls back to a policy on the target resource itself granting events.amazonaws.com permission to invoke or publish.
Here is the practical consequence, and it is a favorite scenario. Create the rule in the console and it works, because the console attaches the resource-based policy for you. Create the same rule with PutTargets and the target is never invoked, because nothing attached that policy. The TriggeredRules metric shows the rule fired; Invocations shows nothing arriving. Two more variants of the same shape: an encrypted SQS queue or SNS topic needs kms:Decrypt and kms:GenerateDataKey granted to events.amazonaws.com in the key policy, and EventBridge cannot use an SQS queue encrypted with an AWS owned key at all.
Input transformation: reshaping the event
Some targets need the event as-is. Others need a specific structure, or a human-readable line. The input transformer solves this in two parts.
The input path defines variables from the event with JSON path:
{
"timestamp": "$.time",
"instance": "$.detail.instance-id",
"state": "$.detail.state"
}
The input template is what the target actually receives:
{
"instance": <instance>,
"state": <state>,
"note": "instance \"<instance>\" is in <state>"
}
You get up to 100 variables, plus reserved ones you do not have to define: aws.events.rule-arn, aws.events.rule-name, aws.events.event.ingestion-time, and aws.events.event.json for the whole original payload.
The failure mode to expect: EventBridge does not validate input paths when you save the rule. A path that matches nothing produces no variable, and that field simply vanishes from the output. No error, no warning, just a target receiving less than you intended.
Scheduled rules and EventBridge Scheduler
A rule can fire on a schedule instead of a pattern, using rate(...) or cron(...). Two facts about scheduled rules that questions turn on: the expression is evaluated in UTC, and the finest resolution is one minute, with the invocation landing somewhere inside that minute rather than on the exact second.
EventBridge Scheduler is the separate, purpose-built service for scheduling, and it is the right answer whenever a scenario stresses scale or per-schedule flexibility. It handles millions of schedules, supports one-time invocations as well as recurring ones, understands time zones, offers flexible time windows to spread load, and reaches more than 270 services through its universal target parameter. Scheduled rules are constrained by the rules-per-bus quota and the 5-targets-per-rule limit; Scheduler is not.
Keyword cue: "thousands of per-customer schedules," "one-time," or "in the customer's local time zone" points at Scheduler. "React when this AWS service does something" points at a rule.
Exam tips
- Read the stem for a past-tense verb. "When an instance is terminated," "when a snapshot completes," "when someone changes a policy" are all EventBridge. "When CPU exceeds 80% for 10 minutes" is an alarm.
- A rule that fires far more often than expected is an under-specified pattern. A rule that never fires is usually one of three things: a pattern with the wrong ARN punctuation, a global-service event expected outside us-east-1, or a filter on a
resourcesfield that CloudTrail-sourced events leave empty. TriggeredRulesgreater than zero withInvocationsat zero means the routing worked and the permissions did not. That is the resource-based-policy question in metric form.- Composite alarms cannot perform EC2 or Auto Scaling actions. When a scenario needs a composite condition to drive a multi-step repair, the composite alarm notifies and an EventBridge rule matches the alarm state-change event.
- Custom event buses never receive AWS service events directly. If an option claims otherwise, eliminate it.
- Remember the three hard numbers: 5 targets per rule (not adjustable), 300 rules per event bus, 100 event buses per account per Region.
The mental model to keep: the bus does not choose a destination. Every rule attached to a bus sees every event that arrives, decides independently whether it matches, and delivers to its own targets. Add a rule and you add a consumer without touching anything already running, which is what "loosely coupled" means in practice here. Next you will look at Pipes, which handles the case a bus is wrong for: one specific stream that needs its records filtered, enriched with a lookup, and handed to exactly one destination.
