DOP Lab 02 - Event-driven auto-remediation with EventBridge

Scaffold: 3/5 (half-built). The Lambda, its execution role, the EventBridge rule, and the permission that lets events invoke the function are all wired. You write the two things that decide whether the right event reaches the right code: the rule’s event pattern and the handler’s remediation body.

The scenario

A security service in your account emits a custom finding whenever it spots an EC2 instance that is missing a required tag. The finding is an EventBridge event: source acme.security, detail-type Instance Missing Required Tag, with the offending instance id in the detail. You want that finding, and only that finding, to trigger a Lambda that quarantines the instance by tagging it Status=quarantined.

The tempting shortcut is a broad rule (“anything from acme.security”) with the filtering done in the Lambda. That fires the function on every finding the security service ever emits, pays for every invocation, and puts the routing decision in code where it is harder to see. The version that worth writing is a rule whose pattern matches the exact finding, so EventBridge drops everything else before the function is ever invoked.

What’s provided

Your task

Gap one, src/event-pattern.json. Narrow the pattern so it matches only the missing-tag finding: source acme.security and detail-type Instance Missing Required Tag. EventBridge patterns match a value when the event’s field appears in the list you give:

{
  "source": ["acme.security"],
  "detail-type": ["Instance Missing Required Tag"]
}

Gap two, src/handler.py. Fill in handler(): read the instance id from event["detail"]["instanceId"], log the remediation (log it before you tag, so it is recorded even if tagging fails), then call ec2.create_tags to add Status=quarantined. Wrap the tag call in try/except ClientError so the fake instance id the test sends does not crash the invocation.

Run it

# Defaults: stack dop-lab-02, region ap-southeast-2.
./scripts/deploy.sh          # deploys with your event-pattern.json, uploads your handler.py
./scripts/test.sh            # puts two findings and reads the function's logs
./scripts/teardown.sh        # deletes the stack and the Lambda log group

Before your first lab, do the one-time setup: run the zip’s preflight.sh, then deploy the lab reaper so a forgotten stack cannot bill you. Every deploy here tags its stack for the reaper.

What success looks like

./scripts/test.sh puts two findings on the bus, a matching one and a non-matching one, waits, and reads the function’s CloudWatch logs:

Handler remediated i-0lab02remediate01: true   (expected true)
Handler saw ignored i-0lab02ignored0002:  false  (expected false)

PASS: the rule routed the missing-tag finding to the Lambda, the handler
remediated it, and the terminated-instance finding was filtered out.

With the starter pattern the handler also acts on the ignored finding, so the test reports it saw i-0lab02ignored0002 and tells you to narrow the pattern. With the skeleton handler nothing is remediated at all, and the test tells you to fill in handler.py.

Reveal the solution

Deploy both reference answers without editing anything:

SRC=solution ./scripts/deploy.sh && ./scripts/test.sh

What you just learned

Next

The rest of the DOP Pro lab track is listed in labs/README-dop.md.