AI SecurityCrowdStrikeAWSCloud SecuritySOC Automation

Cloud Defense Evasion: Agent-Driven Workflows for Security

Triaging AWS defense-evasion detections at scale with an AI agent: CloudTrail tampering, security group changes, and IMDSv1 re-enablement - classified, scoped, and actioned against real change tickets.

Luis Torres-Villarreal

Series: Agent-Driven Workflows - CrowdStrike Detection Triage. Post 2 of 5. Originally published on LinkedIn. Previous in series: Cloud Account Discovery at Scale.

Detection Context

Defense evasion detections in AWS are high-signal because attackers disable logging and open network paths before moving laterally or exfiltrating data. This class maps to MITRE T1562 - Impair Defenses - and covers three distinct behaviors: silencing CloudTrail, punching holes in security groups, and re-enabling IMDSv1 to expose credential endpoints. When these fire in a production environment, the window between detection and impact is short.

Scenario

The team opens the CrowdStrike Falcon console and finds 100+ defense evasion detections sitting in the queue, including: CloudTrail tampering events, security group modifications, and IMDSv1 enablements. The environment spans multiple AWS accounts with a mix of production workloads and CDE subnets falling under the scope of PCI. Manual triage is slow and inefficient.

The bulk of the CloudTrail hits are StopLogging and UpdateTrail/PutEventSelectors - two patterns that look very different at the response level. The security group alerts split between ingress 0.0.0.0/0 and egress 0.0.0.0/0, with a handful touching subnets recognized as PCI scope. The IMDSv1 detections are all ModifyInstanceAttribute calls setting httpTokens to optional - low individual severity, but a forced-pivot enabler if any of those instances carried a high-privilege role.

The following alert fields are handed to an agent harness so it runs structured triage across all three sub-types in parallel:

display_name, event_name, source_ip_address, aws_access_key_id, cloud_account_id, source_account_name, request_parameters, first_timestamp.

Prompt Chain

Prompt 1 - Classify the alert sub-type and pull the raw event

You are a cloud security triage agent.

Alert fields:

  • event_name: {{event_name}}
  • source_ip_address: {{source_ip_address}}
  • aws_access_key_id: {{aws_access_key_id}}
  • cloud_account_id: {{cloud_account_id}}
  • source_account_name: {{source_account_name}}
  • request_parameters: {{request_parameters}}
  • first_timestamp: {{first_timestamp}}

Step 1: Classify this alert as one of: CloudTrail-Tampering, SecurityGroup-Modification, or IMDSv1-Enablement. Step 2: Call the relevant AWS API to retrieve the full event record within a 5-minute window around first_timestamp. Step 3: Return the classification, the raw event JSON, and the caller identity (ARN, access key, source IP).

Prompt 2 - Change ticket lookup and authorization check

Given the following triage context:

  • Event classification: {{classification}}
  • Caller ARN: {{caller_arn}}
  • Event time: {{first_timestamp}}
  • Account: {{cloud_account_id}}

Query Jira for any open or recently closed change tickets that:

  1. Cover this action type in account {{cloud_account_id}}
  2. Were active within a 2-hour window of {{first_timestamp}}
  3. List {{caller_arn}} or the associated team as the authorized implementer

Return: ticket_id, ticket_status, authorized_implementer, ticket_scope, match (yes/no).

If no ticket is found, return match=no and flag for escalation.

Prompt 3 - Sub-type specific risk assessment

Using the classification and event data from prior steps, run the appropriate risk check:

If CloudTrail-Tampering:

  • Map event_name to severity: StopLogging or DeleteTrail = CRITICAL, UpdateTrail or PutEventSelectors = HIGH if scope reduced
  • Check if logging was restored after the event

If SecurityGroup-Modification:

  • Extract groupId, port range, protocol, CIDR from request_parameters
  • Identify attached instances and check subnet against CDE network map
  • Apply port risk table: SSH/RDP = HIGH, all-port = CRITICAL, app port = MEDIUM, ephemeral = LOW
  • Confirm whether the rule is still active

If IMDSv1-Enablement:

  • Retrieve the instanceId and its attached IAM role
  • Flag HIGH if role has admin or cross-account permissions, flag CDE scope separately

Return: severity, scope_flags (CDE, PCI, production), rule_still_active (yes/no/n-a).

Prompt 4 - Decision and response action

Given:

  • Classification: {{classification}}
  • Severity: {{severity}}
  • Change ticket match: {{ticket_match}}
  • Scope flags: {{scope_flags}}
  • Rule still active: {{rule_still_active}}

