A single resource policy that names "everyone" as a principal turns a private bucket, queue, key or function into an internet service, and most estates hold far more resource policies than anyone reviews. Storage is where teams usually look first, but the same pattern applies to message queues, topics, encryption keys, secrets, serverless functions and snapshots. This guide is a task runbook: how to find anonymous and all-authenticated grants across resource types in AWS, Azure and Google Cloud with each provider's own tooling, how to decide which ones are intended, and how to close the rest and stop them coming back. It is for cloud security and platform engineers. Platforms are listed alphabetically; the order is not a ranking. For incident handling when exposed data may already have been read, use the Cloud Storage Exposure Playbook.
Key takeaways
- Audit by principal, not by service. Search for the public principal values (
"*" in AWS, anonymous access settings in Azure, allUsers and allAuthenticatedUsers in Google Cloud) across every resource type at once, then group by service.
- Some public access is not in the policy. A Google Cloud Run service can be public with the invoker IAM check turned off, an Azure Functions HTTP trigger can use the
anonymous authorisation level, and an Azure static website container is always publicly readable. Check these settings as well as the policies.
- "All authenticated" is still public. In Google Cloud,
allAuthenticatedUsers means any signed-in Google account, not your organisation.
- Every intended exposure needs an owner and a record. Archive or label it with a reason, so that a new finding means a new change.
- Prevention is an organisation-level setting. S3 Block Public Access, Azure Policy with a deny effect on anonymous blob access, and Google Cloud domain restricted sharing stop most new grants before they exist.
Where public access hides
| Resource class | AWS | Azure | Google Cloud |
| Object storage | S3 bucket policy, ACL or access point policy; Block Public Access overrides them | Storage account AllowBlobPublicAccess plus container access level (Private, Blob, Container); $web static website container | Bucket IAM with allUsers or allAuthenticatedUsers; public access prevention setting |
| Queues and topics | SQS queue policy; SNS topic policy | Service Bus authorises with Microsoft Entra ID or shared access signatures; review who holds those | Pub/Sub topic and subscription IAM |
| Keys and secrets | KMS key policy; Secrets Manager resource policy | Key Vault access through Azure RBAC or access policies; review assignments | Cloud KMS key IAM; Secret Manager secret IAM |
| Functions and services | Lambda function and layer resource policies | Functions HTTP trigger authLevel | Cloud Run invoker IAM, or invoker IAM check disabled |
The table lists where to look, not a judgement of any platform. Azure data plane access for queues, keys and secrets is granted through Microsoft Entra ID roles and signed tokens rather than resource policies with a public principal, so the Azure audit focuses on anonymous settings and on who holds keys and tokens. See the Azure Storage Security Guide for the account key and SAS side.
Before you start
- Read-only access: an audit identity in each platform with read access to resource configuration and IAM, and no write rights.
- Coverage: list every AWS account and Region in use, every Azure subscription, and the Google Cloud organisation ID. Public findings in an unmonitored Region or subscription are the ones that last.
- Intended exposures: collect the known public assets (website content, public datasets, software downloads, webhooks) with their owners before you start, so they can be labelled rather than argued about.
- Rollback: export each resource policy or IAM policy before changing it; that file is the restore path.
Step-by-step: AWS
- Create an external access analyzer in every Region you use. IAM Access Analyzer is Regional for external access. In the IAM console, create an external access analyzer with your organisation as the zone of trust (from the management or delegated administrator account) or with the current account. The analyzer covers S3 buckets and directory buckets, IAM roles, KMS keys, Lambda functions and layers, SQS queues, Secrets Manager secrets, SNS topics, EBS snapshots, RDS DB and cluster snapshots, ECR repositories, EFS file systems and DynamoDB tables and streams.
- List public findings. The
isPublic filter key (shown as Public access in the console) marks findings where a policy allows public access:
aws accessanalyzer list-findings-v2 \
--analyzer-arn arn:aws:access-analyzer:REGION:ACCOUNT_ID:analyzer/NAME \
--filter '{"isPublic": {"eq": ["true"]}, "status": {"eq": ["ACTIVE"]}}'
Add "resourceType": {"eq": ["AWS::SQS::Queue"]} and similar to work one type at a time.
- Know the timing. AWS says analysis can take up to 30 minutes after a policy change, account-level S3 Block Public Access settings are evaluated every 6 hours, and resource control policy changes are picked up in the periodic scan within 24 hours. For Lambda, findings come from function and layer policies; policies on aliases and on versions invoked with a qualified ARN are not reported, so review those separately.
- Triage. For each finding, confirm the owner and whether public access is intended. Archive intended ones with an archive rule scoped by resource and a documented reason; everything else is a fix.
- Fix. Remove the public statement or add a condition (for example
aws:PrincipalOrgID or aws:SourceArn) and turn on S3 Block Public Access at account level. Before deploying a corrected policy, test it with aws accessanalyzer check-no-public-access --resource-type AWS::SQS::Queue --policy-document file://queue-policy.json; FAIL means the policy might still allow public access.
Step-by-step: Azure
- Find storage accounts that allow anonymous access. Microsoft's Azure Resource Graph query:
resources
| where type =~ 'Microsoft.Storage/storageAccounts'
| extend allowBlobPublicAccess = parse_json(properties).allowBlobPublicAccess
| project subscriptionId, resourceGroup, name, allowBlobPublicAccess
Microsoft notes that accounts where the property was never set show as null; confirm their effective state rather than assuming.
- Check containers in accounts that allow it. Container access level Blob allows anonymous reads of blobs, and Container also allows listing. Private is the default. The account setting overrides container settings when anonymous access is disallowed. The
$web static website container stays publicly readable regardless, so confirm nothing sensitive is stored there.
- Look for anonymous requests actually happening. With resource logs sent to Log Analytics:
StorageBlobLogs
| where TimeGenerated > ago(7d) and AuthenticationType == "Anonymous"
| project TimeGenerated, AccountName, AuthenticationType, Uri
Accounts with anonymous traffic need an owner conversation before you switch the setting off.
- Find anonymous function endpoints. An HTTP trigger with
authLevel anonymous needs no key; function needs a function key and admin the master key. Microsoft notes authorisation is not enforced when running locally, so a setting that looked fine in development behaves differently once published. Review source and deployed configuration for every function app, and put intended anonymous endpoints behind App Service Authentication or your API gateway.
- Fix. Set
AllowBlobPublicAccess to false (for example Set-AzStorageAccount ... -AllowBlobPublicAccess $false) and assign an Azure Policy definition with the deny effect on Microsoft.Storage/storageAccounts/allowBlobPublicAccess not equal to false. Start with the audit effect, then switch to deny once exceptions are agreed.
Step-by-step: Google Cloud
- Search the organisation for public principals. Cloud Asset Inventory finds every allow policy granting a public principal, across resource types:
gcloud asset search-all-iam-policies \
--scope=organizations/ORG_ID \
--query="memberTypes:(allUsers OR allAuthenticatedUsers)" \
--format="table(resource, assetType, policy.bindings.role)"
This returns buckets, Pub/Sub topics and subscriptions, KMS keys, secrets, Cloud Run services and other resources with IAM policies in one pass.
- Find Cloud Run services with the invoker check off. Google Cloud supports two ways to make a service public: granting
roles/run.invoker to allUsers, or disabling the invoker IAM check (--no-invoker-iam-check, annotation run.googleapis.com/invoker-iam-disabled: 'true'). The second does not appear in an IAM search, so list services and inspect that annotation in each service's configuration.
- Check bucket settings. Buckets with public access prevention enforced cannot be made public through IAM. See the Google Cloud Storage Security Guide for the setting.
- Triage and fix. Remove unintended bindings with the resource's
remove-iam-policy-binding command (for Cloud Run, gcloud run services remove-iam-policy-binding SERVICE --member=allUsers --role=roles/run.invoker), and re-enable the Cloud Run invoker check with --invoker-iam-check where public access is not intended.
- Prevent. Domain restricted sharing (
iam.managed.allowedPolicyMembers, or the legacy iam.allowedPolicyMemberDomains) stops grants to principals outside your allowed list; Google documents that the legacy constraint is enforced by default for organisations created on or after 3 May 2024. Intended public resources need an exception, which Google describes through custom organisation policies and tags. To control who can disable the Cloud Run invoker check, use constraints/run.managed.requireInvokerIam, which is not enforced by default. See the Google Cloud Organization Policy Guide.
Decide: intended or not
| Finding | Usually intended? | Action (NHI Mgmt Group view) |
| Public read on a bucket or container serving website assets | Often | Keep, label with owner, move to a dedicated bucket or account with nothing else in it |
| Public principal on a queue, topic, key or secret | Rarely | Fix now; restrict to named accounts, organisation or source conditions |
| Anonymous function or service endpoint | Sometimes (webhooks, public APIs) | Keep only with authentication in the application or gateway, rate limits and logging |
| Public snapshot or image | Rarely | Fix now and treat as possible data exposure |
| All authenticated users on any resource | Almost never | Fix now; replace with groups or domains you control |
Verify it worked
- AWS: the finding moves to Resolved after reanalysis (allow for the timings in step 3), and
check-no-public-access returns PASS for the new policy.
- Azure: the Resource Graph query shows
false for the account, Azure Policy compliance reports it compliant, and the anonymous request query returns nothing new.
- Google Cloud: the
memberTypes search no longer returns the resource, and the Cloud Run service requires authentication.
- Everywhere: an unauthenticated request from outside your network to the resource is refused.
Rollback and common errors
| Situation | Fix |
| A website or download breaks after removing public read | Restore the exported policy for that resource only, then move the content to a dedicated public location or a CDN with origin access control |
| A partner integration breaks after restricting a queue or topic | Grant the partner's specific account or principal, not the public principal |
| Google Cloud refuses an intended public grant | Domain restricted sharing is working; create the documented exception rather than lifting the constraint |
| Cloud Run public access disappears after enabling the check in the console | Expected: Google notes enabling the check in the console removes allUsers invoker bindings, which must be re-granted if public access is intended |
| AWS finding persists after enabling account Block Public Access | Account-level settings are evaluated every 6 hours; recheck later |
Detection and measurement
- Alert on new public grants: new active AWS Access Analyzer findings with
isPublic true; Azure Policy non-compliance and changes to allowBlobPublicAccess in the Activity Log; Google Cloud Admin Activity SetIamPolicy entries that add allUsers or allAuthenticatedUsers, and Cloud Run updates that disable the invoker check.
- Watch access, not only configuration: anonymous request logs show whether an exposure was used.
| Metric | Target direction |
| Unintended public resources open | Zero |
| Intended public resources without owner and reason | Zero |
| Accounts, subscriptions and projects covered by the audit | 100% |
| Median time from new public grant to triage | Under one business day |
| Organisation-level prevention in place (Block Public Access, deny policy, domain restricted sharing) | All platforms in use |
Common failure patterns
- Storage only: buckets are clean, while a queue policy, KMS key or snapshot is shared with everyone.
- One Region or subscription: the analyzer or query runs where the team works, not where every resource lives.
- Policy search alone: a Cloud Run service with the invoker check off or an anonymous Azure function never shows up in an IAM search.
- Permanent exceptions: archived findings and policy exemptions with no review date grow until nobody knows which are real.
- Treating all-authenticated as private: a grant to any signed-in account is public for practical purposes.
Framework mapping
| Framework | Reference | How this task supports it |
| NIST SP 800-53 Rev 5 | AC-3 Access Enforcement; AC-6 Least Privilege; CM-6 Configuration Settings | Removes unintended public grants and enforces safe defaults |
| NIST CSF 2.0 | PR.AA-05; PR.DS-01 | Access permissions reviewed; data at rest protected |
| MITRE ATT&CK | T1530 Data from Cloud Storage | Reduces exposed storage that can be read without credentials |
Practitioner checklist
- Inventory every AWS account and Region, Azure subscription and Google Cloud organisation in scope.
- Run an external access analyzer in every AWS Region and list findings with
isPublic true.
- Run the Azure Resource Graph query for
allowBlobPublicAccess and review anonymous function triggers.
- Search the Google Cloud organisation for
allUsers and allAuthenticatedUsers, and list Cloud Run services with the invoker check off.
- Label every intended exposure with an owner, reason and review date.
- Export policies, then fix unintended exposures and verify with each platform's check.
- Turn on organisation-level prevention on each platform and alert on new public grants.
Standards and references
Related NHI Mgmt Group resources: IAM Access Analyzer Guide · Azure Storage Security Guide · Google Cloud Storage Security Guide · Cloud Data Perimeter Guide · Cloud Storage Exposure Playbook
NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 11 November 2026. Spotted an error? Use our
contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security.
nhimg.org