InfrastructureAll levels

AWS

AWS is Amazon's cloud platform and the oldest of the large clouds, which shows in two ways: it has the most services, and it makes you confront permissions before it lets you do anything useful. Both are the same fact — nothing is implicitly allowed, and the account is the only boundary that really contains a mistake. This page covers how a request is actually authorised, why multi-account is the default answer to isolation, what you trade as you move up the managed-service ladder, and the line items that make the bill a surprise.

Default answer
Deny
The boundary
The account
Credentials
Assumed, not stored

Every request is a permission decision

Nothing in AWS is allowed unless something says so. Every call — from a person, a service, a script — arrives as three facts: who is asking, what they want to do, and to which resource. The answer is computed from every policy that touches that combination, and the default when no policy has an opinion is no. That is why a new account can do almost nothing, and why "it works for me" between two engineers is usually a difference in roles rather than a difference in code.

Nothing in AWS is allowed unless a policy says so, and four separate things can have an opinion — each set by different people, which is what makes a denial confusing to debug. A service control policy is a ceiling the organisation places over a whole account and can only take away. A permission boundary is a ceiling an administrator puts on one role. An identity policy is attached to the user or role making the request. A resource policy is attached to the thing being touched, and is what permits access from outside the account at all. An explicit Deny in any of them ends the evaluation immediately, and if nothing allows the request, the answer is no.

Four things can have an opinion, and they are set by different people, which is the part that makes debugging confusing. A service control policy is a ceiling the organisation places over a whole account — it can only take away, never grant. A permission boundary is a ceiling an administrator puts on one role, so a team can create roles without being able to create one more powerful than themselves. An identity policy is attached to the user or role doing the asking. A resource policy is attached to the thing being touched — an S3 bucket, a queue, a key — and it is what allows access from outside the account at all. An explicit Deny in any of them ends the evaluation immediately; nothing further down can overrule it.

A role is the mechanism that makes this workable, and it is worth understanding as a distinct idea rather than as "a user for machines". A role is a set of permissions with no credentials of its own; a principal assumes it and receives credentials that expire in an hour or less. That is how an application on an instance gets access without a key existing anywhere, how one account grants access to another, and how a person gets an elevated permission for the length of a task rather than permanently. Almost every AWS access design reduces to: who may assume which role, and what does that role allow.

A long-lived access key

  • Works from anywhere, forever, until somebody remembers to rotate it.
  • Ends up in a repository, a CI variable, a laptop and a chat message.
  • Its use looks identical to legitimate use, so a leak is invisible until the bill.
  • Is the single most common root cause in cloud incident write-ups.

An assumed role

  • Issues credentials that expire, so a stolen one has a deadline.
  • Never needs a secret on the machine — the instance or workload proves who it is.
  • Records who assumed what and when, which turns an incident into a timeline.
  • Extends to CI and to other clouds through federation, so no key has to exist.

The account is the blast radius

Newcomers usually assume an account is a billing arrangement and try to separate environments with naming conventions and tags inside one. It does not hold. Tags do not stop a script, a name prefix does not stop a permission, and an accidental deletion in a shared account reaches whatever the caller could see. An account is a hard boundary: separate resources, separate default limits, separate credentials, and no implicit trust in either direction. So the answer to "how do we keep production safe from staging" is usually another account, and creating one is minutes of work.

Organizations is the layer that makes many accounts manageable rather than chaotic. Accounts sit in a tree of organisational units, billing is consolidated at the top, and service control policies apply to a unit and everything under it. Those policies are the only mechanism that stops an account administrator, which makes them the right place for rules that must hold no matter who is asking: no resources outside approved regions, no disabling of audit logging, no deletion of the security tooling. Everything else — who may do what day to day — belongs in the accounts.

Geography is the other boundary and it is more concrete than it looks. A region is a separate set of data centres with its own copy of most services; a resource in one region does not exist in another, and most services are regional even when the console makes them look global. Inside a region, an availability zone is an independent failure domain — separate power and network — and spreading across two or three of them is what makes a service survive a data centre problem. This is also where a cost surprise lives: traffic between zones is charged, often in both directions, so a chatty service split across zones for resilience pays for that resilience per gigabyte.

Choosing among two hundred services

The catalogue is the thing people find overwhelming, and the useful simplification is that almost every job exists at three levels of abstraction. You can rent a machine and run everything yourself; you can use a managed version where the provider handles the operating system, patching, backups and failover; or you can use a serverless version where there is nothing to size at all and you pay per request. The same three levels exist for compute, for databases, for queues and for nearly everything else, and moving up the ladder trades control and portability for operational work you no longer do.

LevelWhat you stop doingWhat it costs you
Rent the machineNothing — you own patching, backups, failover, capacity and the on-call rota.The least lock-in and the most work. Right when a requirement genuinely needs the control.
Managed serviceThe operating system, version upgrades, replication and most of the recovery story.A premium per hour, and configuration limits you cannot exceed. The usual right answer.
ServerlessCapacity planning entirely — there is nothing to size and nothing running when idle.Per-request pricing that inverts at scale, cold starts, and the deepest lock-in of the three.

Two honest caveats about the breadth. First, AWS almost never removes anything, so the catalogue contains several generations of the same idea and the console will happily offer you the oldest one — check when a service was introduced and what replaced it before adopting it. Second, the number of services is not a reason to use many of them: every one added is a permission model to understand, a failure mode to learn, a limit to hit and a line on the bill. A system built from six well-understood services is easier to run than one built from twenty barely-understood ones, and it is the version somebody can still operate when its author leaves.

How this shows up in real delivery

The bill is an architecture diagram nobody drew on purpose, and the surprises are usually not compute. Data leaving the cloud is charged per gigabyte and it is the line that turns a video or export feature into a business problem. Traffic between availability zones is charged, so resilience has a per-gigabyte price. A managed network address translation gateway charges both an hourly rate and a data rate, which is why a private subnet talking to the internet can cost more than the instances in it. And anything provisioned and forgotten — an unattached disk, an idle load balancer, a reserved address, a snapshot from a migration — bills at full rate for as long as it exists.

Two habits keep that from becoming an annual panic. Tag everything with an owner and a purpose from the first resource, because a tag added later never covers the things that predate it and an untagged bill cannot be allocated to anyone. And create resources from code — a repository, reviewed, applied by a pipeline — rather than from the console. The console is the right place to look at things and the wrong place to make them: a resource created by clicking has no history, cannot be recreated in another account, and is invisible to the next person until it appears on the invoice.

Finally, know where the provider's responsibility stops. AWS runs the hardware, the hypervisor, the physical security and the managed service's internals; you own the configuration, the permissions, the patching of anything you installed and, above all, your data. Every widely reported "cloud breach" of the last decade has been on the customer side of that line — a bucket left public, a key committed, a role with more permission than it needed. The provider will not save you from a policy you wrote, and the default settings are a starting point rather than a security posture.

Where it degrades

  • One account holding every environment, separated by naming conventions that stop nothing.
  • Long-lived access keys in CI, on laptops and in repositories, instead of assumed roles.
  • A wildcard policy written to unblock the first hour and never narrowed afterwards.
  • Audit logs written into the same account as the workload they are meant to audit.
  • Resources created in the console, so nothing can be reviewed, recreated or explained.
  • Untagged resources, so the bill cannot be attributed and nobody owns the cleanup.
  • A chatty service spread across availability zones, paying per gigabyte for its own chatter.
  • An older-generation service adopted because the console offered it first.
  • Twenty services in a system that six would have carried, each with its own failure mode.

When to use it

Use it when

  • When you need a service that exists nowhere else, which is still the most common honest reason to choose AWS.
  • Strict isolation requirements, where the account boundary and organisation-level ceilings do real work.
  • Teams hiring for it, since the deepest pool of people and written answers is a genuine operational asset.
  • Workloads needing many regions, where the geographic footprint and the maturity per region matter.

Avoid it when

  • A small team with no one to own permissions, where the model is a cost before it is a protection.
  • A single application that a managed platform would run for a tenth of the setup and a fifth of the concepts.
  • Egress-heavy products — video, downloads, exports — until the per-gigabyte line has actually been modelled.
  • Choosing it because it is the default, without asking what your organisation already runs and already knows.

Found this useful?

Share it with someone who is working on the same problem.