Setting Up AWS
What a new AWS environment needs before you build on it. Account structure, root hardening, identity, billing guardrails and CloudTrail.
Everything below takes about an hour and is far easier now than after you have workloads running. The order matters: identity and billing guardrails first, because both are painful to retrofit.
Decide the account structure first
The single decision with the longest consequences.
One account per environment, at minimum. Production separate from everything else. Accounts are the strongest isolation boundary AWS offers: a mistake in staging physically cannot touch production resources, IAM is entirely separate, and service quotas do not compete.
An IAM-only separation inside one account is weaker in every respect, and the temptation to use it comes from thinking accounts are expensive. They are free. You pay for resources, not for accounts.
Management account billing and Organizations only, no workloads
├── security CloudTrail archive, GuardDuty
├── production
├── staging
└── development
Create them with AWS Organizations, which gives consolidated billing, service control policies as organisation-wide guardrails, and central account creation.
The management account should hold no workloads. It is the account that can do anything to every other one, so keeping it empty limits what a compromise there reaches.
Harden the root user
Every account has a root user that cannot be restricted by any IAM policy or service control policy. It is the one identity with unconditional power.
- Enable hardware MFA. A physical key, kept somewhere access is controlled.
- Delete any root access keys. There is no legitimate use for programmatic root access.
- Use a shared mailbox for the email address, not a personal one. People leave.
- Set an alert on root sign-in via CloudTrail and EventBridge.
Then do not use it. There are perhaps five tasks that genuinely require root, and none of them are daily work.
Set up identity properly
Do this before creating a single IAM user, because once users exist they persist.
Enable IAM Identity Center in the management account and connect an identity source: the built-in directory for a small team, or Entra ID, Okta or Google Workspace if you have one. Then create permission sets and assign groups to accounts.
People sign in once and reach every account they are entitled to, with temporary credentials and no access keys anywhere.
aws configure sso
A convention worth adopting from the start: production defaults to a read-only permission set, with a separate administrator profile selected deliberately. It makes a mistyped command in the wrong terminal fail at the IAM layer.
Billing guardrails
Before anything is created, not after the first surprise.
aws budgets create-budget \
--account-id 111122223333 \
--budget '{"BudgetName":"monthly","BudgetLimit":{"Amount":"200","Unit":"USD"},"TimeUnit":"MONTHLY","BudgetType":"COST"}' \
--notifications-with-subscribers '[{
"Notification":{"NotificationType":"ACTUAL","ComparisonOperator":"GREATER_THAN","Threshold":80,"ThresholdType":"PERCENTAGE"},
"Subscribers":[{"SubscriptionType":"EMAIL","Address":"platform@acme.com"}]}]'
Also worth enabling immediately:
- Cost Anomaly Detection, which flags unusual spend automatically and needs no threshold tuning.
- Cost allocation tags, activated in the billing console so your tags actually appear in Cost Explorer.
- Free Tier alerts, if you are learning.
Turn on CloudTrail everywhere
CloudTrail records every API call. Without it, you cannot answer who did what, and you cannot add it retroactively for events that already happened.
Create an organisation trail covering all Regions and all accounts, delivering to an S3 bucket in a separate security account with restricted access. That separation means someone who compromises a workload account cannot erase the evidence.
Enable GuardDuty at the same time. It is close to zero-effort threat detection and costs little at low volume.
Tag from the beginning
Retrofitting tags across an existing estate is tedious and never finishes. Decide the schema now:
| Tag | Purpose |
|---|---|
Environment | production, staging, development |
Owner | Team or individual accountable |
Project | Cost attribution |
ManagedBy | terraform, cloudformation, manual |
Enforce it with provider-level defaults, default_tags in the Terraform AWS provider applies them to everything automatically, and with a service control policy or AWS Config rule for anything created outside IaC.
Set a few account defaults
Small settings that are annoying to apply later:
# Encrypt every new EBS volume by default
aws ec2 enable-ebs-encryption-by-default --region eu-west-1
# Block public S3 access at the account level, above any bucket setting
aws s3control put-public-access-block \
--account-id 111122223333 \
--public-access-block-configuration \
"BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"
Note that EBS encryption by default is per Region, so it must be set in each Region you use.
Install the tooling
| Tool | For |
|---|---|
| AWS CLI v2 | Everything; configure with SSO rather than access keys |
| Terraform or OpenTofu | Infrastructure as code from the start |
| Session Manager plugin | Shell access without SSH keys or open ports |
aws-vault or granted | Safer credential handling across accounts |
Start with infrastructure as code rather than promising to adopt it later. Importing a hand-built estate into Terraform afterwards is a genuinely unpleasant project.
A checklist
- Create the Organization and the account structure.
- Hardware MFA on every root user; delete root access keys.
- Enable IAM Identity Center; create permission sets; assign groups.
- Budget with an alert, plus Cost Anomaly Detection.
- Organisation-wide CloudTrail to a separate security account.
- Enable GuardDuty.
- Decide the tagging schema and enforce it.
- EBS encryption by default; account-level S3 public access block.
- Install the CLI with SSO, Terraform, the Session Manager plugin.
- Set up remote Terraform state with a locked, versioned S3 backend.
Go deeper in this section
| Sub-topic | What you will learn |
|---|---|
| AWS Account Setup | Root hardening, MFA and billing alarms in detail |
| AWS Console Tour | Navigating the console, and when not to use it |
| AWS CLI Setup | SSO configuration, profiles and the credential chain |
Quick reference
| Task | Command |
|---|---|
| Who am I | aws sts get-caller-identity |
| Configure SSO | aws configure sso |
| Create a budget | aws budgets create-budget ... |
| EBS encryption default | aws ec2 enable-ebs-encryption-by-default |
| Account S3 block | aws s3control put-public-access-block --account-id <id> ... |
| List accounts | aws organizations list-accounts |
| CloudTrail status | aws cloudtrail describe-trails |
Key takeaways
- Separate accounts per environment. Accounts are free and are the strongest isolation AWS offers.
- Keep the management account empty of workloads.
- Hardware MFA on root, no root access keys, shared mailbox, sign-in alert.
- Identity Center before any IAM users exist: and make production read-only by default.
- Budget alert before you create anything, plus Cost Anomaly Detection.
- Organisation CloudTrail into a separate security account, so evidence survives a compromise.
- Decide tagging now. Retrofitting never finishes.
- EBS encryption default is per Region and must be set in each.
Check your understanding
Separating environments
A team is deciding between separate AWS accounts per environment or one account with IAM separation. What is the strongest argument for separate accounts?
Where CloudTrail logs should live
Why deliver organisation CloudTrail logs to an S3 bucket in a separate security account rather than in each workload account?
Frequently Asked Questions
Should I use one AWS account or several?
Several, at minimum, production separate from everything else. An account is the strongest isolation boundary AWS provides: IAM is entirely separate, service quotas do not compete, and a mistake in one account cannot reach resources in another. Accounts are free, and AWS Organizations consolidates billing so there is no administrative penalty. A common structure is a management account holding only billing and Organizations, a security account for CloudTrail and GuardDuty, and one account per environment.
What should I do first with a brand new AWS account?
Enable hardware MFA on the root user and delete any root access keys, since root cannot be restricted by any policy. Set a budget with an alert before creating anything, so a mistake becomes a notification rather than a month-end surprise. Enable CloudTrail across all Regions. Then set up IAM Identity Center before creating any IAM users, because once users exist they tend to persist for years.
How do I avoid an unexpected AWS bill?
Create a budget with an alert at 80% of your expected spend before you build anything, and enable Cost Anomaly Detection, which flags unusual patterns without needing a threshold. Then be aware of the common sources: NAT gateways charging hourly plus per gigabyte, CloudWatch log groups defaulting to never expire, EBS volumes still billing after their instances are terminated, and data transfer out to the internet. Activating cost allocation tags early makes attribution possible later.
Do I need AWS Organizations for a small team?
It is worth it even for two accounts. You get consolidated billing, which combines usage for volume discounts and Free Tier, central account creation, and service control policies that set guardrails no member account can override. Such as denying the ability to disable CloudTrail or restricting which Regions may be used. There is no cost to enabling it, and retrofitting an Organization onto existing standalone accounts is more work than starting with one.
Should I create IAM users when setting up AWS?
No. Enable IAM Identity Center and connect an identity source instead, so people sign in with corporate credentials and receive temporary role sessions with no access keys. IAM users hold permanent credentials that do not expire and are the most common source of leaked AWS credentials. Doing this before any users exist saves a migration later, since users created for convenience early on tend to stay for years.
What tagging strategy should I use from the start?
At minimum Environment, Owner, Project and ManagedBy. Enforce them automatically, default_tags in the Terraform AWS provider applies them to every resource without repetition, and add an AWS Config rule or service control policy for resources created outside infrastructure as code. Remember to activate cost allocation tags in the billing console, otherwise they exist on resources but never appear in Cost Explorer. Retrofitting tags across a live estate is a project that rarely gets finished.