Monday, November 2, 2026
No menu items!
Google search engine
HomeTechnologyCloud Security 102: AWS Forensics: Who Left the S3 Bucket Open?

Cloud Security 102: AWS Forensics: Who Left the S3 Bucket Open?

By Tech Corsair

There is a particular flavour of dread that comes with the phrase "we think someone's been in our AWS account." It sits somewhere between "the auditors are coming" and "who gave the intern root access" on the corporate anxiety spectrum. The good news is that AWS, for all its labyrinthine complexity, actually provides a rather generous set of forensic tools. The bad news is that most organisations only discover these tools exist after someone has exfiltrated half their customer database through a publicly readable S3 bucket.

Half of all cloud breaches start with misconfigured storage. This is not hyperbole. This is not a scare statistic plucked from a vendor whitepaper to justify a SaaS subscription. This is the reality we have collectively built for ourselves, and yet here we all are, still deploying buckets called prod-backup-final-FINAL with ACLs that would make a locksmith weep.

Let us, then, walk through how to actually investigate when things go sideways in AWS -- because they will, and when they do, panic is not a methodology.

The Forensic Toolbox: What AWS Gives You (If You Turned It On)

The first rule of AWS forensics is brutally simple: you cannot investigate what you did not log. If CloudTrail was not enabled, if VPC Flow Logs were never configured, if S3 access logging was switched off because someone decided it was "too expensive" -- well, that investigation is going to be very short and very unsatisfying.

Here is your forensic toolkit, assuming past-you had the foresight to enable it.

CloudTrail: The API Audit Log

CloudTrail is the crown jewel of AWS forensics. Every API call made against your AWS account -- every CreateUser, every PutBucketPolicy, every RunInstances -- gets recorded. It is, in essence, a surveillance camera pointed at your entire AWS estate.

Key things to know:

  • Management events (control plane operations) are logged by default in every region since 2019. If someone creates an IAM user, modifies a security group, or launches an instance, CloudTrail has it.
  • Data events (S3 object-level operations, Lambda invocations) are not enabled by default. These cost extra. They are also exactly what you need when investigating data exfiltration. The irony is not lost on anyone.
  • CloudTrail delivers logs to S3 with a typical delay of 5-15 minutes. It is not real-time. If you need real-time, pipe it into CloudWatch Logs or EventBridge.

When the alarm bells ring, CloudTrail is where you start. Who did what, when, and from where.

# Look up recent API calls by a specific IAM user
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=Username,AttributeValue=suspicious-user \
  --start-time "2026-10-28T00:00:00Z" \
  --end-time "2026-11-01T23:59:59Z" \
  --max-results 50

# Search for specific event types -- e.g., who's been creating access keys?
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=CreateAccessKey \
  --start-time "2026-10-01T00:00:00Z"

# Check which trails exist and whether they're actually logging
aws cloudtrail describe-trails
aws cloudtrail get-trail-status --name my-org-trail

VPC Flow Logs: Network Forensics, Cloud-Style

VPC Flow Logs capture metadata about network traffic flowing through your Virtual Private Cloud -- source IP, destination IP, ports, protocol, bytes transferred, and whether the traffic was accepted or rejected. Think NetFlow, but managed by AWS and delivered to S3 or CloudWatch Logs.

They will not give you packet contents (this is metadata, not a PCAP), but they will tell you:

  • Which instances were communicating with external IPs
  • Whether traffic was allowed or denied by security groups and NACLs
  • Unusual data transfer volumes that might indicate exfiltration
  • Connections to known-bad IP addresses
# Create a flow log for a VPC (if one doesn't exist -- do this NOW, not during an incident)
aws ec2 create-flow-logs \
  --resource-type VPC \
  --resource-ids vpc-0123456789abcdef0 \
  --traffic-type ALL \
  --log-destination-type s3 \
  --log-destination arn:aws:s3:::my-flowlogs-bucket

# Query flow logs using CloudWatch Logs Insights
aws logs start-query \
  --log-group-name /vpc/flowlogs \
  --start-time $(date -d '24 hours ago' +%s) \
  --end-time $(date +%s) \
  --query-string 'fields @timestamp, srcAddr, dstAddr, dstPort, bytes
    | filter dstPort = 443
    | sort bytes desc
    | limit 25'

GuardDuty: The Threat Detection Service That Actually Works

GuardDuty is AWS's managed threat detection service, and credit where it is due -- it is genuinely useful. It analyses CloudTrail logs, VPC Flow Logs, and DNS query logs to identify suspicious activity, including:

  • Compromised EC2 instances communicating with known command-and-control servers
  • Unusual API calls from anomalous locations
  • Cryptocurrency mining activity (because of course attackers mine crypto on your bill)
  • Reconnaissance activity against your environment
# List high-severity findings
aws guardduty list-findings \
  --detector-id your-detector-id \
  --finding-criteria '{"Criterion":{"severity":{"Gte":7}}}'

