AWS CloudTrail
The AWS CloudTrail connector polls management-plane API events from the CloudTrail event history. Unlike a raw CloudTrail-to-S3 firehose, this connector ships with a curated allow-list of ~80 high-signal event names chosen to align 1:1 with AiSOC's bundled cloud detection content.
That choice is deliberate. A busy production AWS account emits tens of thousands of CloudTrail events per minute, the vast majority of which are read-only describes / lists from AWS services themselves. Blindly ingesting all of them would saturate the alert pipeline without producing any net new detection signal. The allow-list keeps ingest volume tractable while still surfacing every event the bundled detections actually fire on.
Use the AWS GuardDuty connector for ML-based threat detection. Use this CloudTrail connector for deterministic detection of sensitive AWS API calls — IAM grants, trail tampering, public-S3 changes, KMS key destruction, cross-account sharing, console logins, and so on.
What you get
| Source | CloudTrail API | Notes |
|---|---|---|
| Management events | LookupEvents | One filtered call per event-name in the allow-list |
Events are normalized with source: aws_cloudtrail and
category: cloud. The full embedded CloudTrailEvent payload is
preserved on raw_event so detection rules and playbooks can inspect
requestParameters, responseElements, and the full userIdentity
shape.
Capabilities
| Capability | Backed by | Notes |
|---|---|---|
PULL_ALERTS | cloudtrail:LookupEvents | Default — every connector instance |
CloudTrail is read-only. To block a malicious IP that surfaces in a
CloudTrail event (e.g. a ConsoleLogin from an unexpected geography),
route the alert through a playbook that uses the
AWS Security Hub connector's
BLOCK_IP capability or any other network-control connector.
Prerequisites
- AWS CloudTrail enabled in the region you want to monitor — the
default
Management events: Read/Writetrail that AWS provisions on every account is enough. - IAM permissions:
cloudtrail:LookupEventscloudtrail:DescribeTrails(used byTest connection)sts:AssumeRole(only if you target a role in another account)
- One of:
- Static access key (
AccessKeyId+SecretAccessKey) for a dedicated IAM user, or - No credentials at all — AiSOC falls back to the runtime IAM role
/ instance profile of the host running the
connectorsservice.
- Static access key (
The runtime-IAM-role path is strongly preferred for production deployments.
Setup walkthrough
1. (Optional) Create a least-privilege IAM user
If you cannot use an instance role, create a dedicated IAM user with only the policy below, and capture an access key for it:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AiSOCCloudTrailRead",
"Effect": "Allow",
"Action": [
"cloudtrail:LookupEvents",
"cloudtrail:DescribeTrails"
],
"Resource": "*"
}
]
}
2. Add the connector in AiSOC
- Connectors → Add connector → AWS CloudTrail.
- Set AWS Region (e.g.
us-east-1). - Leave Access Key ID and Secret Access Key blank to use the runtime IAM role. Otherwise paste the static credentials from step 1.
- Leave Event allow-list blank to use AiSOC's curated default (recommended). See Customising the allow-list below if you need to override it.
- Test connection — AiSOC calls
DescribeTrailsto verify auth. - Save.
Polling details
- Default interval: 300 seconds.
- Each poll iterates the configured event allow-list and issues one
paginated
LookupEventscall per event name, filtered byLookupAttributes={EventName=<name>}and the time window(now - 300s, now). - Per-event-name results are capped at 100 events per poll to bound memory and respect the AWS CloudTrail rate limit (2 transactions per second per region per account).
- Failures on any single event-name lookup are logged and skipped — one bad attribute does not halt the rest of the poll.
Severity mapping
CloudTrail events do not carry intrinsic severity, so AiSOC labels each event by sensitivity:
| Event class | Examples | AiSOC severity |
|---|---|---|
| Trail/detection tamper, KMS destruction, root account use, org tampering | DeleteTrail, StopLogging, DisableSecurityHub, ScheduleKeyDeletion, RemoveAccountFromOrganization, LeaveOrganization | high |
| Mutating IAM / network / public-S3 / config | CreateAccessKey, AttachUserPolicy, PutBucketPolicy, AuthorizeSecurityGroupIngress, PutKeyPolicy | medium |
| Read-only recon | GetAccountAuthorizationDetails, ListAccessKeys, GetSecretValue | low |
If the event has an errorCode set (the API call was denied), AiSOC
bumps the severity up one tier. A denied destructive action is
often the loudest signal in the account — for example, an attacker
trying StopLogging against a trail they don't have permission to
modify.
Customising the allow-list
The event_names field accepts three modes:
- Blank (default) — use AiSOC's curated detection-aligned default list. This is the right answer for ~95% of operators.
- Comma-separated event names — replace the default with your own
list. Example:
ConsoleLogin,CreateAccessKey,PutBucketPolicy,DeleteTrail. Useful when you've added custom detection content and want to surface a narrower set than the default. *— disable filtering entirely. AiSOC will pull every CloudTrail event in the time window. High volume warning — only use this in lab/staging accounts or when you have downstream rate-limiting in place. A single production account on*can generate millions of events per day.
The default list is curated against the bundled
detections/cloud/aws-*.yaml rules — every event name in it is
referenced by at least one detection rule.
Multi-account / multi-region
CloudTrail's management-event history is per-region. To cover an
account globally, add one connector instance per region that hosts
production workloads. The connector emits an aws_region field on
every event so playbooks can branch on origin.
For multi-account topologies, prefer one connector per account × region pair, each with its own IAM credentials. CloudTrail does not have a delegated-administrator pattern equivalent to GuardDuty.
Troubleshooting
AccessDenied on LookupEvents — the IAM user / role is missing
cloudtrail:LookupEvents. Reattach the policy from step 1.
Test connection succeeds but no events appear — confirm the
allow-list is not over-narrow for your account, and that the events
you expect are actually firing in the AWS console under
CloudTrail → Event history. Try setting event_names to *
temporarily (in lab) to confirm the connection works.
Events arrive several minutes late — CloudTrail is eventually consistent. AWS publishes a typical end-to-end delivery latency of ~15 minutes. AiSOC polls a 5-minute window every 300 seconds with no high-water-mark cursor, so events that arrive late will be picked up on the next poll cycle.
Rate-limit / ThrottlingException — the allow-list iteration can
hit the 2-TPS-per-region CloudTrail limit if the list is very large
or polling is set very aggressively. Reduce the allow-list, increase
the poll interval, or split the load across multiple connector
instances per region.
boto3 is required at runtime — boto3 is bundled with the
services/connectors Docker image. If you are running the service
outside Docker, install it: pip install boto3.
Related
- AWS GuardDuty — ML-based threat detection layered on top of CloudTrail, VPC Flow Logs, and DNS.
- AWS Security Hub — multi-source
finding aggregator with
BLOCK_IP/ALLOW_IPcontainment. - AWS VPC Flow Logs — raw network telemetry to cross-reference against CloudTrail events.
Configuration reference
| Field | Label | Type | Required | Default | Notes |
|---|---|---|---|---|---|
region | AWS Region | string | yes | us-east-1 | — |
access_key | Access Key ID | string | no | — | Leave blank to use the runtime IAM role / instance profile. |
secret_key | Secret Access Key | secret | no | — | encrypted at rest · Required only when supplying a static access key above. |
event_names | Event allow-list (comma-separated) | string | no | — | Override the default curated event list. Leave blank to use AiSOC's curated list, or set to '*' to pull every CloudTrail event in the window (high volume — not recommended). |
secret_key is encrypted at rest by the credential vault before the row is written, and decrypted only at poll time. The value is never logged and never returned by the API. See credential vault.