Laptop to Production

Who changed what

CloudTrail, and answering 'who did this?'.

Time
30 minutes
Level
Beginner

Part 1: The problem

QuickCart, Tuesday 14:20

The orders page started returning errors at 14:18. The logs showed every request timing out while connecting to the database. The database was running and healthy. The app hadn’t been deployed in two days.

Then Sam spotted it: the database’s security group no longer had the rule letting the app in on port 3306. Nobody remembered removing it. There were five people with access to the console, and every one of them said “not me”.

Sam put the rule back, and the errors stopped. But the next question mattered as much: who removed it, and why? If it was a mistake, it would happen again. If it wasn’t a mistake, that was worse.

Every change in AWS leaves a record. This lesson is about finding it.

Part 2: The idea

Everything you do in AWS, whether you click in the console, run a CLI command, or let Terraform apply, becomes a call to AWS’s API. CloudTrail records those calls: who made each one, what it was, when, from where, and whether it worked.

Key point: Every change in AWS is an API call, and CloudTrail writes down who made it.

What gets recorded

Kind of eventWhat it coversExamplesRecorded by default?
Management eventsCreating, changing, deleting and describing resourcesRunInstances, RevokeSecurityGroupIngress, DeleteBucket, ConsoleLoginYes, in event history
Data eventsReading or writing what’s inside a resourceGetObject and DeleteObject on S3 files, calling a Lambda functionNo — only by a trail with data events turned on, at extra cost

Failed calls are recorded too. An event with "errorCode": "AccessDenied" shows exactly which action someone tried and was refused — which makes CloudTrail the best place to debug a permissions problem, as the IAM lesson shows.

Event history: free, on, 90 days

Every account has event history turned on from the start. It keeps 90 days of management events, costs nothing, and can’t be turned off. You open it in the console under CloudTrail → Event history.

FactWhat it means for you
90 daysFor anything older, you need a trail
Management events onlyIt can’t tell you who deleted a file inside a bucket
One region at a timeLook in the region where the change happened. Changes to global services such as IAM appear in us-east-1
Filter by one attribute at a timePick the one that narrows it most, usually the event name or the resource
Arrives within minutesEvents typically appear within about 5 minutes of the call

You filter by one lookup attribute:

Lookup attributeUse it when you knowExample
Event nameWhat kind of change it wasRevokeSecurityGroupIngress
Resource nameWhich resource changedsg-0db5e1f2
User nameWho might have done itnoor
Event sourceWhich serviceec2.amazonaws.com
Read onlyYou only want changesfalse hides everything that only looked
Resource typeWhat kind of resourceAWS::EC2::SecurityGroup

Most events are someone looking at something: Describe…, List…, Get…. Filtering by Read only = false removes all of them and leaves only the changes. That’s usually the first filter to try when asking “what changed?”

Reading an event record

Each event has a record in JSON. These are the fields that answer “who did what”:

FieldWhat it tells you
eventTimeWhen, always in UTC
eventSourceWhich service: ec2.amazonaws.com, s3.amazonaws.com
eventNameThe API call, such as RevokeSecurityGroupIngress
userIdentityWho made the call. See the next table
sourceIPAddressWhere the call came from. An AWS service name here means a service made the call for you
userAgentWhat made it: the console, the CLI, Terraform, an SDK
requestParametersWhat they asked for: which group, which port, which rule
responseElementsWhat AWS answered
errorCode, errorMessageOnly present if the call failed, for example AccessDenied
readOnlytrue if it only looked; false if it changed something

userIdentity has a type that tells you what sort of caller it was:

TypeMeansHow to find the person
IAMUserAn IAM user with its own password or keysuserName
AssumedRoleTemporary credentials from a role: someone signed in through single sign-on, a server, a pipelineThe end of the arn, after the last /, is the session name: usually a person’s name or a job name
RootThe account’s root userIt’s the account owner. Root should almost never appear
AWSServiceAn AWS service acting for youThe service name, such as autoscaling.amazonaws.com

Trails: keeping it longer, and in one place

Event history is enough to answer “who did this, this week?” For anything more, create a trail: it writes every event to files in an S3 bucket, where you decide how long they stay.

In the AWS console: CloudTrailTrailsCreate trail

SettingWhat it doesQuickCart’s choice
Trail nameA name for the trailquickcart-trail
Storage locationThe S3 bucket the files go toCreate new S3 bucket
Log file SSE-KMS encryptionEncrypts the files with your own KMS key, which costs about $1 a monthOff for a small team; S3’s own encryption still applies
Log file validationAdds signed digest files, so you can prove later that nobody edited or deleted a log fileOn
CloudWatch LogsAlso sends events to a log group, so you can alarm on them — for example on ConsoleLogin by the root userOptional
EventsManagement events (read and write), data events, Insights eventsManagement events only

Trails created in the console record every region, which is what you want. Costs, roughly and as of writing: the first copy of management events is free, apart from the S3 storage; data events cost about $0.10 per 100,000 events; a second copy of management events is charged too. The bucket holds your audit record, so lock it down: no public access, and few people allowed to delete from it.

CloudTrail Lake is a paid option that stores events for years and lets you search them with SQL. You won’t need it for QuickCart; if you do later, check the current pricing and availability first. A trail in S3 plus Athena can answer the same questions.

Part 3: See it