# Get details on specific findings
aws guardduty get-findings \
  --detector-id your-detector-id \
  --finding-ids "finding-id-here"

The most important thing about GuardDuty is that it needs to be enabled to work. This sounds obvious, but the number of organisations that discover GuardDuty exists only after an incident is genuinely distressing.

S3 Access Logging and IAM Credential Reports

S3 access logging records every request made to an S3 bucket -- who accessed it, from where, and what they did. This is separate from CloudTrail data events and provides more granular detail about object-level access.

IAM credential reports provide a comprehensive snapshot of every IAM user and the state of their credentials -- when passwords and access keys were last used, whether MFA is enabled, and when credentials were last rotated.

# Generate and download an IAM credential report
aws iam generate-credential-report
aws iam get-credential-report --output text --query Content | base64 -d > credential-report.csv

# Check S3 bucket logging status
aws s3api get-bucket-logging --bucket my-important-bucket

# List all public S3 buckets (the command you should run right now, today)
aws s3api list-buckets --query 'Buckets[].Name' --output text | tr '\t' '\n' | while read bucket; do
  result=$(aws s3api get-public-access-block --bucket "$bucket" 2>&1)
  if echo "$result" | grep -q "NoSuchPublicAccessBlockConfiguration"; then
    echo "NO PUBLIC ACCESS BLOCK: $bucket"
  fi
done

CloudWatch: Metrics, Alarms, and Log Aggregation

CloudWatch ties everything together. It aggregates logs from across your AWS estate, provides metrics on resource utilisation, and allows you to set alarms for anomalous behaviour. During an investigation, CloudWatch Logs Insights is invaluable for querying large volumes of log data.

# Search CloudWatch Logs for failed console logins
aws logs filter-log-events \
  --log-group-name /aws/cloudtrail \
  --filter-pattern '{ $.eventName = "ConsoleLogin" && $.responseElements.ConsoleLogin = "Failure" }' \
  --start-time $(date -d '7 days ago' +%s)000

# Check for unusual spikes in API calls
aws cloudwatch get-metric-statistics \
  --namespace AWS/CloudTrail \
  --metric-name EventCount \
  --start-time "2026-10-28T00:00:00Z" \
  --end-time "2026-11-01T00:00:00Z" \
  --period 3600 \
  --statistics Sum

Incident Response in AWS: The Playbook

When an incident occurs in AWS, the response process has its own unique characteristics. You cannot walk up to a server and pull the power cable. The server is in a data centre in us-east-1, and all you have is an API and a mounting sense of urgency.

Step 1: Isolate the Compromised Instance

Do not terminate the instance. That destroys your evidence. Instead, isolate it by replacing its security group with one that allows no inbound or outbound traffic.

# Create a quarantine security group (do this in advance, not during a crisis)
aws ec2 create-security-group \
  --group-name "forensic-quarantine" \
  --description "No inbound or outbound traffic - forensic isolation" \
  --vpc-id vpc-0123456789abcdef0

# The group has no rules by default, which means no inbound.
# Remove the default outbound allow-all rule:
QUARANTINE_SG=$(aws ec2 describe-security-groups \
  --filters Name=group-name,Values=forensic-quarantine \
  --query 'SecurityGroups[0].GroupId' --output text)

aws ec2 revoke-security-group-egress \
  --group-id $QUARANTINE_SG \
  --ip-permissions '[{"IpProtocol":"-1","FromPort":-1,"ToPort":-1,"IpRanges":[{"CidrIp":"0.0.0.0/0"}]}]'

# Apply quarantine SG to compromised instance (replaces all existing SGs)
aws ec2 modify-instance-attribute \
  --instance-id i-0compromised123 \
  --groups $QUARANTINE_SG

Step 2: Snapshot Forensics

Take snapshots of the instance's EBS volumes. These are your forensic images -- the cloud equivalent of dd-ing a hard drive.

# Get volume IDs attached to the compromised instance
aws ec2 describe-instances \
  --instance-ids i-0compromised123 \
  --query 'Reservations[].Instances[].BlockDeviceMappings[].Ebs.VolumeId' \
  --output text

# Create forensic snapshots (tag them properly)
aws ec2 create-snapshot \
  --volume-id vol-0abc123def456 \
  --description "Forensic snapshot - incident 2026-11-01 - DO NOT DELETE" \
  --tag-specifications 'ResourceType=snapshot,Tags=[{Key=Purpose,Value=Forensic},{Key=IncidentID,Value=INC-2026-001}]'

Once snapshotted, you can mount these volumes on a clean forensic analysis instance in an isolated VPC. Analyse the filesystem, check for persistence mechanisms, examine running processes from memory dumps, and generally do all the things you would do with a traditional forensic image -- just in the cloud.

Step 3: Credential Rotation (The "Change All the Locks" Phase)

If credentials are compromised, rotate everything. And by everything, that means everything.

# List access keys for a compromised user
aws iam list-access-keys --user-name compromised-user

