SCENARIO 09 AWS IAM Least Privilege CloudTrail

AWS IAM Least Privilege & Role Assumption

Cloud expansion into AWS required establishing a baseline identity architecture before any workloads were deployed. Zero standing admin access implemented via time-bound role assumption with ExternalId trust boundary, explicit Deny on all IAM write actions, and CloudTrail audit trail capturing every AssumeRole event for SOC 2 compliance.

AWS IAM Least Privilege STS AssumeRole CloudTrail IAM Policies SOC 2 CC6.3

Business Problem

IDSentinel Solutions' cloud expansion into AWS required establishing a baseline identity architecture before any workloads were deployed. The Security team mandated that no human or service identity operate with standing administrative access — all access must follow least-privilege principles, and any privilege elevation must occur through time-bound role assumption with a full audit trail captured via CloudTrail.

An internal review confirmed that without enforced role assumption boundaries, a compromised service credential would grant unrestricted access to IAM and other AWS services — a direct violation of IDSentinel's Zero Trust initiative.

Risk

  • Service identities with standing admin access create permanent blast radius
  • No audit trail for privilege elevation without CloudTrail enforcement
  • Compromised long-lived credentials grant unrestricted AWS access
  • Non-compliant with IDSentinel's Zero Trust and least-privilege mandate
  • Potential compliance exposure under SOC 2 Type II CC6.3 controls

Solution Design — 4 Workstreams

WS 1

IAM Identities

Service user created with programmatic-only access and no inline permissions. All permissions assigned via group membership for consistent policy application.

WS 2

Least-Privilege Policy

Custom IAM policy with explicit ReadOnly grants and explicit Deny on all IAM write actions — ensuring even a misconfiguration cannot grant write access to the identity plane.

WS 3

Role Assumption with Trust Boundary

IAM role with scoped trust policy restricting assumption to a single principal with an ExternalId condition — preventing confused deputy attacks.

WS 4

CloudTrail Audit

Trail enabled across all regions capturing AssumeRole events — tamper-evident audit log for compliance and incident response.

Implementation

  • 01

    Create IAM Identities

    Service user svc-idsentinel-reporter created with programmatic-only access (no console login). Added to group GRP-IAMReporters — policy assigned at group level, not inline, for consistent governance.

  • 02

    Deploy Least-Privilege Policy

    Custom policy IDSentinel-ReadOnly-Policy created with explicit Allow on IAM read actions and explicit Deny on all IAM write actions. Attached to GRP-IAMReporters — inherited by all group members. Explicit Deny overrides any conflicting Allow — defense in depth.

  • 03

    Create IAM Role with Scoped Trust Policy

    Role Role-IDSentinel-Auditor created with trust policy restricting assumption to svc-idsentinel-reporter only, enforced by ExternalId condition IDSentinel-Lab-2026 to prevent confused deputy attacks.

  • 04

    Enable CloudTrail

    Trail IDSentinel-AuditTrail created across all regions with management events (Read + Write) logged to S3 bucket idsentinel-cloudtrail-logs.

  • 05

    Assume Role via AWS CLI

    bash — STS Role Assumption
    # Verify baseline identity (user, not role)
    aws sts get-caller-identity --profile idsentinel-reporter
    
    # Assume the role with ExternalId condition
    aws sts assume-role \
      --role-arn "arn:aws:iam::ACCOUNT_ID:role/Role-IDSentinel-Auditor" \
      --role-session-name "IDSentinel-AuditSession-01" \
      --external-id "IDSentinel-Lab-2026" \
      --profile idsentinel-reporter
    
    # Export temporary credentials
    export AWS_ACCESS_KEY_ID=<AccessKeyId>
    export AWS_SECRET_ACCESS_KEY=<SecretAccessKey>
    export AWS_SESSION_TOKEN=<SessionToken>
    
    # Confirm identity is now the ROLE, not the user
    aws sts get-caller-identity
  • 06

    Validate Least-Privilege Enforcement

    bash — Read/Write enforcement test
    # Should SUCCEED — allowed by ReadOnly grant
    aws iam list-users
    
    # Should FAIL — blocked by explicit Deny
    aws iam create-user --user-name test-deny-check
    # → AccessDenied confirmed ✅
  • 07

    CloudTrail Audit Evidence

    AssumeRole event captured in CloudTrail Event History with full session metadata — principal ARN, session name, ExternalId, source IP, and timestamp — providing complete audit trail for SOC 2 CC6.3 compliance documentation.


Outcome

IAM service user created with programmatic-only access — no console login, no standing permissions
Explicit Deny on all IAM write actions — AccessDenied on iam:CreateUser confirmed
Role assumption with ExternalId condition — confused deputy attack vector closed
Temporary STS credentials used throughout — zero long-lived credentials at any point
CloudTrail AssumeRole event captured with full session metadata as SOC 2 audit evidence
Zero standing administrative access granted at any stage of implementation

Implementation Results

MetricValue
IAM users created1 (programmatic only — no console access)
IAM groups created1 (GRP-IAMReporters)
IAM roles created1 (Role-IDSentinel-Auditor)
Trust policy scopeSingle principal + ExternalId condition
Policy typeCustom — explicit Allow + explicit Deny
Least-privilege violations tested1 (iam:CreateUser → AccessDenied confirmed)
Credential type usedTemporary STS credentials (time-bound)
Long-lived credentials used0
CloudTrail events capturedAssumeRole with full session metadata
Permanent admin access granted0

Files

  • policies/IDSentinel-ReadOnly-Policy.jsonLeast-privilege IAM policy — ReadOnly grant + explicit Deny on all write actions
  • diagrams/aws-iam-flow.pngArchitecture and role assumption flow diagram
  • screenshots/Evidence across all 7 implementation steps — IAM config, CLI role assumption, Deny enforcement, CloudTrail event