Someone removed the rule that lets the app reach the database. Below is the last hour of QuickCart’s event history. Try each lookup, then open the event that answers the question. Finally, try to find who deleted a file in S3.

Lookup attribute
CloudTrail event history, us-east-1, the last hour
Event timeEvent nameUser nameEvent sourceResource
14:20:03leoec2.amazonaws.com—
14:18:44noorec2.amazonaws.comsg-0db5e1f2
14:18:39noorec2.amazonaws.comsg-0db5e1f2
14:12:09mayaec2.amazonaws.comsg-0a9b8c7d
14:05:51leoec2.amazonaws.com—
13:58:30pipelineecs.amazonaws.comquickcart-orders
13:41:12mayalogs.amazonaws.com—
7 eventsThe question: who removed the database's security group rule? Unfiltered, the history is mostly people looking at things. Filter it.

What to notice: unfiltered, most of the history is people looking at things. Read-only: false or the exact event name gets you to the one change in seconds. And the S3 file deletion isn’t there at all: that’s a data event, and event history doesn’t record them.

Part 4: Do it

Free — security groups cost nothing, and event history is free.

You’ll make a change, undo part of it, and then find both in CloudTrail — exactly as you would after an incident. About 20 minutes, most of it waiting for events to arrive.

Check the region selector says N. Virginia (us-east-1). Event history shows one region at a time, so the change and the lookup must be in the same region.

  1. Create a security group with one rule

    In the AWS console: EC2Network & SecuritySecurity GroupsCreate security group

    FieldEnter
    Security group namequickcart-trail-lab
    DescriptionCloudTrail lab
    VPCthe default VPC, or any VPC you have

    Under Inbound rules, choose Add rule:

    TypePort rangeSource
    Custom TCP8080Custom, 10.0.0.0/16

    Leave the outbound rules as they are, and choose Create security group.

    You should see

    The new group’s page. Copy its Security group ID, which starts sg-. You’ll look it up later.

  2. Remove the rule, as someone might during an incident

    On the group’s page, open the Inbound rules tab and choose Edit inbound rules. Choose Delete next to the 8080 rule, then Save rules.

    You should see

    Inbound rules (0). Note the time. Now wait about 5 minutes: events usually take a few minutes to reach CloudTrail.

  3. Find the change by its event name

    In the AWS console: CloudTrailEvent history

    FieldEnter
    Lookup attributesEvent name
    ValueRevokeSecurityGroupIngress
    You should see

    One row (or more, if you’ve done this before): Event name RevokeSecurityGroupIngress, User name with your own sign-in name, Event source ec2.amazonaws.com, and your security group ID under Resource name.

    Choose the event name to open it.

    You should see

    The event’s details, and below them the Event record: the full JSON. Find these fields in it:

    • eventName: RevokeSecurityGroupIngress
    • userIdentity: you. type is IAMUser if you signed in as an IAM user, or AssumedRole if you signed in through single sign-on
    • sourceIPAddress: your own internet address
    • requestParameters: your group’s ID, and the rule that was removed — shown either as the port and range, or as a rule ID starting sgr-
    • readOnly: false
  4. See the whole life of one resource

    Change the lookup:

    FieldEnter
    Lookup attributesResource name
    Valueyour security group ID, like sg-0db5e1f2
    You should see

    Every change to that one group, newest first: RevokeSecurityGroupIngress, then AuthorizeSecurityGroupIngress (the rule being added), then CreateSecurityGroup. The console did it in two calls; you clicked once. Your list may also include read-only calls the console made to show you the group.

  5. Ask what changed in the last hour

    This is the question to ask early in any incident.

    FieldEnter
    Lookup attributesRead only
    Valuefalse

    Set the time range at the top to the last hour.

    You should see

    Only changes: your three security group calls, plus anything else that changed in this region in the last hour — including changes made by AWS services for you, such as auto scaling launching servers, if you have any running.

  6. Clean-up step: Clean up

    In the AWS console: EC2Network & SecuritySecurity Groupsquickcart-trail-labActionsDelete security groups

    Choose Delete.

    You should see

    The group is gone. If you look in event history in a few minutes, you’ll find DeleteSecurityGroup with your name on it. There’s nothing else to clean up: event history can’t be turned off, and it costs nothing.

Part 5: Check yourself

Someone removed a security group rule yesterday. Where is the quickest free place to find out who?

Which of these would NOT appear in CloudTrail event history?

How long does event history keep events?

In an event record, what does the userIdentity type AssumedRole usually mean?

You want to keep a record of every change for a year, across all regions. What do you set up?

Part 6: Cheat sheet

On one card
Term or actionIn one line
CloudTrailA record of every AWS API call: who, what, when, from where
Management eventA change to, or a look at, a resource. In event history
Data eventReading or writing inside a resource, such as an S3 file. Only in a trail, at extra cost
Event historyFree, always on, 90 days, one region at a time
Read only = falseOnly changes. The first filter in any incident
userIdentity.typeIAMUser, AssumedRole (session name at the end of the ARN), Root, AWSService
errorCode: AccessDeniedA refused call — how to debug permissions
TrailCopies events to S3, all regions, kept as long as you like
Log file validationProves the log files weren’t edited
aws cloudtrail lookup-events --lookup-attributes AttributeKey=EventName,AttributeValue=RevokeSecurityGroupIngressThe same lookup from the CLI

Finished the build and the quiz? Mark it done to fill in its stop on the route map.