Check your AWS account in 15 minutes
Sabri Eddir · Founder, Secure Layer · 7+ years at AWS Security
Two things cost a small company dearly on AWS: data getting out, and a bill exploding. Both can be prevented from your own console, with the sixteen checks below.
For each check, paste the command into your terminal, or follow the console path, then answer: OK, Not OK, or I don’t know. Your summary builds at the bottom of the page.
Not the person with access to the account? Send this page to whoever has it. One person, one sitting, fifteen minutes.
Your answers stay in your browser, they are never sent to us. We send only anonymous usage counts: page views and progress ticks (question number, never the answer), with no cookie and no identifier. Each check links to the original AWS guide. The stories with numbers link to their authors: field reports, not AWS guidance.
identite/
Identity
Who can get into your account, and with what. Most AWS intrusions start with a credential lying around, not with a cloud vulnerability.
- 01
Multi-factor authentication (MFA) on the root account, and everything around it
The root account can do everything, including delete the rest. AWS now enforces MFA on it, so that box alone no longer tells you much. What matters: who receives the root account’s email, and whether access keys still exist on it. A founder’s personal Gmail inbox is an account-takeover path.
Where to look
aws iam get-account-summary --query 'SummaryMap.{RootMFA:AccountMFAEnabled,RootAccessKeys:AccountAccessKeysPresent}'- No terminal: IAM console, home page: the Security recommendations panel. Then the question to ask out loud: who reads the root account’s mailbox?
- 02
Access keys left lying around
A key older than 90 days has had time to end up in an old commit, a .env file, a laptop returned at the end of a contract. Whoever finds it has your account, no password, no MFA.
Where to look
aws iam generate-credential-reportaws iam get-credential-report --query Content --output text | base64 --decodegit log -p | grep AKIA- No terminal: IAM console, Credential report: the access_key_1_last_rotated column.
- 03
Humans with IAM users instead of IAM Identity Center
AWS’s current recommendation: no human has an IAM user. People sign in through IAM Identity Center, with temporary credentials that expire. Most tutorials still teach the opposite, so most accounts still do the opposite.
Where to look
aws iam list-users --query 'Users[].UserName'- No terminal: IAM console, Users: every user with a first name in it is one to migrate. IAM Identity Center console: is it even enabled?
- 04
Your CI deploys with a stored key
An AWS_SECRET_ACCESS_KEY in the repo’s secrets works, never complains, and eventually leaks. The replacement is OpenID Connect (OIDC): your CI assumes an AWS role for the duration of the deploy, no key stored anywhere.
Where to look
aws iam list-open-id-connect-providers- No terminal: In GitHub: Settings, then Secrets. Does an AWS key live there? The token.actions.githubusercontent.com provider should appear in the command above.
- 05
No emergency access
If your identity provider goes down at 2am, how do you get into AWS? Teams that migrated properly to Identity Center often deleted every IAM user, including the fire escape. AWS defines an exception exactly for this: an emergency user, with MFA, whose credentials sleep offline.
Where to look
- Look for it in the IAM console. If it does not exist, the answer is Not OK.
- 06
MFA that resists phishing
Fake AWS sign-in portals relay the password and the MFA code to the real site as you type them. Access observed less than 20 minutes after the click. A 6-digit code does not protect against that. A passkey does.
Where to look
aws iam list-virtual-mfa-devices --assignment-status Assigned- No terminal: IAM console, MFA devices: what device type on root and the admins? The command lists one-time-code devices. A root or admin listed here, with no passkey next to it: the answer is Not OK.
donnees/
Data
What is visible from the internet. Scanners sweep AWS around the clock, run by people who do this for a living.
- 07
Storage or a database reachable from the internet
The most common leak, and the only one visible from outside. An open S3 bucket or an exposed database gets found in hours, not months.
Where to look
aws s3control get-public-access-block --account-id $(aws sts get-caller-identity --query Account --output text)aws ec2 describe-security-groups --filters Name=ip-permission.cidr,Values='0.0.0.0/0' --query 'SecurityGroups[].[GroupId,GroupName]'- No terminal: S3 console: Block Public Access, at the account level. EC2 console, Security Groups: look at what listens behind every rule open to 0.0.0.0/0.
- No terminal: The first command returns NoSuchPublicAccessBlockConfiguration? The lock was never set: the answer is Not OK.
- 08
Secrets live in the code
A private repo is not a security control. A researcher put a key in his code in 2026: scanners found it within days, the attacker held the account for 48 hours, and buried AWS’s alert emails under spam to stay invisible.
Where to look
aws secretsmanager list-secrets --query 'SecretList[].Name'- No terminal: Zero secrets stored in Secrets Manager is already an answer. In your repos, a secret scan (trufflehog or similar) answers in minutes.
AWS guide: Secrets Manager best practices · The researcher’s account: Zvi Biran
detection/
Detection
Who notices, and how fast. An enabled detector nobody listens to gives the same result as no detector.
- 09
CloudTrail: a multi-region log, out of reach
The 90-day history visible in the console is not a trail. A single-region trail misses the regions you never visit, exactly where a crypto miner sets up. And a log stored in the account it watches disappears with it.
Where to look
aws cloudtrail describe-trails --query 'trailList[].{Name:Name,MultiRegion:IsMultiRegionTrail,Bucket:S3BucketName}'- No terminal: IsMultiRegionTrail must be true, and the destination bucket should live outside the watched account, or at least be locked down.
- 10
GuardDuty runs, but who gets told?
Enabling GuardDuty takes one click. Routing its findings to a human, nobody ever checks. A GuardDuty that talks to nobody is a smoke detector without a battery. The real question: when it fires, who gets the message, and within how many minutes?
Where to look
aws guardduty list-detectorsaws events list-rules --output json | grep -i guardduty- No terminal: GuardDuty console, Findings: when did someone last open this page?
- 11
Cost Anomaly Detection: the alarm for the unplanned
A budget watches a threshold you planned. Cost Anomaly Detection watches what you did not plan: the leaked key, the runaway loop, the forgotten region. It is free, and many accounts never turned it on.
Where to look
aws ce get-anomaly-monitors --query 'AnomalyMonitors[].MonitorName'- No terminal: A monitor should exist, with a recipient who actually reads their email.
- 12
If your account were compromised, who would see it, and when?
Billing data lags by up to 24 hours: the bill is a tripwire, not an alarm. A forgotten cluster at 4,000 euros a month and crypto mining look the same on a bill nobody reads. This check does not happen in a console. It happens in a team meeting.
Where to look
- Ask the question exactly as written. If the answer is silence, you have your answer.
facture/
The bill
What you pay without knowing. On AWS, a security mistake and a cost mistake end up in the same place: the bill.
- 13
A budget alert that can actually fire
The known trap: an alert on a forecasted amount stays silent for about 5 weeks, until AWS has enough history. The console accepts it and shows it green anyway. A recent account with only a forecast alert has, in practice, no alert.
Where to look
aws budgets describe-budgets --account-id $(aws sts get-caller-identity --query Account --output text) --query 'Budgets[].BudgetName'- No terminal: Budgets console: for each alert, the condition type (actual or forecasted amount). And where do the emails go? Has anyone ever received one?
- 14
Cost tags activated on the billing side
Tagging cleanly in Terraform is not enough. Cost allocation tags must be activated by hand in the Billing console, otherwise Cost Explorer cannot group by them. The test: can you answer « what does staging cost? » in one click?
Where to look
aws ce list-cost-allocation-tags --status Active- No terminal: At least one of your own tags should come back with status Active.
- 15
S3 traffic going through a NAT Gateway
A VPC endpoint to S3 is free. The same traffic through a NAT Gateway is billed per gigabyte. The architecture works either way, so nothing flags it. One team paid 907 dollars in a single day for that difference.
Where to look
aws ec2 describe-nat-gateways --query 'NatGateways[].[VpcId,State]'aws ec2 describe-vpc-endpoints --query 'VpcEndpoints[].[VpcId,ServiceName]'- No terminal: Every VPC that has a NAT Gateway should also have an S3 gateway endpoint. In Cost Explorer, grouped by usage type: a NatGateway-Bytes line that surprises you?
- 16
Forgotten resources still running
A test environment never shut down, an oversized instance. It breaks nothing, it costs money every month. The simple question: in Cost Explorer, can you name the purpose of every line?
Where to look
- Cost Explorer console, by service, sorted by cost. What you cannot name is the answer.
Your summary
Answer the sixteen checks above. The summary builds here, in your browser.
The logical next step: the same exercise, computed instead of ticked. Import your CloudFormation template into Secure Layer. Every resource is checked against the security rules that apply to it, verdict by verdict. Free, no card, and no access to your AWS account.
Import a template and see the verdict