AWS from zero · Part 1: Foundations · Lesson 2 of 38 · about 45 minutes

A safe account, before anything else

Create an AWS account on the free plan and make it safe before you build anything, using AWS's new sign-up from September 2026: MFA on the login that owns the account, a budget alarm that actually fires, and a monitor for unusual spending. What the new sign-up does differently, what it blocks, the one-way switch to leave it, and a script that checks the account before and after.

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

PartCost
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:

MistakeWhat stops itWhere
A card charged with no ceilingThe free plan: no charges at allSign-up, this lesson
Someone signs in as youMFA on whatever owns the account, two devicesThis lesson
Spending you don't noticeA budget alarm that actually firesThis lesson
Spending that isn't like your usualCost Anomaly DetectionThis lesson
Leaked everyday keysShort-lived credentials instead of long-lived keysLessons 3 and 4
Things left runningEvery lab ends by deleting what it made, and checkingEvery lesson
Spending past a hard limit (paid plan)A project spend limit, which pauses the projectLater, 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-upClassic sign-up
Who owns the accountYour AWS Builder ID, a personal AWS login. No root user is created.A root user: the sign-up email and a password
CardNot needed for most new customersAsked for
PlanFree plan, $100 in credits, up to $100 moreFree or paid
RegionsOne, chosen by AWS from your contact details; you can't change itAll of them; you pick
Services and settingsA large set, fenced by policies AWS managesAll of them
Hard spending limitOn the paid plan, a monthly limit per project that pauses itNone; budgets only alert
Who it's forLearning, side projects, getting startedRegulated 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:

Step 1 of 3 offers to connect an AI coding agent. Skip it for now: an agent with access to an unprotected account is the opposite of this lesson's order.

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.

A brand-new account: $100 in credits, 182 days, and an automatically named project. Cost data takes up to a day to appear.

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)

BASH
aws configure get region; echo "$AWS_REGION"
OUTPUT
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:

  1. Turn on MFA, with two devices. The new sign-up requires it.
  2. 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.
  3. 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:

  1. Turn on MFA. AWS has required MFA for root users of standalone accounts since 2024.
  2. 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.
  3. 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.

KindHow it worksAWS lists it asResists phishing?
Passkey or security keyYour laptop, phone or a USB key proves who you are to the real AWS siteWEBAUTHNYes: it won't answer a fake site
Authenticator appAn app shows a 6-digit code that changes every 30 secondsTOTP (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.

The new sign-up requires MFA. Register the built-in authenticator first, then come back and add an authenticator app.

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.

Done: a passkey (WEBAUTHN) and an authenticator app (TOTP). Rename them so you can tell them apart; AWS names them after your email by default.

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 with ls -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 export instead 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)

BASH
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)

BASH
./check-account.py

The new account, before anything was set:

OUTPUT
== 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)

BASH
export EMAIL=you@example.com NAME="Your Name" PHONE="+15555550100"
BASH
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:

OUTPUT
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.py will 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:

BASH
export BUDGET_EMAIL=you@example.com
BASH
./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 |

OUTPUT
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)

BASH
export ALERT_EMAIL=you@example.com
BASH
./make-anomaly-monitor.sh
OUTPUT
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)

BASH
./check-account.py
OUTPUT
== 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.

Advanced features sit at the bottom of Manage projects. Continue to activation only shows information; nothing changes until you confirm.
Read this page before you ever confirm it: paid plan required, spend limits deleted, and no way back.

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:

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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.
  8. 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

SettingWhyCost
Free plan, new sign-upNo charges, no card$0
A separate sign-up email, with its own MFAWhoever controls it controls the account$0
Builder ID MFA, two devices, recovery emailA stolen password isn't enough; a lost phone doesn't lock you out$0
No root access keys, everNothing that can do everything should be in a file$0
Budget, credits left out, actual alertsAn alarm that fires while credits drain$0, and $20 of credits
Cost Anomaly DetectionFlags spending unlike your usual$0
Advanced featuresOne-way: paid plan, spend limits deleted. Decide on purpose.
AlwaysDelete 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

  1. Why does a default budget never alert on the free plan?

  2. What does a budget with only email alerts do when spending passes its limit?

  3. In the new sign-up, what owns the account?

  4. Setting a security contact failed with an explicit deny in a service control policy. What does that mean?

  5. What happens to your spend limits when you activate advanced features?

  6. Which kind of MFA can't be phished by a fake sign-in page?

  7. Why register a second MFA device?

  8. You get an email from AWS about an exposed access key. What comes first?

  9. 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