Cloud Penetration Testing: Our Methodology for AWS, Azure, and GCP
Our cloud penetration testing methodology for AWS, Azure, and GCP: IAM abuse, misconfig, exposed storage, SSRF to metadata, privilege escalation, logging.

Hand us a read-only IAM role that someone over-provisioned, and there is a decent chance we walk it up to full account control before your standup ends. The cloud provider is not broken when that happens. Somebody attached a policy with a wildcard action, left a role assumable by half the internet, and stopped reading CloudTrail sometime last quarter. The whole cloud penetration testing methodology in this article lives in that gap, the one between “the platform is secure” and “our configuration is secure.”
What follows is the sequence we actually run on AWS, Azure, and GCP work. It is not a compliance checklist reformatted as prose, but the order we test in, the tooling we reach for, and the misconfigurations that keep paying out engagement after engagement.
One framing note. Cloud testing is a permission-model problem before it is a network problem. On-prem you fight firewalls and segmentation. Here you fight IAM policies, trust relationships, and metadata endpoints. Run it like a classic external network test and you will sail straight past the things that actually get accounts owned.
Key takeaways
- A cloud penetration testing methodology is identity-first: IAM policies and trust relationships are the primary attack surface, well ahead of anything at the network layer.
- Four findings dominate our reports: over-permissive IAM policies, publicly exposed storage (S3, Blob, GCS), SSRF that reaches the instance metadata service, and privilege escalation through policy or role misconfiguration.
- Scope and written authorization matter more here than in any other test. You are working inside a shared-responsibility boundary, so you need both the provider’s rules and the account owner’s sign-off before you touch anything.
- IMDSv2, least-privilege policies, blocked public access on storage, and monitored logging (CloudTrail, Azure Monitor, Cloud Logging) close most of what we find.
- CSPM scanners flag misconfigurations one at a time. They do not chain three of them into account takeover. That chaining is the entire point of a manual test.
What is cloud penetration testing, and how is it different?
Cloud penetration testing is an authorized attack simulation against the cloud environment you own: the accounts, identities, services, and configurations sitting inside AWS, Azure, or GCP. The provider secures the hardware, hypervisor, and physical layer. You own everything you configure on top: IAM, storage permissions, network security groups, key management, logging. That split is the shared responsibility model, and it draws the line around what we are permitted to test.
The practical difference from a traditional pentest is that the perimeter is soft and the identity plane is enormous. A single leaked access key, a sloppy OIDC trust for a CI pipeline, or a Lambda carrying an attached admin role can matter far more than any open port. So the methodology is built around identity, trust, and configuration, not around scanning a CIDR range.
Step 1: Scope, authorization, and rules of engagement
Before a single command runs, we pin down three things. Which accounts and subscriptions are in scope. What kind of test it is, external with no credentials or an authenticated “assumed breach” starting from a low-privilege identity. And what the provider actually allows. AWS, Azure, and GCP each publish acceptable-use terms for security testing. Most common services no longer need pre-approval, but denial-of-service testing, sustained heavy load, and certain managed services still carry limits. We stay inside them.
The most useful cloud tests we run are authenticated. We ask for a deliberately weak identity: a read-only IAM user, a basic Entra ID account, a GCP service account with minimal roles. Then we see how far it goes. That models the realistic threat, which is a phished employee, a key leaked in a public repo, or a compromised third-party integration, not a faceless attacker starting from nothing. External unauthenticated work has its place for attack-surface mapping. The interesting escalation almost always lives after that first foothold.
Step 2: Enumerate identity, because that is the real attack surface
With a foothold in hand, the first job is answering two questions: who are we, and what can we become? On AWS it starts plainly.
aws sts get-caller-identity
aws iam get-account-authorization-details # if permitted
aws iam list-attached-user-policies --user-name svc-ci
Then we map the identity graph. Pacu and ScoutSuite give us broad AWS coverage, and PMapper turns a heap of JSON policies into a straight answer about which principal can reach admin. On Azure we lean on AzureHound and the wider BloodHound ecosystem to graph directory roles, group nesting, and eligible PIM assignments. On GCP we walk the resource hierarchy by hand and read role bindings at the org, folder, project, and resource level, because a binding inherited from a parent is trivially easy to miss with the eye.
What we hunt at this stage: wildcard actions like "Action": "*" or a service-wide iam:*, roles with permissive sts:AssumeRole trust policies, and any path that lets a weak identity grant itself more. A policy that permits iam:PassRole next to a compute-create permission is not a theoretical concern. It is a working escalation primitive.
Step 3: IAM privilege escalation
This is where cloud engagements are won or lost. The AWS escalation paths Rhino Security Labs documented years ago still land in live accounts, because teams keep granting the ingredient permissions without noticing what they add up to. A few we check every single time:
- iam:PassRole plus compute create. If we can pass an admin role to a fresh EC2 instance, Lambda function, or Glue job, we run our own code under that role and read its credentials. Instant escalation.
- iam:CreatePolicyVersion or AttachUserPolicy. If our user can edit or attach policies, it can attach AdministratorAccess to itself. Game over.
- Assumable roles with loose trust. A role trusting
"Principal": {"AWS": "*"}, or a broad account root, is a door left standing open.
The Azure and GCP equivalents are every bit as productive. On Azure we look for custom roles carrying Microsoft.Authorization/roleAssignments/write, service principals with excessive Graph permissions, and Automation Account runbooks or managed identities we can hijack. On GCP the reliable primitives are iam.serviceAccounts.getAccessToken (mint a token for a stronger service account), iam.serviceAccountKeys.create, and setIamPolicy at the project level. Any one of them turns a modest foothold into project ownership.
Step 4: SSRF to the instance metadata service
The highest-value chain in cloud testing is a server-side request forgery bug in an app that can reach the metadata endpoint. Point that SSRF at the link-local metadata address and try to read the attached role’s temporary credentials.
http://169.254.169.254/latest/meta-data/iam/security-credentials/
# then, with the role name that comes back:
http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name>
On a legacy IMDSv1 host that hands back an AccessKeyId, a SecretAccessKey, and a session token, we export them and use them directly. This is the pattern behind one of the most widely studied cloud breaches on record, and why we push so hard on IMDSv2. The equivalent endpoints exist elsewhere: Azure at 169.254.169.254/metadata/identity/oauth2/token with a Metadata: true header, and GCP at metadata.google.internal with Metadata-Flavor: Google. Then we map how far that identity reaches. This technique maps cleanly to MITRE ATT&CK T1552.005, unsecured credentials from the cloud instance metadata API.
Step 5: Exposed storage and public data
Publicly readable object storage is still one of the most common serious findings we write up. We enumerate S3 buckets, Azure Blob containers, and GCS buckets tied to the target, read their ACLs and bucket policies, and test for public list and read access. Then we test for public write, which is the one people forget. Public write on a bucket that serves site assets or software updates is not a data-exposure problem. It is a supply-chain one.
Storage is only half of it. We also sweep for exposed secrets: access keys committed to public repos, keys baked into mobile app bundles, tokens sitting in front-end JavaScript, and overly readable Secrets Manager or Key Vault entries. One valid long-lived key can change the shape of the entire engagement.
Step 6: Network, services, and lateral movement
Only after identity do we care about the network. We review security groups and NSGs for open ingress, the usual SSH and RDP exposed to 0.0.0.0/0, databases hanging off the public internet, then check public RDS or managed-database endpoints and how segmentation behaves across VPCs, subnets, and peering. From a compromised identity or host, we test movement. Can we reach internal services? Assume roles into other accounts? Pivot from a dev subscription into prod through a shared identity? Multi-account and multi-subscription trust boundaries tend to be softer than the architecture diagram suggests.
Step 7: Did anyone see us?
Here is a finding we care about as much as any exploit: did the environment notice? We confirm that CloudTrail is on in all regions with log file validation, that Azure Monitor and Activity Logs are collecting, and that GCP Cloud Audit Logs are enabled, centralized, and alerting on the actions we just performed. An attacker who creates an access key, disables logging, and exfiltrates data should trip something. On plenty of engagements, nothing fires at all. We report that as a detection gap, and we do not soften it, because prevention eventually fails and detection is the backstop.
How do you prevent what we find?
Least privilege is the whole game. Scope IAM policies to specific actions and resources, delete the wildcards, and use permission boundaries and service control policies to cap what any identity can reach. Enforce IMDSv2 on every instance so a stray SSRF cannot mint credentials. Turn on account-wide public-access blocks for S3, keep Blob and GCS private by default, and verify it rather than trusting the console default. Favor short-lived federated credentials over long-lived keys, and rotate the keys you genuinely cannot avoid. And make logging real: centralized, tamper-evident, and wired to alerts a human or a SIEM will act on. A log nobody reads is theater.
How CyberXplore helps
Our cloud penetration testing service runs this exact methodology against your AWS, Azure, and GCP environments. Identity-first, manual, and focused on chaining misconfigurations into the impact a real attacker would reach, not on printing a list of CSPM alerts. You get findings ranked by exploitability, reproduction steps you can hand to engineering, and a free retest once you remediate. If you want a scoped test of your cloud footprint, get a quote and we will map the engagement to your accounts and to the provider’s rules of engagement.
FAQ
Is cloud penetration testing allowed by AWS, Azure, and GCP?
Yes, within limits. All three providers permit testing of your own resources for most common services without prior approval, and each restricts denial-of-service testing and certain managed services. We work inside the provider’s current published acceptable-use policy for whatever is in scope, and we require written authorization from the account owner before we start.
What is the difference between a CSPM scan and a cloud penetration test?
A cloud security posture management tool continuously flags misconfigurations against a rule set, which is useful, but it reports each issue in isolation. A penetration test chains those issues together, so a read-only role plus a PassRole permission plus an SSRF becomes a demonstrated account takeover. We use scanners for coverage and manual testing for impact.
Do you need credentials, or can you test from outside?
Both are valid and they answer different things. An external, unauthenticated test measures your exposed attack surface. An authenticated “assumed breach” test, starting from a low-privilege identity, tends to surface the escalation and lateral-movement paths that matter most. For cloud work we usually recommend the authenticated approach.
How long does a cloud penetration test take?
It depends on account count, service breadth, and whether it is single or multi-cloud. A single well-scoped AWS account runs shorter than a multi-account org with Azure and GCP in the mix. Scope drives the timeline, which is why we size each test individually instead of quoting a flat number.
What are the most common cloud findings you report?
Over-permissive IAM policies and privilege-escalation paths lead by a wide margin, followed by publicly exposed storage, SSRF that reaches the instance metadata service, and inadequate or unmonitored logging. On their own they range from medium to high severity. Chained together, they routinely become criticals.



