Many cloud data exposures are caused not by a clever exploit but by a setting someone changed, never changed, or did not know existed. An open bucket, a publicly shared snapshot, a security group admitting the internet to port 22, an access key left in a repository for years: each is a one-line error, and each has caused a public breach. This guide catalogues the misconfigurations that matter most across AWS, Microsoft Azure and Google Cloud, how to prevent them with organisation guardrails, infrastructure as code (IaC) scanning and policy as code, and how to detect the rest with posture management and drift detection. It is written for cloud security engineers, platform teams and architects; provider features are named only as documented examples.
Key takeaways
- Misconfiguration is the top-ranked cloud risk: the Cloud Security Alliance's Top Threats to Cloud Computing 2024 puts "misconfiguration and inadequate change control" first, ahead of identity and access management.
- The same short list recurs in breaches: public storage, snapshots and images, wildcard IAM, long-lived keys, open management ports, missing logs, unencrypted data, the old metadata service, broad shared links and default credentials.
- Prevent at the organisation layer first: AWS SCPs and RCPs, Azure Policy and Google Cloud organisation policy constraints stop the worst errors in every account, including ones nobody scans.
- Scan in the pipeline, confirm at runtime: IaC scanners catch errors before deployment; posture management and drift detection catch console changes and resources built outside code.
- Many misconfigurations are identity problems: static keys, wildcard permissions and instance credentials reachable through the metadata service turn one mistake into account-wide access.
Why cloud misconfiguration keeps causing breaches
NSA's Top Ten Cloud Security Mitigation Strategies (March 2024) states that "Many cloud breaches occur due to misconfigurations in cloud tenants." Under the shared responsibility model, every setting on a customer's storage, network rules, roles and keys is the customer's to get right.
- Self-service at speed: any engineer with API rights can create internet-facing resources in minutes, outside change control, which is why the CSA pairs misconfiguration with "inadequate change control".
- Defaults differ by service and age: newer storage blocks public access by default, older resources may not, and NSA notes that "Default logging policies vary greatly between cloud services".
- Expressive policy languages: one
"Principal": "*"in a bucket policy or"Action": "*"on a role grants far more than intended. - Sprawl and no owner: a control enabled in one region or account is absent in the next, and test resources outlive the people who built them.
The most common cloud misconfigurations
| Misconfiguration | Why it is dangerous | Preventive control (examples) | Detect with |
|---|---|---|---|
| Public storage buckets and blobs | Anyone can list or read objects; world-writable buckets let attackers alter content | S3 Block Public Access at organisation level; Azure AllowBlobPublicAccess false; Google Cloud public access prevention | CSPM, anonymous request logs |
| Exposed databases | Unauthenticated or weakly protected data reachable from the internet | Private endpoints; constraints/sql.managed.restrictPublicIp; policy denying public network access | External scans, CSPM |
| Public snapshots and machine images | Disk contents, including secrets, can be copied by any account | EBS block public access for snapshots and block public access for AMIs, per Region | Sharing inventory |
| Wildcard IAM policies | Any compromise becomes an account compromise | Policy validation in pipelines; SCPs; permission boundaries | CIEM, unused access findings |
| Long-lived access keys | Keys leak into code, images and environment files and work until revoked | Workload identity federation; constraints/iam.managed.disableServiceAccountKeyCreation | Key age reports, secret scanning |
| 0.0.0.0/0 on management ports | SSH, RDP and database ports open to brute force and exploits | Policy denying internet ingress to listed ports; session manager or bastion | CSPM, flow logs |
| Disabled or partial logging | No evidence for detection or investigation | Organisation-wide trail member accounts cannot stop; diagnostic settings by policy | Log gap alerts |
| Unencrypted resources | Data readable from copied disks or intercepted traffic | Encryption by default; customer-managed keys for sensitive data; deny non-TLS requests | CSPM |
| Instance metadata service v1 | Request forgery can read instance role credentials | "IMDSv2 only (token required)" as account default | Metadata options inventory |
| Over-broad SAS tokens and presigned URLs | Bearer links with wide scope or long life | User delegation SAS; disallow Shared Key; s3:signatureAge limits | Access logs, secret scanning |
Default credentials on managed services and exposed Kubernetes dashboards complete the list; both are covered under network exposure below.
Storage, snapshots and shared links
Storage exposure leads directly to data loss (ATT&CK T1530 Data from Cloud Storage, often preceded by T1619 Cloud Storage Object Discovery).
- AWS S3: Block Public Access has four settings,
BlockPublicAcls,IgnorePublicAcls,BlockPublicPolicyandRestrictPublicBuckets, at organisation, account, bucket and access point level; the most restrictive combination wins. New buckets block public access by default, so the risk sits in older buckets and in teams that switch it off. Serve genuine public content through a CDN with origin access instead. - Azure Blob Storage: set the account's
AllowBlobPublicAccessproperty to false. If it is allowed, each container can be private, "Container" (anonymous listing and read) or "Blob" (anonymous read of blobs only). Before switching it off, Microsoft suggests queryingStorageBlobLogsforAuthenticationType == "Anonymous"to find what still depends on it. - Google Cloud Storage: enforce public access prevention and uniform bucket-level access, and use domain restricted sharing; Google notes that "By default, all user identities are allowed to be added to IAM policies."
- Snapshots and images: EBS block public access for snapshots is Regional. "Block all sharing" also makes already-public snapshots private; "block new sharing" leaves them public. It "does not prevent the public sharing of EBS-backed AMIs", so enable block public access for AMIs too, through an AWS Organizations declarative policy covering every account and Region. Images built from working servers carry keys and history files: build them from clean pipelines and scan for secrets.
- Write access matters too: the Twilio TaskRouter SDK Compromise 2020 came from a world-writable bucket serving JavaScript to customers.
SAS tokens and presigned URLs
Shared links are configuration, and they are credentials: AWS calls presigned URLs "bearer tokens that grant access to those who possess them."
| Property | Azure shared access signature | AWS S3 presigned URL |
|---|---|---|
| Signed with | User delegation SAS: Microsoft Entra credentials (Microsoft's recommendation). Service and account SAS: the account key | The credentials of the IAM principal that generated it |
| Lifetime | Set by the issuer; a SAS expiration policy warns when service or account SAS exceed it | Up to 7 days (SigV4, IAM user credentials); 12 hours from the console; never beyond temporary credentials |
| Visibility | "It's not possible to audit the generation of SAS tokens" | Generation is local signing; only use is logged |
| Revocation | Change the stored access policy (five per container, service SAS only); otherwise rotate the account key | Revoke or deactivate the generating credential |
| Guardrail | Disallow Shared Key so account-key SAS cannot be issued | Bucket policy denying s3:signatureAge above a limit; aws:SourceIp or aws:SourceVpce |
In the Microsoft SAS Token Exposure 2023, one over-permissive account SAS link published in a public repository exposed 38TB of internal data. Add SAS strings and presigned URLs to secret scanning rules and prefer short, read-only, single-object links.
Where identity fits: keys, roles and the metadata service
The CSA ranks IAM second, and the two risks overlap: most cloud identity weaknesses are settings on non-human identities such as roles, service principals, service accounts and access keys.
- Wildcard and inherited permissions: flag policies granting
*actions or resources, trust policies open to"Principal": "*"or whole external accounts, and default service accounts holding Editor (blocked byconstraints/iam.managed.preventPrivilegedBasicRolesForDefaultServiceAccounts). AWS IAM Access Analyzer reports unused roles, keys and permissions, the cheapest risk to remove. See the Cloud PAM and CIEM Guide. - Long-lived access keys: static keys in code, images and
.envfiles are a standing invitation (ATT&CK T1078.004 Cloud Accounts). The 230 Million AWS Cloud Environments Campaign 2024 harvested keys from exposed environment files, and in the Toyota T-Connect Key Exposure 2022 a key sat on public GitHub for five years. Move to roles, managed identities and workload identity federation, block key creation by policy, and alert on keys past your rotation limit. See the Cloud Workload Identity Guide and Secrets Management Guide. - Instance metadata service: AWS instances accept IMDSv1 or IMDSv2 by default. IMDSv2 needs a session token from a PUT request, rejects token requests carrying
X-Forwarded-For, and its default hop limit of 1 stops tokens being relayed through an extra network hop. Make "IMDSv2 only (token required)" the account default in each Region once no agent still uses v1, because enforcement breaks v1 clients. Azure and Google metadata endpoints require aMetadata: trueorMetadata-Flavor: Googleheader. The Capital One Breach 2019 is the reference case: request forgery through a firewall returned role credentials that could read storage (T1552.005 Cloud Instance Metadata API). - Keys left on hosts: the TeamTNT Worm 2020 stole AWS credential files from Docker hosts with an internet-facing API.
Network exposure, logging, encryption and defaults
Rules allowing 0.0.0.0/0 or ::/0 belong on ports 80 and 443 of a load balancer and almost nowhere else. Put the deny list in policy.
| Service | Default port(s) | Safer access pattern |
|---|---|---|
| SSH / RDP / WinRM | 22 / 3389 / 5985, 5986 | Session manager, MFA bastion or just-in-time opening |
| Kubernetes API server / kubelet | 6443 / 10250 | Private endpoint or authorised network ranges |
| Docker Engine API / etcd | 2375, 2376 / 2379 | Never internet-facing; TLS client authentication |
| MySQL, PostgreSQL, SQL Server | 3306, 5432, 1433 | Private endpoints; public IP denied by policy |
| MongoDB, Redis, Elasticsearch | 27017, 6379, 9200 | Private subnet, authentication on |
- Dashboards and consoles: the Tesla Kubernetes Cryptojacking 2018 began at an open Kubernetes console exposing AWS credentials, and the DeepSeek Database Exposure 2025 was an open ClickHouse database holding chat logs and API secrets. See the Kubernetes NHI Security Guide.
- Default credentials: marketplace images, self-hosted databases and admin panels can ship with known or empty passwords or authentication off. Require credentials in the template and scan for default logins after deployment.
- Logging: Google Cloud Data Access audit logs are disabled by default except for BigQuery, Azure resource logs need a diagnostic setting, and CloudTrail event history keeps only 90 days of management events. Run an organisation-level trail member accounts cannot stop, in a separate log account, and alert on changes to it (T1685 Disable or Modify Tools, Defense Impairment in ATT&CK v20). See the Log Management and Retention Guide.
- Encryption: S3 applies SSE-S3 default encryption to every bucket, and EBS encryption by default can be enabled per Region. Use customer-managed keys where you need key-level access control or crypto-shredding, and deny non-TLS requests with
aws:SecureTransportor equivalents. See the Encryption Guide.
Prevention: guardrails, IaC scanning and policy as code
| Layer | Acts when | Examples | Strength | Limit |
|---|---|---|---|---|
| Organisation guardrails | Any API call | AWS SCPs and RCPs; Azure Policy deny; Google Cloud constraints | Cannot be bypassed by console or scripts | Coarse; a wrong deny breaks production |
| IaC scanning | Pull request | Checkov, Trivy | Cheapest fix, in the developer's context | Blind to console changes and apply-time values |
| Plan-time policy as code | Before apply | Rego (OPA, Conftest) on Terraform plan JSON | Sees resolved values | Only covers pipeline deployments |
| Admission control | Kubernetes object creation | Pod Security Admission, policy engines | Covers in-cluster objects | Per cluster |
| Posture and auto-remediation | After deployment | CSPM, Azure Policy modify and deployIfNotExists, AWS Config rules | Catches legacy and out-of-band resources | Exposure exists until fixed |
Organisation guardrails
- AWS: SCPs set the maximum permissions for principals in member accounts and grant nothing; RCPs cap what principals outside the organisation can do to your resources. Use them to deny disabling Block Public Access, stopping the organisation trail and launching instances that allow IMDSv1. They do not restrict the management account, so keep workloads out of it.
- Azure: Azure Policy evaluates
disabled, thenappendandmodify, thendeny, thenaudit; layered assignments are "cumulative most restrictive". Assign at management group scope, start inauditor enforcement modeDoNotEnforce, and move todenywhen compliance is clean. - Google Cloud: constraints such as
iam.managed.disableServiceAccountKeyCreation,iam.managed.disableServiceAccountKeyUpload,compute.managed.vmExternalIpAccess,compute.managed.requireOsLoginandsql.managed.restrictPublicIpenforce common controls at organisation or folder level.
IaC scanning and policy as code
- Scanners: Checkov scans Terraform, CloudFormation (including SAM), ARM, Serverless framework, Helm, Kubernetes and Dockerfiles with "more than 750 predefined policies" and graph-based checks across connected resources. Trivy's
trivy configcovers Terraform, CloudFormation, ARM, Helm, Kubernetes and Dockerfiles. tfsec's maintainers "encourage the tfsec community to transition over to Trivy", so do not start new pipelines on tfsec. - Gate on a short list: fail builds on public storage, open management ports, wildcard IAM, unencrypted storage and IMDSv1; report the rest. Record suppressions in code with a reason and expiry.
- Protect Terraform state: state can hold generated passwords and keys in plain text. Keep it in an encrypted, locked remote backend readable only by the pipeline identity.
- Pipeline identity: the deployment role is the most privileged NHI in the estate; federate it from CI with short-lived tokens. See the CI/CD Pipeline Identity Security Guide.
Detection: posture management, drift and ownership
- Posture management: CSPM evaluates configuration continuously against benchmarks. CIS publishes "prescriptive configuration recommendations" as consensus-based, vendor-neutral benchmarks, including Foundations benchmarks for AWS, Azure, Google Cloud, Oracle, Alibaba and IBM clouds, service benchmarks, and EKS, AKS and GKE benchmarks. See the CNAPP Guide.
- Drift detection: NSA notes that "IaC allows organizations to quickly detect unauthorized changes to infrastructure." CloudFormation marks stacks
DRIFTED,IN_SYNCorNOT_CHECKEDand resourcesMODIFIEDorDELETED, but only for properties set explicitly in the template, not nested stacks or unsupported types. Terraform users can scheduleterraform plan -refresh-only. Treat security-relevant drift as an incident until explained, and fix it in code. - External view: scan your own IP ranges and DNS names for open ports, dashboards and storage endpoints. See the Attack Surface Management Guide.
- Ownership: require
owneranddata-classificationtags by policy at creation, and route each finding to the owning team with a due date by severity. - Alert on: bucket and infrastructure enumeration (T1580 Cloud Infrastructure Discovery, T1619), storage made public, new public snapshot shares, rules opening management ports, and key use from new networks.
Metrics that show it is working
- Public exposure count: anonymously reachable storage, snapshots, images and databases outside the approved exception list.
- Guardrail coverage: share of accounts, subscriptions and projects under the baseline.
- Long-lived keys: active access and service account keys, and the share older than 90 days.
- Time to remediate: median days to fix critical misconfigurations.
- IaC coverage and drift: share of production resources deployed by pipeline, and drift findings per week.
Implementation roadmap
- Baseline (weeks 1-4): enable native posture management in every account and region, run the CIS Foundations benchmark, and list public storage, public snapshots, open management ports and access keys by age.
- Close public exposures: confirm intended public resources with owners using anonymous access logs, then enable public access blocks at account level, then organisation level.
- Guardrails in audit mode: assign Azure Policy as
auditorDoNotEnforce, attach SCPs and organisation policies to a test OU or folder, and review would-be blocks for two to four weeks. - Enforce in rings: sandbox, then non-production, then production. Roll back by detaching the policy or returning it to audit, and keep a documented break-glass path.
- IaC gates: run Checkov or Trivy in report-only mode, then fail builds on the critical list.
- Retire static keys: move workloads and pipelines to federation, then block key creation with a reviewed exception list.
- Operate: schedule drift detection, route findings to owners and report metrics monthly.
Decision guidance
- Preventive or detective: deny outright what is almost never legitimate (public snapshots, IMDSv1, disabling the audit trail); detect and remediate where exceptions are common (public website buckets, partner sharing).
- Native or third-party: single-cloud organisations get most value from native posture services; multi-cloud estates benefit from one policy language and one findings queue.
- Small versus large: a small team can remove most risk with a landing zone template and a few organisation settings (public access blocks, IMDSv2 default, organisation trail, no key creation). Large estates need policy as code with version control, tests and staged rollout, because guardrails become production change.
Common failure patterns
- Fixing the console, not the code: a finding is closed by hand and the next deployment reintroduces it.
- Guardrails in one region only: snapshot and AMI blocks, IMDS defaults and EBS encryption by default are Regional; an unused region becomes the gap.
- Treating shared links as harmless: account-key SAS tokens and week-long presigned URLs end up in tickets and repositories, as in the Microsoft SAS Token Exposure 2023.
- Keys that never die: the Imperva Breach 2019 combined an exposed internal instance with an AWS API key that should not have been there.
- Logging assumed, not verified: data access logs were never enabled, so nobody can say what was read.
- Exceptions without expiry: suppressions and policy exemptions accumulate until the guardrail protects little.
Framework mapping
| Area | NIST CSF 2.0 | SP 800-53 Rev. 5 | CIS Controls v8.1 | ISO/IEC 27001:2022 | ATT&CK v20 |
|---|---|---|---|---|---|
| Configuration baseline and change control | PR.PS-01 | CM-2, CM-6, CM-7 | 4.1 | A.8.9, A.5.23 | T1578 |
| Public storage and data protection | PR.DS-01 | AC-3, SC-28 | 3.3, 3.11 | A.8.24 | T1530, T1619 |
| Least privilege and keys | PR.AA-05 | AC-6, IA-5 | 6.8 | A.5.15, A.5.17 | T1078.004, T1552.005 |
| Network exposure | PR.IR-01 | SC-7 | 4.4, 12.2 | A.8.20 | T1190 |
| Default credentials | PR.AA-01 | IA-5 | 4.7 | A.5.17 | T1078.004 |
| Logging and monitoring | PR.PS-04, DE.CM-09 | AU-2, AU-12, CA-7 | 8.2 | A.8.15, A.8.16 | T1685 |
Practitioner checklist
- Enable storage public access blocks at organisation or account level in every cloud.
- Block public sharing of snapshots and machine images in every Region by organisation policy.
- Make "IMDSv2 only (token required)" the default and deny launches allowing IMDSv1.
- Deny 0.0.0.0/0 and ::/0 ingress to management and database ports.
- Run an organisation-level audit trail member accounts cannot stop, plus data access logs for sensitive stores.
- Replace static keys with federation, block new key creation and alert on keys older than 90 days.
- Use user delegation SAS, disallow Shared Key and cap presigned URL age with
s3:signatureAge. - Scan IaC in every pull request with a critical-only gate, and lock down Terraform state.
- Schedule drift detection and fix drift in code.
- Require owner tags and route every finding to an owner with a due date.
Standards and references
- NSA: Top Ten Cloud Security Mitigation Strategies
- Cloud Security Alliance: Top Threats to Cloud Computing 2024 Report
- Center for Internet Security: CIS Benchmarks
- Microsoft Learn: Grant limited access to Azure Storage resources using shared access signatures
- Microsoft Learn: Remediate anonymous read access to blob data
- AWS: Download and upload objects with presigned URLs
- AWS: Block public access for Amazon EBS snapshots
- Google Cloud: Organization policy constraints
Related NHI Mgmt Group resources: CNAPP Guide · Cloud Workload Identity Guide · Cloud PAM and CIEM Guide · Secrets Management Guide · Attack Surface Management Guide