# Deactivate compromised access keys (don't delete yet -- you need them for the investigation)
aws iam update-access-key \
  --user-name compromised-user \
  --access-key-id AKIA0COMPROMISED123 \
  --status Inactive

# Invalidate all active sessions for an IAM role by adding a deny-all inline policy
# with a date condition (any session created before NOW is denied)
aws iam put-role-policy \
  --role-name compromised-role \
  --policy-name RevokeOlderSessions \
  --policy-document '{
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*",
      "Condition": {
        "DateLessThan": {"aws:TokenIssueTime": "2026-11-01T12:00:00Z"}
      }
    }]
  }'

The AWS Security Gotchas: A Greatest Hits Collection

Some security misconfigurations in AWS are so common they have become cliches. They are the "password123" of cloud security -- everyone knows they are bad, everyone has seen them in production, and yet they persist with a stubbornness that would be admirable if it were not so dangerous.

Public S3 Buckets: The Gift That Keeps on Giving

The number of organisations that have been breached via publicly accessible S3 buckets is, at this point, beyond parody. Capital One, Twitch, various government agencies, and countless others have all had their "oh no, the bucket was public" moment.

AWS has introduced multiple guardrails -- S3 Block Public Access at the account level, bucket policies that warn about public access, console banners that practically scream at you -- and yet public buckets persist. Enable S3 Block Public Access at the account level. Do it now. Do it before finishing this article.

Overpermissive IAM: The Principle of Most Privilege

The AdministratorAccess managed policy is not a default. It is a surrender. When every Lambda function, every EC2 instance, and every developer has full administrative access, the blast radius of any compromise is "everything."

The principle of least privilege exists for a reason. Use it. Yes, it is more work. Yes, developers will complain. But "we gave everything admin access because it was easier" is not a sentence anyone wants to say in a post-incident review.

IMDS and SSRF: The Metadata Service Problem

The Instance Metadata Service (IMDS) at 169.254.169.254 is a treasure trove for attackers who achieve SSRF (Server-Side Request Forgery) on an EC2 instance. A single SSRF vulnerability can allow an attacker to retrieve the temporary credentials associated with the instance's IAM role -- and from there, pivot through the entire AWS account.

IMDSv2 (which requires a session token via a PUT request before metadata can be accessed) mitigates this significantly. Enforce it across all instances:

# Enforce IMDSv2 on an existing instance
aws ec2 modify-instance-metadata-options \
  --instance-id i-0123456789abcdef0 \
  --http-tokens required \
  --http-endpoint enabled

# Check which instances are still using IMDSv1
aws ec2 describe-instances \
  --query 'Reservations[].Instances[].[InstanceId,MetadataOptions.HttpTokens]' \
  --output table

Building a Forensic Readiness Programme

The worst time to figure out your AWS forensics capability is during an incident. The second worst time is right now. But right now is still better than during the next incident, so here is a readiness checklist:

  1. Enable CloudTrail in all regions with data events for critical S3 buckets and Lambda functions. Send logs to a centralised, immutable S3 bucket with object lock enabled.
  2. Enable VPC Flow Logs for all VPCs. The cost is minimal compared to the cost of not having them.
  3. Enable GuardDuty across all accounts and regions. Aggregate findings into a central security account.
  4. Create forensic infrastructure in advance -- quarantine security groups, a forensic analysis VPC, and an AMI with your forensic tools pre-installed.
  5. Practise. Run tabletop exercises. Simulate compromised credentials and walk through the response. The time to learn the aws iam put-role-policy syntax is not when someone is actively exfiltrating data.
  6. Enable S3 Block Public Access at the organisation level via AWS Organizations SCPs.
  7. Enforce IMDSv2 across all accounts via an SCP or launch template defaults.
  8. Set up cross-account log aggregation so that a compromised account cannot tamper with its own audit trail.
  9. Wrapping Up: The Cloud Forensic Mindset

    AWS forensics is fundamentally different from traditional forensics. There is no hard drive to image, no physical chain of custody, and the "crime scene" is a collection of API calls and JSON documents spread across multiple regions. But the principles remain the same: preserve evidence, establish a timeline, determine scope, and figure out what happened.

    The cloud security landscape is littered with the wreckage of organisations that assumed AWS would handle security for them. AWS will give you the tools. AWS will give you the logs. AWS will give you GuardDuty and Security Hub and a dozen other services with reassuringly enterprise-sounding names. What AWS will not do is configure them for you, enable them by default (mostly), or respond to your incidents.

    That part is still very much your problem. The data migrated to the cloud. The responsibility did not migrate with it. And somewhere out there, right now, an S3 bucket called prod-database-backup-2026 is sitting wide open, waiting patiently for someone to notice.

    Make sure it is you who notices first.


    Tech Corsair writes about cybersecurity, cloud infrastructure, and the various ways organisations manage to make "someone else's computer" their own problem. New articles published weekly at techcorsair.co.uk.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments