Profile    Mohammed Shiroz Status   Loading  
Logo
Share This
Back to blog
Filter by:
Tags
//Article title

Seven AWS Mistakes Small Teams Make (and the Afternoon Fix for Each)

About Post

AWS will let you do almost anything. That's the selling point, and for a small team it's also the trap.

Big companies have a cloud team, guardrails and someone whose job is to read the bill. A small team has a developer who set up the account two years ago, an EC2 instance called server-new-final, and a vague feeling that the backups are probably fine.

None of the mistakes below are exotic. That's what makes them dangerous: each one is easy to make on a busy Tuesday and stays invisible until the day it isn't. Here they are, with why they hurt and the fix that takes an afternoon, not a project.

1. Using the root account for everyday work

The mistake: logging in with the email address that created the account, and maybe even creating access keys for it.

Why it hurts: the root user can do everything, including closing the account and changing billing. It can't be limited by IAM policies. If those credentials leak, there is no ceiling on the damage.

The fix:

  • Turn on MFA for root, store the credentials somewhere safe, and stop using it.
  • Delete any root access keys. There's almost never a good reason for them.
  • Give each person their own identity (IAM Identity Center or IAM users) with MFA, and only the permissions they need.

2. Access keys in code and on servers

The mistake: an AWS_ACCESS_KEY_ID pasted into a .env file on an EC2 instance, or worse, committed to a repository.

Why it hurts: long-lived keys get copied, forgotten and leaked. Automated scanners look for them in public repositories constantly.

The fix: give the EC2 instance an IAM role (an instance profile). The AWS SDKs pick up temporary credentials from it automatically, and they rotate on their own. Your Laravel app can talk to S3 with no keys in .env at all. For CI, prefer short-lived credentials over a permanent key stored in the pipeline.

3. Public S3 buckets

The mistake: making a bucket public "just so the images load", then later storing invoices, contracts or database exports in the same bucket.

Why it hurts: public is public. Anyone who finds or guesses an object URL can download it.

The fix:

  • Keep Block Public Access on. AWS has enabled it by default for new buckets since 2023, so if you turned it off, you did it on purpose. Make sure the reason still holds.
  • Serve private files with pre-signed URLs that expire. In Laravel that's Storage::disk('s3')->temporaryUrl($path, now()->addMinutes(10)).
  • If you need public assets, put them in a separate bucket (ideally behind CloudFront), so a policy change on one can't expose the other.

4. Security groups open to the whole internet

The mistake: an inbound rule allowing 0.0.0.0/0 on port 22 (SSH) or 3306 (MySQL), added while debugging and never removed.

Why it hurts: every open port on a public IP gets probed by bots all day long. Strong passwords help, but the best attack surface is the one that isn't there.

The fix:

  • Only 80 and 443 should be open to the world on a web server, and often only on the load balancer.
  • Restrict SSH to known IPs, or skip open SSH entirely and use Systems Manager Session Manager.
  • Your RDS database should not be publicly accessible. Its security group should allow traffic only from the app servers' security group, not from an IP range.

5. No billing alerts

The mistake: finding out what you spent when the invoice arrives.

Why it hurts: cloud costs don't creep up politely. A forgotten load test, a runaway Lambda loop, leaked keys used to mine crypto, or a NAT gateway quietly moving lots of data can all turn a normal month into a very bad one. The cloud bills by the hour, so the earlier you know, the less it costs.

The fix: create an AWS Budget with email alerts at a few thresholds of your normal monthly spend, including a forecast alert. Turn on Cost Anomaly Detection. It takes ten minutes and it's the cheapest insurance in the whole console.

6. Backups that have never been restored

The mistake: RDS automated backups are on, so the team considers backups "done".

Why it hurts: a backup you've never restored is a hope, not a plan. Do you know how long a restore takes? Which endpoint the app should point to afterwards? Whether the uploaded files in S3 and the database rows will still match?

The fix:

  • Set a retention period that matches how far back you might need to go.
  • Turn on versioning for S3 buckets with important files, so a bad delete or overwrite can be undone.
  • Schedule a restore drill: restore a snapshot to a new instance, point a staging copy of the app at it, and write down every step. The written steps are half the value.
  • Consider a copy in another region or account for the data you truly can't lose.

7. Oversized instances and forgotten resources

The mistake: picking a big instance "to be safe", and leaving old experiments running.

Why it hurts: you pay for capacity whether you use it or not, every hour. And the forgotten stuff adds up: stopped instances still have EBS volumes, unattached volumes and old snapshots keep billing, and an idle test database costs the same as a busy one.

The fix: look at CloudWatch CPU and memory for a few weeks before choosing a size, start smaller and scale up when the numbers say so, and use Compute Optimizer's recommendations as a second opinion. Tag every resource with a project and owner, so "what is this and can I delete it?" has an answer.

The small-team rule: you don't need an enterprise landing zone. You need MFA everywhere, no long-lived keys, nothing private exposed, a budget alert, and a restore you've actually tested. That covers most of the ways a small AWS account goes wrong.

An afternoon checklist

  1. Root: MFA on, access keys deleted, not used day to day.
  2. People: individual logins with MFA and least privilege.
  3. Servers: IAM roles instead of access keys.
  4. S3: Block Public Access on; private files via pre-signed URLs.
  5. Security groups: no 0.0.0.0/0 on SSH or database ports; RDS not public.
  6. Billing: budget alerts and anomaly detection on.
  7. Backups: retention set, S3 versioning on, one restore drill done and documented.
  8. Costs: tags on everything, a monthly look for idle resources.

Which of these did you learn the hard way? And if you run a small AWS account, what would you add to the list?

Comments (0)
Leave your review

Thanks for your valuable comments. Your comments has been updated and appreciate your getting in touch...

01. About Shiroz

Mohammed Shiroz

Hi, I'm Mohammed Shiroz, a software engineer and AI enthusiast from Sri Lanka who turns ideas into intelligent, real-world solutions. With over 9 years of hands-on experience, I currently lead real estate ERP development at Kate Group, a...

03.My Projects

04. Categories

Ready To order Your Project ?

Get in Touch
Close