By the end you'll know
- What an AWS account is, and how AWS's new sign-up from September 2026 differs from the classic one
- Who owns your account: a root user, or an AWS Builder ID, and how to protect each
- Which kind of multi-factor authentication (MFA) to use, and why you want two
- How accounts end up with bills in the thousands, and which defences stop which mistake
- What a budget alarm does, what it doesn't, and the setting that keeps it silent on the free plan
- What the new sign-up blocks, and why turning on its "advanced features" is a one-way decision
- What to do, in order, if you think the account has been hacked
Before you start
- You need: an email address you'll use only for this account, and a phone.
- Set this up before you start: a way to do MFA. Either an authenticator app (Google Authenticator, Microsoft Authenticator, 1Password or similar) or a passkey on your phone or laptop. Ideally both: one is your backup.
- Cost: $0, and no card. Everything in this lesson is free, and one step even earns you credits.
- Where you run things: AWS CloudShell, a terminal in your browser that's already signed in as you. Nothing to install.
- The example: Juniper & Rye, the made-up bakery from Lesson 1, opening the account its shop will run in. Every output below is from a real sign-up on November 9, 2026; account numbers and personal details are hidden.
The short version
- An AWS account is a container for resources and a bill. Everything you create lives in one, and everything in it is charged to it.
- AWS's new sign-up asks for no card, puts you on a free plan with $100 in credits for up to 6 months, and can't charge you.
- In the new sign-up, an AWS Builder ID owns the account, not a root user. Its password and MFA are what protect everything. Register two MFA devices.
- The new sign-up is fenced in on purpose: one Region, chosen for you, and AWS-managed policies that block some services and settings. Leaving the fence, called advanced features, needs the paid plan, can't be undone, and deletes your spending limits.
- A budget is an alarm, not a brake. It emails you, hours after the spending happened. It doesn't stop anything.
- On the free plan, a default budget never fires, because credits pay for everything and your "cost" stays at $0. Leave credits out and it tracks what you actually use.
- Leaked access keys are the fastest way to a huge bill. AWS quarantines keys it finds on public GitHub within seconds, but that limits the damage; it doesn't undo it.
What this lesson costs
| Part | Cost |
|---|---|
| Creating the account | $0, no card |
| MFA | $0 |
| CloudShell | $0 |
| A cost budget with email alerts | $0, and it earned $20 in credits, one of the free plan's activities (watching budgets is free; only budgets with actions cost money, and the first two of those are free) |
| Cost Anomaly Detection | $0 |
| CloudTrail's 90-day event history | $0 |
| This lesson | $0, plus $20 of credits, and nothing left running |
How accounts end up with bills in the thousands
Stories of four- and five-figure bills on learning accounts are common, and they come from a short list of causes:
- Leaked access keys. Someone pushes code with an AWS key in it to a public GitHub repository. Automated scanners find it, and the key is used to start servers, often for crypto mining, in Regions the owner never looks at. In a test by Palo Alto Networks' Unit 42, AWS attached its quarantine policy to an exposed key within 10 seconds. That blocks a list of risky actions; it doesn't delete what was already started, and keys leaked anywhere else aren't covered.
- Things that bill for existing. Lesson 1's NAT gateway cost $32.85 a month doing nothing. A managed Kubernetes cluster, a database left on, a big server "just for the weekend": each one bills every hour until someone deletes it.
- Expensive sizes, by mistake. The same click that starts a $12-a-month server starts one costing hundreds or thousands, and both start in seconds.
- A card on a classic free tier. Before July 2025, AWS's free tier was a set of monthly allowances on an account with a card. Go past an allowance and the card was charged, with no ceiling. That's how most surprise bills on learning accounts happened.
The defences in this lesson each stop a different one:
| Mistake | What stops it | Where |
|---|---|---|
| A card charged with no ceiling | The free plan: no charges at all | Sign-up, this lesson |
| Someone signs in as you | MFA on whatever owns the account, two devices | This lesson |
| Spending you don't notice | A budget alarm that actually fires | This lesson |
| Spending that isn't like your usual | Cost Anomaly Detection | This lesson |
| Leaked everyday keys | Short-lived credentials instead of long-lived keys | Lessons 3 and 4 |
| Things left running | Every lab ends by deleting what it made, and checking | Every lesson |
| Spending past a hard limit (paid plan) | A project spend limit, which pauses the project | Later, if you upgrade |
What an account is
An AWS account holds resources and owns their bill. Everything you create, a server, a bucket, a user, lives in exactly one account, and the account pays for it. Each one has a 12-digit account ID. It isn't a password, but there's no reason to publish it; this track's scripts never print it, and where one appears in an error below, it's been replaced with AWS's documentation example, 111122223333.
An account is also a security boundary: by default nothing in one account can reach another. That's why companies use many accounts, one per team or environment, managed together with AWS Organizations (Part 6).
Something has to own each account and be able to do anything in it. How that works depends on how the account was made.
Two ways to sign up
Since September 16, 2026, AWS offers two sign-ups. AWS's documentation calls them "new" and "advanced"; this track calls the second one classic, because it's how every AWS account worked before.
| New sign-up | Classic sign-up | |
|---|---|---|
| Who owns the account | Your AWS Builder ID, a personal AWS login. No root user is created. | A root user: the sign-up email and a password |
| Card | Not needed for most new customers | Asked for |
| Plan | Free plan, $100 in credits, up to $100 more | Free or paid |
| Regions | One, chosen by AWS from your contact details; you can't change it | All of them; you pick |
| Services and settings | A large set, fenced by policies AWS manages | All of them |
| Hard spending limit | On the paid plan, a monthly limit per project that pauses it | None; budgets only alert |
| Who it's for | Learning, side projects, getting started | Regulated work, full control, every service |
This track uses the new sign-up, on the free plan, for as long as it can. It can't charge you, and its fences stop some expensive mistakes before they happen. Where a lesson needs something the fence blocks, the lesson says so, what it would cost, and lets you decide.
The free plan ends after 6 months or when the credits run out, whichever comes first, and nothing is charged while you're on it. When it ends, the account closes; AWS keeps it for 90 days in case you upgrade, then deletes it.
Signing up
At aws.amazon.com/free (opens in a new tab), Create a free account. You can sign up with a Google, GitHub, Apple or Amazon login, or with an email address.
Use a new email address, only for this account. Whoever controls the sign-in also controls the account. An address you use nowhere else keeps it separate from everything else you have, and makes it obvious which emails are about it. Give that inbox its own MFA too.
The sign-up asked for the email address, then your name, and set up the Builder ID's sign-in. It never asked for a card, and the account started on the free plan. Use your real name: it isn't shown publicly, and AWS Support uses it to check who you are if you're ever locked out. Then came three welcome steps:
Skip all three. Don't connect a coding agent: it would get access to the account before it has MFA, a budget or limited permissions. And don't pick anything on "What do you want to create?": every tile starts building something. Choose Done: go to the AWS Management Console.
The account is a project, and AWS named it for you, here "Sunrise Sprint". There's no Region selector at the top of the console: the project works in one Region, chosen from your contact details. CloudShell tells you which:
(CloudShell)
aws configure get region; echo "$AWS_REGION"
us-east-2
us-east-2 is US East (Ohio). Lesson 1's prices were for us-east-1, Northern Virginia; most prices are the same or close, and later lessons use the Region you have.
Who owns the account
In the new sign-up: your Builder ID
AWS's documentation is direct: in the new sign-up, "You do not create a root user." Your AWS Builder ID, the login you signed up with, owns the account. When you open the console, AWS signs you in to the account through a role it manages, AccountFullAccessRole, which can do almost anything in the account.
So the Builder ID is what to protect. Its password and MFA guard everything in the account, which makes the rules short:
- Turn on MFA, with two devices. The new sign-up requires it.
- Add a recovery email, in case you lose access to the main one. Check it before you send the code: AWS limits how many codes it resends, and a typo can lock that step for a while.
- Keep the sign-up inbox safe. Whoever controls it can reset the Builder ID's password.
In a classic account: the root user
A classic account has a root user: the sign-up email and a password, able to do anything, including close the account. You'll meet one in this track too: turning on advanced features (below) creates a management account with a root user. The rules for root:
- Turn on MFA. AWS has required MFA for root users of standalone accounts since 2024.
- Never create access keys for root. An access key is a password for programs; a root access key is one that can do anything and doesn't expire.
- Use root only for the few tasks that need it, like changing the account's email or closing it. Everyday work uses identities with limited permissions (Lesson 3).
Never do this
Never create an access key for the root user, and never put any access key in code. A key pushed to a public GitHub repository can be found and used within minutes, and everything it starts is billed to you. Lessons 3 and 4 set up credentials that expire on their own instead.
Multi-factor authentication
MFA means signing in needs two things: something you know (the password) and something you have (a device). A stolen password alone isn't enough.
| Kind | How it works | AWS lists it as | Resists phishing? |
|---|---|---|---|
| Passkey or security key | Your laptop, phone or a USB key proves who you are to the real AWS site | WEBAUTHN | Yes: it won't answer a fake site |
| Authenticator app | An app shows a 6-digit code that changes every 30 seconds | TOTP (time-based one-time password) | No: you can be tricked into typing the code on a fake site |
For a Builder ID: open your profile's Security page and choose Register device.
Register two: the built-in authenticator (a passkey, using your laptop's fingerprint reader) as the main one, then an authenticator app as the backup. Any one registered device works to sign in, so losing a phone is an inconvenience, not a support case with identity checks. If your browser asks where to save the passkey, choose a synced password manager, not "this device only", so it survives a lost laptop.
A budget is an alarm, not a brake
A budget won't stop spending
A budget only sends email, hours after the spending happened. Nothing is turned off when you pass it. The only real protection is deleting what each lab made, the same day.
A budget watches spending and emails you when it passes a line. What it doesn't do matters as much:
- It doesn't stop anything. Budget actions can, by applying a policy that blocks creating resources, or by stopping servers and databases, but only if you set them up.
- It's late. Budget data is updated up to three times a day, typically 8 to 12 hours apart, and there's a further delay between using something and it appearing on the bill. AWS's documentation says plainly that you can pass a threshold before the alert arrives.
- Forecasts need history. An alert on forecast spending needs about five weeks of usage before it can fire. In a new account, only alerts on actual spending work.
- On the free plan, the default never fires. Budgets count credits by default. Credits pay for everything, so your cost stays at $0, and an alert at $10 never fires while the credits drain. Leaving credits out makes the budget track what you actually use.
The new sign-up's spend limit is different: on the paid plan, a project that reaches its monthly limit is paused, so the bill can't grow past it. That's a brake. Budgets remain the alarm.
Cost Anomaly Detection is the other free alarm. Instead of a fixed line, it learns what your spending usually looks like and flags what's unusual, such as a service you've never used suddenly costing money.
CloudShell
CloudShell is a terminal in the AWS console: the >_ icon at the top right. It's free, it comes with the AWS command line interface (CLI) and Python, and it's already signed in as you. That makes it the safest place to run commands before Lesson 4 sets up the CLI on your own machine: no keys to download or leak.
To get a file into it, choose Actions, then Upload file. Two things that catch people out:
- Uploading a file with the same name may not replace the old one. Delete the old copy first (
rm check-account.py), upload, then check the size withls -l. - Paste one command at a time. Pasting several lines at once can feed the later lines into a command that's waiting for input. That's why the commands below set values with
exportinstead of asking for them.
Check the account, then fix it
The practice folder has three scripts for this lesson. Upload them to CloudShell and make them runnable:
(CloudShell)
chmod +x check-account.py make-budget.sh make-anomaly-monitor.sh
check-account.py only reads. It checks who is signed in, the root user's MFA and access keys, recent root sign-ins, the alternate contacts, the plan and credits, budgets, anomaly monitors, and which Regions the account can use. It prints labels and counts, never the account ID, an email address or a session name.
(CloudShell)
./check-account.py
The new account, before anything was set:
== Who is signed in
OK signed in as assumed-role AccountFullAccessRole (not root)
== The root user
info new sign-up: no root user to sign in as; your Builder ID's MFA protects sign-in
OK root has no access keys
info IAM users in the account: 0
== Root sign-ins recorded by CloudTrail (last 7 days)
info none found yet (sign-ins can take up to 15 minutes to appear)
== Alternate contacts (who AWS emails about billing, security and operations)
FIX billing contact not set
FIX security contact not set
FIX operations contact not set
== Account plan and credits
info plan FREE, status ACTIVE
info credits left: 100.0 USD, plan ends 2027-05-09
== Budgets
FIX no budgets: nothing will warn you about spending
== Cost Anomaly Detection
info monitors: 0
== Regions this account can use
info enabled: 17; opt-in Regions not enabled: 17
- Signed in through
AccountFullAccessRole, with no root user, as the new sign-up promises. MFA is on the Builder ID, set up above. - No alternate contacts, no budget, no anomaly monitor. Those are the three things to fix.
- 17 Regions enabled, but the project works in one. The others exist in the account; AWS's policies keep you out of them.
Alternate contacts: blocked
Alternate contacts tell AWS who to email about billing, operations and security, such as a notice that a key leaked. In a classic account you set all three, even if they're all you. In the new sign-up, try setting all three, one line at a time:
In the console: Account menu at the top right > Account > Alternate contacts. In the new sign-up it's blocked there too.
(CloudShell)
export EMAIL=you@example.com NAME="Your Name" PHONE="+15555550100"
for t in BILLING OPERATIONS SECURITY; do
aws account put-alternate-contact --alternate-contact-type "$t" \
--email-address "$EMAIL" --name "$NAME" --phone-number "$PHONE" --title "Owner" \
&& echo "$t contact set"
done
The same error came back three times, once for each contact:
aws: [ERROR]: An error occurred (AccessDeniedException) when calling the PutAlternateContact operation: User: arn:aws:sts::111122223333:assumed-role/AccountFullAccessRole/(session name removed) is not authorized to perform: account:PutAlternateContact on resource: arn:aws:account::111122223333:account with an explicit deny in a service control policy: arn:aws:organizations::(AWS's organization, removed):policy/(removed)/service_control_policy/(removed)
This error is worth reading slowly, because you'll see its shape again:
- "explicit deny in a service control policy". Your account sits inside an AWS Organization that AWS runs, and a service control policy (SCP) there blocks this action. An SCP is a rule over a whole account: no permission inside the account can override it, not even "full access". Lesson 36 writes your own.
- The new sign-up manages contacts for you. There's nothing to fix here, and
check-account.pywill keep showing these three lines. It's one of the fences.
The budget
make-budget.sh creates a $10 monthly budget that leaves credits out, with alerts when actual usage passes $5 and $10, and when the month's forecast passes $10.
In the console: Billing and Cost Management > Budgets > Create budget, and leave credits out of the charge types it counts.
(CloudShell) One line at a time:
export BUDGET_EMAIL=you@example.com
./make-budget.sh
| Command | What it does |
|---|---|
| export BUDGET_EMAIL=you@example.com | Sets the address that gets alerts, for this session. Use an inbox you actually read. |
| ./make-budget.sh | Checks the address looks like one email address, then creates the budget and its three alerts |
created budget monthly-10-usd, credits left out so it tracks real usage
alerts: actual spend past $5 and past $10, and a forecast past $10 (forecasts need about 5 weeks of history)
Confirm the email AWS sends; alerts arrive only after you do. Budgets aren't fenced: this one worked, and creating a budget with alerts is one of the free plan's activities, so it added $20 to the credits.
The anomaly monitor
make-anomaly-monitor.sh creates a monitor that watches each service's spending, and a daily email when unusual spending reaches $5.
In the console: Billing and Cost Management > Cost Anomaly Detection > Create monitor.
(CloudShell)
export ALERT_EMAIL=you@example.com
./make-anomaly-monitor.sh
created monitor spend-by-service: watches each service's spending for anything unusual
created subscription daily-unusual-spend: a daily email when unusual spending reaches $5
Check again
(CloudShell)
./check-account.py
== Who is signed in
OK signed in as assumed-role AccountFullAccessRole (not root)
== The root user
info new sign-up: no root user to sign in as; your Builder ID's MFA protects sign-in
OK root has no access keys
info IAM users in the account: 0
== Root sign-ins recorded by CloudTrail (last 7 days)
info none found yet (sign-ins can take up to 15 minutes to appear)
== Alternate contacts (who AWS emails about billing, security and operations)
FIX billing contact not set
FIX security contact not set
FIX operations contact not set
== Account plan and credits
info plan FREE, status ACTIVE
info credits left: 120.0 USD, plan ends 2027-05-09
== Budgets
OK budget 'monthly-10-usd': 10 USD a month
alert when actual spend passes 50%
alert when actual spend passes 100%
alert when forecasted spend passes 100%
== Cost Anomaly Detection
info monitors: 1
spend-by-service (dimensional)
== Regions this account can use
info enabled: 17; opt-in Regions not enabled: 17
What changed:
- Credits went from $100 to $120: the budget activity's $20.
- A budget with three alerts, the $5 and $10 lines on actual spending and the forecast line for later.
- One anomaly monitor, watching spending by service.
- The contacts still say FIX, and in this sign-up they always will. A check script reports what it sees; knowing why a line can't be fixed is part of reading it.
The fence, and the one-way door
The new sign-up's limits come from AWS's own policies over your account. When you need past them, the console offers advanced features: under Manage projects.
One-way decision
Activating advanced features needs the paid plan, deletes your spend limits, and can't be reversed. You get every Region and service, your own organization and a management account with a root user. You also lose the only hard brake on spending. This track stays inside the fence for as long as it can, and the lesson that needs to leave will say so first.
If you think you've been hacked
Signs: a budget or anomaly alert you can't explain, an email from AWS about irregular activity or an exposed key, servers or users you didn't create, or a sign-in you didn't make.
Act the same hour
Don't wait for the month's bill. Every hour a stolen key is used is billed to you. Work through the list below now, starting at the top.
AWS's own checklist for a suspected compromise, in the order that stops the damage fastest:
- Answer any email from AWS first. If AWS sent a notice about irregular activity or an exposed key, do what it asks, then reply to the case in the Support Center saying what you did.
- Lock the doors. Change the password of whatever owns the account, the Builder ID or the root user, check that every MFA device is yours, and use Delete all active sessions on the Builder ID's Security page. Change the passwords of anyone else with access.
- Kill the leaked keys. Deactivate every access key you didn't create or that may have leaked, then delete it. Delete any root access key, whoever made it.
- Remove what the attacker made. In IAM, deactivate users you didn't create and delete roles and policies you don't recognise. CloudTrail's event history shows when each was created, and by whom.
- Check every Region you can, not just yours. Attackers start servers where you don't look. Compare this month's spending with last month's, service by service.
- Delete what you didn't start. If you might need it as evidence, back it up first; a snapshot of a server's disk is enough.
- Check the account details: the sign-in email and recovery email, and in a classic account the alternate contacts. Attackers sometimes change them so AWS's warnings go to them.
- Open a case with AWS Support about the charges. Account and billing support is free on every plan. AWS can review charges caused by a compromise; that's a review, not a promise.
On the free plan, nothing is charged, so a compromise burns your credits instead of your card. You still have to clean up: a hacked free plan account that runs out of credits closes, with everything in it.
In real systems
- Nobody works as root. Companies use classic accounts in an organization, people sign in through IAM Identity Center with short-lived credentials, and root's password and MFA devices are locked away, used a few times a year.
- The fence you just met is how companies run AWS too. The new sign-up's managed organization and service control policies are a small version of a company's landing zone (Lesson 36).
- Budgets are per team and per environment, using tags (Part 6), with alerts to a shared channel instead of one person's inbox.
- Billing data is checked weekly, not when the alert arrives. Lesson 37 builds that habit.
Spot the problem
Work out what's wrong before you read the explanation.
"The budget is set, so we're safe." A student opens a free plan account, creates a $10 cost budget with the default settings and an alert at 100% of forecast spending, then spends two weeks of labs leaving a cluster and a NAT gateway running between sessions. The credits are nearly gone and no email ever came. What went wrong? Two settings, each enough on its own. The budget counted credits, so with credits paying for everything, its cost stayed at $0. And the alert was on forecast spending, which needs about five weeks of history before it fires. The fix: leave credits out of the budget, alert on actual spending at a low line like $5, and delete what each lab made at the end of the session. Then check: does the budget page show your real usage climbing, not $0?
Keep this
| Setting | Why | Cost |
|---|---|---|
| Free plan, new sign-up | No charges, no card | $0 |
| A separate sign-up email, with its own MFA | Whoever controls it controls the account | $0 |
| Builder ID MFA, two devices, recovery email | A stolen password isn't enough; a lost phone doesn't lock you out | $0 |
| No root access keys, ever | Nothing that can do everything should be in a file | $0 |
| Budget, credits left out, actual alerts | An alarm that fires while credits drain | $0, and $20 of credits |
| Cost Anomaly Detection | Flags spending unlike your usual | $0 |
| Advanced features | One-way: paid plan, spend limits deleted. Decide on purpose. | |
| Always | Delete what a lab made, the same day | |
Where you are now
You have an account on the free plan with no card, owned by a Builder ID with two MFA devices, a budget alarm that tracks real usage instead of sitting at $0, and a monitor for unusual spending. You know how big bills happen and which defence stops which mistake, that a budget warns but doesn't stop, what the new sign-up's fence blocks and why leaving it is one-way, and what to do, in order, if the account is ever compromised. The next lesson is about who can do what inside the account: IAM users, roles and policies, and working with only the permissions a job needs.
Check yourself
Why does a default budget never alert on the free plan?
What does a budget with only email alerts do when spending passes its limit?
In the new sign-up, what owns the account?
Setting a security contact failed with an explicit deny in a service control policy. What does that mean?
What happens to your spend limits when you activate advanced features?
Which kind of MFA can't be phished by a fake sign-in page?
Why register a second MFA device?
You get an email from AWS about an exposed access key. What comes first?
What happens when the free plan's 6 months end?
Key terms
- AWS account: a container for resources that owns their bill; also a security boundary between teams and environments.
- Account ID: the account's 12-digit number. Not secret, but not worth publishing.
- AWS Builder ID: a personal AWS login. In the new sign-up it owns your accounts, and its password and MFA protect them.
- Project: in the new sign-up, an AWS account plus who can use it. AWS names the first one for you.
- Root user: in a classic account, the identity created with the account. It can do anything, including close the account.
- IAM (Identity and Access Management): AWS's system of users, roles and permissions inside an account. Lesson 3.
- Access key: a long-lived credential programs use instead of a password.
- MFA (multi-factor authentication): signing in with a password plus something you have. AWS lists a passkey as WEBAUTHN and an authenticator app as TOTP.
- Passkey: a credential stored on a device that proves who you are only to the real site, so it can't be phished.
- Service control policy (SCP): a rule from an organization over a whole account. Nothing inside the account can override it.
- Advanced features: the new sign-up's switch to full AWS. Needs the paid plan, deletes spend limits, can't be undone.
- Alternate contacts: the people AWS emails about billing, operations and security. Managed by AWS in the new sign-up.
- Free plan: a new account's first 6 months at most, paid for with credits, with no charges.
- Budget: a spending line that sends alerts when actual or forecast cost passes it. Alerts only, unless you add budget actions.
- Spend limit: in the new sign-up, a monthly cap per project on the paid plan; the project pauses when it's reached.
- Cost Anomaly Detection: a free service that learns your usual spending and flags what's unusual.
- CloudShell: a free terminal in the AWS console, already signed in as you.
Go deeper
- AWS: Compare sign-up options (opens in a new tab), the new and advanced sign-ups side by side, and the announcement (opens in a new tab) from September 2026.
- Wiz: Exploring the new AWS sign-up experience (opens in a new tab), a security look at the managed organization and its policies.
- AWS: Choosing an AWS Free Tier plan (opens in a new tab).
- AWS: Managing your costs with AWS Budgets (opens in a new tab) and its best practices (opens in a new tab), including the update delays; and Budgets pricing (opens in a new tab).
- AWS: what to do if you notice unauthorized activity in your account (opens in a new tab); Unit 42 on how AWS quarantines exposed keys (opens in a new tab).
- Try: change
make-budget.shso the budget covers only one service, EC2. What would it miss that the account-wide budget catches?