Advanced Cloud

Logging and auditing in the cloud — CloudTrail, Cloud Audit Logs, event alerts

Without proper logging, an attack can go undetected for months. Cloud auditing is not optional — it is the mechanism that separates detection within hours from discovery after the damage is done. CloudTrail on AWS and Cloud Audit Logs on GCP record every control-plane action and are the foundation of any forensic investigation.

AWS CloudTrail — what it records and what it doesn’t

CloudTrail records:
  - Control-plane API calls (who created, deleted, or modified resources)
  - Console, CLI, SDK, and AWS service actions
  - Actions on IAM, S3, EC2, Lambda, RDS, etc.

CloudTrail does NOT record by default:
  - Data events (S3 object reads/writes, Lambda invocations)
  - These must be explicitly enabled and incur additional cost
# Create a multi-region trail with log file validation
aws cloudtrail create-trail \
  --name prod-trail \
  --s3-bucket-name audit-logs-prod \
  --include-global-service-events \
  --is-multi-region-trail \
  --enable-log-file-validation

# Enable data events for S3
aws cloudtrail put-event-selectors \
  --trail-name prod-trail \
  --event-selectors '[{
    "ReadWriteType": "All",
    "IncludeManagementEvents": true,
    "DataResources": [{
      "Type": "AWS::S3::Object",
      "Values": ["arn:aws:s3:::sensitive-bucket/"]
    }]
  }]'

Protecting audit logs

CloudTrail logs must be immutable. An attacker who compromises an account will try to delete evidence:

# Log bucket with Object Lock (WORM immutability)
aws s3api put-object-lock-configuration \
  --bucket audit-logs-prod \
  --object-lock-configuration '{
    "ObjectLockEnabled": "Enabled",
    "Rule": {
      "DefaultRetention": { "Mode": "COMPLIANCE", "Days": 365 }
    }
  }'

# Log File Validation — detects deleted or tampered files
aws cloudtrail validate-logs \
  --trail-arn arn:aws:cloudtrail:us-east-1:123456789:trail/prod-trail \
  --start-time 2026-06-01T00:00:00Z

Event alerts with CloudWatch and EventBridge

Detect critical actions in near real time:

# Metric filter — detect root account usage
aws logs put-metric-filter \
  --log-group-name CloudTrail/DefaultLogGroup \
  --filter-name RootAccountUsage \
  --filter-pattern '{ $.userIdentity.type = "Root" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != "AwsServiceEvent" }' \
  --metric-transformations metricName=RootAccountUsage,metricNamespace=CloudTrailMetrics,metricValue=1

# CloudWatch alarm for the metric above
aws cloudwatch put-metric-alarm \
  --alarm-name RootAccountUsage \
  --metric-name RootAccountUsage \
  --namespace CloudTrailMetrics \
  --statistic Sum \
  --period 300 \
  --threshold 1 \
  --comparison-operator GreaterThanOrEqualToThreshold \
  --evaluation-periods 1 \
  --alarm-actions arn:aws:sns:us-east-1:123456789:security-alerts

Critical events that should trigger immediate alerts:

- Root account usage
- CloudTrail disabled or trail modified
- IAM changes (user creation, AdministratorAccess attached)
- Security group with ingress 0.0.0.0/0 created
- S3 bucket with Block Public Access disabled
- Access key created for an IAM user
- Repeated MFA login failures
- High-severity GuardDuty finding

GCP Cloud Audit Logs

On GCP, audit logs have three categories:

Admin Activity  → always on, free — resource creation/deletion
Data Access     → off by default, paid — data reads
System Events   → automatic GCP actions — always on, free
# Enable Data Access logs for Cloud Storage via gcloud
gcloud projects get-iam-policy my-project --format=json > policy.json
# Edit policy.json: add auditLogConfigs for storage.googleapis.com
gcloud projects set-iam-policy my-project policy.json

# Create a log alert in GCP — export to Pub/Sub and process
gcloud logging sinks create audit-alerts \
  pubsub.googleapis.com/projects/my-project/topics/cloud-alerts \
  --log-filter='protoPayload.methodName="SetIamPolicy"'

Correlation and SIEM

Isolated logs cannot detect complex attacks. Forward them to a SIEM:

AWS   → Kinesis Firehose → S3 → Athena or SIEM (Splunk, Elastic)
GCP   → Log Sink → Pub/Sub → Dataflow → BigQuery or SIEM
Azure → Diagnostic Settings → Event Hub → SIEM

Useful queries (Athena over CloudTrail):
  SELECT userIdentity.arn, eventName, COUNT(*)
  FROM cloudtrail_logs
  WHERE errorCode IS NOT NULL
  GROUP BY 1, 2
  ORDER BY 3 DESC
  LIMIT 20;