Apply the decision table for this classification and output:

  1. Verdict: False Positive, True Positive, or Undetermined
  2. Immediate actions (list, in order)
  3. Falcon alert status to set: closed, in-progress, or escalate
  4. Slack message draft summarizing the finding for the on-call channel

Agent Workflow

CloudTrail Tampering

Step 1 - Map the event to its impact

The agent reads event_name and maps it against this table:

event_name Meaning
StopLogging CloudTrail logging paused - gap in audit record begins
DeleteTrail Trail deleted - logging gone until recreated
UpdateTrail Trail configuration changed - scope or destination may have shifted
PutEventSelectors Event selectors narrowed - specific event types may be excluded

Step 2 - Pull the raw CloudTrail event

aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue={{event_name}} \
  --start-time {{first_timestamp - 5min}} \
  --end-time {{first_timestamp + 5min}} \
  --region {{region}}

For StopLogging, the agent extracts the trail ARN. For PutEventSelectors, it extracts the new selector configuration and compares it against the previous baseline to determine what was excluded.

Step 3 - Jira change ticket check

The agent queries the Jira REST API for tickets in the relevant account’s change board, filtering for tickets active within a 2-hour window of first_timestamp. It checks whether the caller ARN matches the authorized implementer on the ticket.

Step 4 - Decision table

Condition Verdict Action
StopLogging + no ticket CRITICAL Escalate immediately, restore logging
StopLogging + valid ticket Document Verify logging was restored post-change
DeleteTrail + no ticket CRITICAL Escalate, open incident
UpdateTrail + no ticket HIGH Review scope change, hold for analyst
PutEventSelectors + no ticket HIGH Review excluded events, hold for analyst
UpdateTrail + valid ticket + scope unchanged Close Document and close

Security Group Modifications

Step 1 - Extract the rule details

The agent parses request_parameters for: groupId, port range, protocol, CIDR block (checking both 0.0.0.0/0 and ::/0).

Step 2 - Find attached instances

aws ec2 describe-instances \
  --filters Name=instance.group-id,Values={{groupId}} \
  --query 'Reservations[].Instances[].{InstanceId:InstanceId,SubnetId:SubnetId,VpcId:VpcId,Tags:Tags}'

Step 3 - Check scope

The agent compares each instance’s SubnetId against the CDE network map and checks instance tags for Environment:production and Compliance:PCI.

Step 4 - Port risk table

Port / Range Risk
22 (SSH) or 3389 (RDP) HIGH
0-65535 (all ports) CRITICAL
Application port (80, 443, 8080) MEDIUM
Ephemeral range (32768-60999) LOW

Step 5 - Confirm rule is still active

aws ec2 describe-security-groups \
  --group-ids {{groupId}} \
  --query 'SecurityGroups[].IpPermissions'

Step 6 - Decision

  • Port 22 or 3389 + CDE subnet + no ticket: revoke rule immediately, open incident
  • All-port rule (0-65535): CRITICAL, escalate for revocation
  • Non-CDE + valid ticket: document, close

IMDSv1 Enablement

Step 1 - Get the instance

The agent extracts instanceId from request_parameters.

Step 2 - Check the attached IAM role

aws ec2 describe-iam-instance-profile-associations \
  --filters Name=instance-id,Values={{instanceId}}

The agent retrieves the role ARN and checks for admin-level or cross-account policies.

Step 3 - Remediate

Always remediate, regardless of ticket status:

aws ec2 modify-instance-metadata-options \
  --instance-id {{instanceId}} \
  --http-tokens required \
  --http-endpoint enabled

Step 4 - Escalation criteria

  • CDE subnet: escalate
  • High-privilege IAM role (admin, PowerUser, or cross-account AssumeRole): escalate and review CloudTrail for that instance over the exposure window

CQL Hunt Queries

Use these in CrowdStrike NG-SIEM / LogScale to sweep for activity across the full fleet, independent of what Falcon surfaced.

Hunt 1 - CloudTrail tampering

#repo=search-all eventSource="cloudtrail.amazonaws.com"
  (
    eventName="StopLogging"
    OR eventName="DeleteTrail"
    OR eventName="UpdateTrail"
    OR eventName="PutEventSelectors"
  )
| select([
    eventTime,
    eventName,
    userIdentity.arn,
    userIdentity.accessKeyId,
    sourceIPAddress,
    requestParameters
  ])
| sort(eventTime, order=desc)

Hunt 2 - Security group rules opened to internet

#repo=search-all eventSource="ec2.amazonaws.com"
  (
    eventName="AuthorizeSecurityGroupIngress"
    OR eventName="AuthorizeSecurityGroupEgress"
  )
