Lesson 3 of 5 · 25 min read

Cloud Audit Logs — CloudTrail, Azure Activity, GCP Audit

Detection on cloud infrastructure requires understanding a completely different log format from Windows events. The principles are the same (who, what, where, when, why), but the schema, the data, and the attack surface all differ.


Why Cloud Logs Are Different

On-premises logs describe OS operations — processes, files, network connections. Cloud audit logs describe API operations — because in cloud environments, everything (creating a VM, attaching a role, reading an S3 bucket) goes through an API.

The adversary goal is the same: gain access, escalate privilege, persist, exfiltrate. But the actions look like:


AWS CloudTrail

CloudTrail is AWS’s primary audit trail. Every API call made to AWS services generates a CloudTrail event — regardless of how the call was made (Console, CLI, SDK, Lambda function).

AWS CloudTrail — CloudTrail Event — iam:CreateAccessKey
{
  "eventVersion": "1.08",
  "userIdentity": {
    "type": "AssumedRole",
    "principalId": "AROAEXAMPLEID:session-name",
    "arn": "arn:aws:sts::123456789012:assumed-role/AdminRole/session-name",
    "accountId": "123456789012",
    "sessionContext": {
      "sessionIssuer": {
        "type": "Role",
        "arn": "arn:aws:iam::123456789012:role/AdminRole",
        "accountId": "123456789012",
        "userName": "AdminRole"
      },
      "webIdFederationData": {},
      "attributes": {
        "creationDate": "2024-03-15T08:00:00Z",
        "mfaAuthenticated": "false"
      }
    }
  },
  "eventTime": "2024-03-15T09:23:14Z",
  "eventSource": "iam.amazonaws.com",
  "eventName": "CreateAccessKey",
  "awsRegion": "us-east-1",
  "sourceIPAddress": "203.0.113.55",
  "userAgent": "aws-cli/2.13.0",
  "requestParameters": {
    "userName": "backup-user"
  },
  "responseElements": {
    "accessKey": {
      "accessKeyId": "AKIAEXAMPLEKEYID",
      "status": "Active",
      "userName": "backup-user",
      "createDate": "Mar 15, 2024 9:23:14 AM"
    }
  },
  "eventID": "12345678-1234-1234-1234-123456789012",
  "readOnly": false,
  "eventType": "AwsApiCall"
}

Key CloudTrail fields for detection

FieldDetection use
userIdentity.typeIs this a User, Role session, Service, or Root?
userIdentity.arnThe specific principal (account + role + session)
eventNameThe API action called — this is your “what”
eventSourceWhich AWS service (iam.amazonaws.com, s3.amazonaws.com)
sourceIPAddressWhere the call originated
errorCodePresent on failed calls — AccessDenied sequences are reconnaissance patterns
readOnlyTrue for read operations; false for writes/mutations

Azure Activity Log

The Azure Activity Log records control-plane operations across an Azure subscription — resource creation, role assignments, policy changes. It is distinct from Entra ID (Azure AD) sign-in and audit logs.

{
  "time": "2024-03-15T09:23:14.882Z",
  "operationName": {
    "value": "Microsoft.Authorization/roleAssignments/write",
    "localizedValue": "Create role assignment"
  },
  "status": {
    "value": "Succeeded"
  },
  "caller": "attacker@victim.onmicrosoft.com",
  "tenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "subscriptionId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
  "resourceId": "/subscriptions/.../resourceGroups/prod-rg/providers/Microsoft.Compute/virtualMachines/web-01",
  "properties": {
    "requestbody": "{\"properties\":{\"roleDefinitionId\":\"...Owner...\",\"principalId\":\"...\"}}",
    "statusCode": "Created"
  }
}

The most important Activity Log events for detection:

OperationWhy it matters
roleAssignments/writePrivilege escalation — someone assigned a role
policyAssignments/writePolicy bypass — attacker exempting resources
virtualMachines/runCommand/actionCode execution via Azure Run Command
managedIdentities/writePersistence via managed identity
deployments/writeInfrastructure changes (backdoor via ARM template)

GCP Audit Logs

GCP organizes audit logs into three types that you must treat differently:

TypeWhat it recordsDefaultCost
Admin ActivityControl plane changes — creating VMs, modifying IAMAlways onFree
Data AccessReading/writing data — GCS GetObject, BigQuery readsOffBillable
System EventGCP-initiated operations — live migrationAlways onFree
{
  "logName": "projects/my-project/logs/cloudaudit.googleapis.com%2Factivity",
  "resource": {
    "type": "iam_role",
    "labels": { "project_id": "my-project" }
  },
  "timestamp": "2024-03-15T09:23:14.123Z",
  "protoPayload": {
    "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
    "authenticationInfo": {
      "principalEmail": "attacker@compromised.iam.gserviceaccount.com"
    },
    "requestMetadata": {
      "callerIp": "203.0.113.55",
      "callerSuppliedUserAgent": "google-cloud-sdk/456.0.0"
    },
    "serviceName": "iam.googleapis.com",
    "methodName": "google.iam.admin.v1.CreateServiceAccountKey",
    "resourceName": "projects/my-project/serviceAccounts/victim-sa@my-project.iam.gserviceaccount.com",
    "status": {}
  }
}

For detection: protoPayload.methodName is your “what”, protoPayload.authenticationInfo.principalEmail is your “who”, and protoPayload.requestMetadata.callerIp is your “where.”

AWS CloudTrail User Guide— AWS Docs Azure Activity Log— Microsoft Docs GCP Cloud Audit Logs— Google Cloud Docs