Skip to content
CloudSecOps

AWS security assessment and penetration testing

We audit AWS the way it is actually built — principals, Organizations boundaries, workload roles, and the data paths between them — and hand back the escalation paths we can demonstrate, each with the policy, SCP, or Terraform change that closes it.

When you need this

  • Half the estate moved onto EKS. Pods take roles through IRSA or Pod Identity, and nobody can say what a compromised container reaches beyond its own namespace.

  • IAM grew with the company. There are hundreds of roles, some belonging to people who left, and nobody can say who can reach production data.

  • We split into a dozen accounts under Organizations and wrote SCPs from a blog post. We've never tested whether they stop anything.

  • GuardDuty and Security Hub are switched on, findings pile up in a console nobody opens, and we can't tell whether a real intrusion would look any different from the noise.

What we do

01

IAM as an attack graph, not an inventory

We enumerate every principal, trust policy, permission boundary, and inline policy across the accounts in scope, then trace the escalation primitives that matter: iam:PassRole paired with ec2:RunInstances, lambda:CreateFunction, or cloudformation:CreateStack; iam:CreatePolicyVersion or iam:AttachUserPolicy pointed at your own principal; ssm:SendCommand onto an instance wearing a better role. Federation gets the same treatment. A GitHub Actions OIDC trust policy that matches a wildcard sub claim, or omits the aud condition, hands your account to anyone who can open a pull request. IAM Access Analyzer external-access and unused-access findings are a starting point we verify by hand, not the answer.

02

Account boundaries, tested rather than assumed

We read the Organizations layout the way an attacker sitting in one account would: which SCPs and resource control policies apply where, what each OU inherits, and which principals sit outside the boundary — service-linked roles, and the management account, where SCPs never applied in the first place. We check that cross-account trust is as narrow as it looks, that third-party vendor roles carry a real external ID, and that the data-perimeter conditions are on the policies that can enforce them: aws:PrincipalOrgID on the resource policies deciding who may call in, aws:ResourceOrgID in identity policies and SCPs deciding where your own credentials may send data. Where Control Tower or a landing zone set guardrails, we test for drift instead of assuming the control still exists.

03

Workload identity, secrets, and keys

Compute is where an application bug becomes an IAM problem. On EKS we look at IRSA and Pod Identity assignments, node instance-role blast radius, EKS access entries or a stale aws-auth ConfigMap, and whether the IMDSv2 hop limit lets a pod read the node role's credentials. On ECS we look for task roles carrying permissions the execution role should hold, and who can reach the task credentials endpoint. Lambda gets execution-role scope, resource policies with open principals, function URLs left on AuthType NONE, and secrets sitting in environment variables. Then the keys themselves: SSM parameters stored as String rather than SecureString, Secrets Manager resource policies, and KMS key policies, which decide decryption regardless of what IAM says — checked for kms:ViaService conditions, cross-account grants, and keys protecting data three accounts away.

04

Data paths, egress, and whether you would see it

S3 is rarely public any more and still rarely private. We check Block Public Access at account and bucket level, Object Ownership and leftover ACLs, access point and bucket policies that trust an entire organization, replication into accounts outside it, and presigned URLs minted by long-lived credentials. Egress gets the same read: interface and gateway endpoints without endpoint policies, NAT paths to anywhere, snapshots and AMIs shared beyond the account. Then we turn around and ask what the environment recorded — organization CloudTrail coverage including the S3 and Lambda data events that are off by default, Config recorders missing in the regions nobody uses, and which GuardDuty protection plans are genuinely enabled across S3, EKS runtime, malware, RDS, and Lambda.

What you receive

  • An IAM escalation map: which principals reach which roles, in which accounts, and the exact API calls that get them there
  • Findings per account with evidence, severity, and the AWS-native fix — policy JSON, an SCP or RCP, or a Terraform change
  • A boundary review of your Organizations layout, including what your SCPs and RCPs do not cover
  • A detection-coverage table mapping the API calls we made against what CloudTrail, Config, GuardDuty, and Security Hub actually recorded
  • Remediation sequenced by blast radius, separating what you can ship this week from what needs a migration
  • A retest that re-runs each path and marks every finding closed or still open, with the evidence

How it runs

  1. Scope and access

    days

    Accounts and regions in scope, rules of engagement agreed, fixed price set. You deploy a scoped read-only role, usually by CloudFormation StackSets across the organization, with credentials you can revoke.

  2. Assess

    1–3 weeks

    Automated enumeration across accounts and regions, then manual path analysis and controlled validation. Criticals reach you the day we confirm them.

  3. Report and readout

    days

    Written findings, the escalation map, and a working session with the engineers who will make the changes.

  4. Retest

    included

    We re-run the paths against your fixes and update each finding's status.

Durations are indicative. Actual scope and price are fixed after the scoping call.

Questions we get asked

Is this an audit, an assessment, or a penetration test?
One engagement covers all three in practice: configuration review across the organization, then validated exploitation of the paths that matter, so findings are proven rather than flagged. What it is not is a compliance attestation. We are not an accredited audit firm, we do not issue SOC 2 or ISO opinions, and if a customer needs a signed report from a licensed auditor you will need that as well as this.
What access do you need, and how does that work across dozens of accounts?
A read-only role you create and can revoke, typically deployed organization-wide by CloudFormation StackSets and assumed with an external ID. SecurityAudit and ViewOnlyAccess cover most of it; we send you the short list of extra read permissions we need and why each one is there. Anything that changes state — creating a throwaway role to prove an escalation path works, for example — is agreed in writing first and reverted after. Account count moves the price far less than environment complexity does, because enumeration is automated.
What is in scope, and what do you not test?
The accounts and regions you name, and the AWS services actually in use there: IAM and Organizations, S3, EKS and ECS, Lambda, RDS, KMS and Secrets Manager, networking, and the logging stack. What we do not do is application security testing of the code running inside those workloads — source review and business-logic flaws in your web tier are a different engagement, and when a path we are following runs into an application bug we say so and stop at that boundary. We also work inside the AWS Customer Support Policy for Penetration Testing: the permitted-services list covers this work, and anything it excludes, such as simulated denial-of-service, needs AWS approval first and is normally out of scope.
How much of this is automated, and who writes the findings?
Automation does what it is good at: inventory and enumeration across every account and region, correlating policies into an identity graph, first-pass triage. From there an engineer builds the threat model, decides which paths are worth chasing, validates each one by hand, and writes the finding — including the ones the tooling ranked as noise and the ones it never had the context to see. We have worked on AWS since 2018. Nothing reaches the report that an engineer has not confirmed in your environment.