| requestParameters.ipPermissions.items[].ipRanges.items[].cidrIp = "0.0.0.0/0"
  OR requestParameters.ipPermissions.items[].ipv6Ranges.items[].cidrIpv6 = "::/0"
| select([
    eventTime,
    eventName,
    userIdentity.arn,
    requestParameters.groupId,
    requestParameters.ipPermissions,
    sourceIPAddress
  ])
| sort(eventTime, order=desc)

Output and Decision

False Positive

Conditions: Valid Jira change ticket, caller matches authorized implementer, action is within documented scope, logging was restored (CloudTrail), rule was temporary and already removed (SG), or IMDSv1 was re-enabled for a documented legacy workload with no sensitive role attached.

Actions:

  • Set Falcon alert status to closed
  • Document ticket reference and analyst name in the alert notes
  • No further action required

True Positive

Conditions: No change ticket, caller ARN does not match any authorized team, action originated from an external IP outside VPN CIDRs, rule still active (SG), logging still paused (CloudTrail), or IMDSv1 active on a high-privilege or CDE instance.

Actions for authorized operator (by sub-type):

CloudTrail:

  • Restore logging immediately via aws cloudtrail start-logging --name {{trail_arn}}
  • Revoke or rotate the access key used
  • Pull 24 hours of CloudTrail events for that access key
  • Open a P1 incident

Security Group:

  • Revoke the rule via aws ec2 revoke-security-group-ingress or revoke-security-group-egress
  • Pull VPC Flow Logs for the security group during the full exposure window
  • Open a P1 or P2 incident depending on CDE scope

IMDSv1:

  • Run modify-instance-metadata-options --http-tokens required immediately
  • Open a tracking ticket
  • If extended exposure + high-privilege role: pull CloudTrail for that instance and open an investigation

Undetermined

Conditions: Ticket exists but caller does not match, ticket is expired, source IP is ambiguous (shared NAT), or the event is within a change window but request_parameters show unexpected scope.

Actions:

  • Set Falcon alert status to in-progress
  • Page the on-call engineer and the account owner
  • Do not close until a human confirms authorization
  • Document all findings in the alert before handing off

Prerequisites

Access:

System Permission Needed
CrowdStrike Falcon Alerts read/write, Detections read
AWS (per account) cloudtrail:LookupEvents, ec2:DescribeInstances, ec2:DescribeSecurityGroups, ec2:DescribeIamInstanceProfileAssociations, ec2:ModifyInstanceMetadataOptions, ec2:RevokeSecurityGroupIngress, ec2:RevokeSecurityGroupEgress
Jira API token with read access to the change management board
Slack Webhook URL for the on-call security channel

Context (what you feed the harness). The harness needs:

  • Falcon Alerts API reference and field schema
  • CQL/LogScale syntax guide for the version in use
  • CloudTrail event schema for cloudtrail.amazonaws.com and ec2.amazonaws.com sources, or access to ingest
  • Environment context: VPN CIDR ranges, CDE subnet list, AWS account IDs mapped to account names
  • MITRE T1562 sub-technique descriptions for in-prompt classification grounding

Defense evasion triage benefits from codification more than almost any other alert class. Once you encode the decision tables - ticket match, scope check, port risk, logging state - the agent runs the same logic consistently across a volume of alerts that would take a human analyst the better part of a day.

Each run produces a structured audit trail: the raw event, the Jira lookup result, the scope flags, the verdict, and the response actions taken. That trail compounds over time. Future investigations get faster because you can query past verdicts by account, caller ARN, or event type. The workflow itself is tool-agnostic - the same prompt chain runs against any LLM with API access to CrowdStrike, AWS, and Jira.


Next in series: Cloud Impact - triaging data exfiltration and resource abuse detections in AWS.


Building AI-driven detection and triage for your own environment? See how 543HQ designs security automation workflows.

Disclaimer: The AI-assisted workflows described in this article are intended to augment human judgment, not replace it. All agent outputs (verdicts, recommendations, and draft actions) require human review and verification before execution. Use of agentic tooling in security must align with your organization's policies, change management procedures, and applicable compliance requirements.

Luis Torres-Villarreal is a Senior Leader with 15+ years in IT, Information Security, PCI DSS, HITRUST, NIST CSF, and SOC 2 Type II compliance. He writes about AI agents, Security Automation, and the evolution of InfoSec Teams.

Need a hand with this at your company?

543HQ helps startups and growing companies build security programs that actually work. Start with a free 30-minute call.

Book a Free Call