Documentation & Tools →
Sign In
In this section

Identity Is the Perimeter in AWS: IAM, Roles, and Credentials

Module 0

An attacker is active in your AWS account right now. You pull up the network view. Every connection is an outbound HTTPS session to an AWS API endpoint, the same endpoint every legitimate tool in your company talks to all day. There is no exploited port, no inbound shell, no malware beaconing to a strange address. The traffic is encrypted, ordinary, and indistinguishable from the work your engineers do every minute. The network tells you nothing, because in AWS the network is not where the fight is.

The attacker is not coming through a hole in a wall. They are walking through the front door with a key. The perimeter you defend, and the place you investigate, is identity.

There is no network edge

In a traditional environment, there is an inside and an outside, and a perimeter between them: firewalls, network segments, a VPN to cross. Compromise often means breaching that boundary, so the network is where you watch and where you investigate. AWS does not have that boundary in the same way. The control plane, where resources are created and managed, is a public API endpoint reachable from anywhere on the internet. There is no network position that is "inside" it. What stands between a request and your resources is not a firewall. It is authorization.

Every single API call is authenticated to a specific identity and then checked against that identity's permissions before it runs. The request to launch an instance, read a bucket, or create a user carries credentials, AWS works out which principal they belong to, and IAM evaluates whether that principal is allowed to do exactly that. Pass the check and the call runs. Fail it and the call is denied and logged.

This evaluation is the perimeter. It happens on every call, for every identity, with no concept of a trusted network the caller might be sitting in. The boundary moved from the network layer to the identity layer, and that is where both the defender and the attacker now operate.

This does not mean networks vanish. AWS still has VPCs, subnets, and security groups, and they matter for controlling traffic between resources, the data plane where your application actually runs. But they are not what stands between an attacker and the control plane. You cannot firewall the AWS API; it answers from the public internet by design, and the only thing that stops an arbitrary request to it is whether the credentials it carries are authorized.

Two kinds of policy decide that. Identity-based policies attach to a principal and say what that principal may do. Resource-based policies attach to a resource, such as an S3 bucket, and say who may act on it. An attacker with a valid credential is working inside this policy logic, not against a network barrier, and so are you when you investigate them. Understanding that the contest happens in authorization, not in packets, is the whole reorientation of this section.

Principals, credentials, and roles

Identity in AWS is expressed as principals, and you need three kinds clear before you can read a single investigation. The course explains each fully when you first use it; this is the orientation.

An IAM user is a long-lived identity, usually a person or an application, that authenticates with a long-lived access key. Those keys begin with the prefix AKIA, they do not expire on their own, and they are the credential most often leaked, because they get committed to repositories, baked into scripts, and shared. A role is an identity that nobody holds permanently. A principal assumes a role through the Security Token Service, and AWS hands back temporary credentials that begin with ASIA and expire after a set time.

Roles are how an EC2 instance, a Lambda function, or a federated employee gets permissions without a permanent key. Root is the account's original identity, all-powerful, and any activity from it in normal operation is itself a red flag.

Root deserves a closer look, because it is the one identity that should almost never appear in your logs. When an AWS account is created, root holds unconditional power over everything in it, beyond the reach of the permission policies that constrain every other principal. Mature organizations lock root away: they enable multi-factor authentication on it, remove its access keys entirely, and reserve it for the handful of tasks that genuinely require it, treating any use as a break-glass event that is logged, alerted on, and reviewed.

The practical consequence for you is simple and powerful. A root login or a root API call that you were not expecting is one of the highest-signal events in all of AWS, because legitimate root use is rare and planned. When you see it, you treat it as an incident until proven otherwise, and the course returns to root activity as a recurring high-priority signal.

The single most important identity mechanic to understand is role assumption, because it is everywhere in AWS and it is how attackers move and escalate. Here is the call that does it.

CloudTrail STS Management Event
{
  "eventTime": "2026-05-12T15:44:10Z",
  "eventSource": "sts.amazonaws.com",
  "eventName": "AssumeRole",
  "awsRegion": "us-east-1",
  "sourceIPAddress": "10.30.6.40",
  "userIdentity": { "type": "IAMUser", "userName": "m.chen-dev",
    "arn": "arn:aws:iam::444444444444:user/m.chen-dev" },
  "requestParameters": {
    "roleArn": "arn:aws:iam::333333333333:role/cross-account-deploy",
    "roleSessionName": "deploy-session"
  },
  "responseElements": {
    "credentials": { "accessKeyId": "ASIAEXAMPLEDEPLOY1" }
  },
  "eventType": "AwsApiCall"
}

Read what happened. The user m.chen-dev in the development account assumed the role cross-account-deploy in the production account, and STS returned a temporary key beginning ASIA. From this moment, the calls that key makes will appear in CloudTrail with a userIdentity type of AssumedRole, carrying a session context that names the role and who assumed it. That chain, user assumes role, role does things, is the backbone of how work gets done in AWS and how an attacker crosses from a foothold into real reach.

A leaked m.chen-dev key that can assume a powerful production role is far more dangerous than the key alone, and the only place that relationship is visible is the identity record. Following identity across role assumptions is the skill that turns a single suspicious key into the full scope of an incident. One detail on the region: this call used the global STS endpoint, which logs in us-east-1 as shown; STS can also be called at a regional endpoint, which logs in that region.

So read us-east-1 on an STS event as a property of the endpoint the caller chose, not as the caller's location.

Reading identity in the record

Because identity is where the investigation lives, the userIdentity block of a CloudTrail record is the part you learn to read first and trust most. Its type field tells you the kind of principal: IAMUser for a long-lived user, AssumedRole for a temporary session from a role, Root for the account's master identity, and AWSService when an AWS service itself made the call on your behalf.

For an IAMUser, the record names the user and the access key. For an AssumedRole, it carries a session context whose session issuer names the role that was assumed and the identity that assumed it, so even a call made by a temporary credential can be traced back to the human or key behind it. That back-reference is what lets you follow a chain: a leaked user key assumes a role, the role's session does the damage, and the session records still point home to the original key.

Here is the next call in that chain, made by the session the earlier AssumeRole created.

CloudTrail Management Event
{
  "eventTime": "2026-05-12T15:45:02Z",
  "eventSource": "s3.amazonaws.com",
  "eventName": "ListBuckets",
  "awsRegion": "eu-west-2",
  "sourceIPAddress": "203.0.113.41",
  "userIdentity": {
    "type": "AssumedRole",
    "arn": "arn:aws:sts::333333333333:assumed-role/cross-account-deploy/deploy-session",
    "sessionContext": {
      "sessionIssuer": {
        "type": "Role",
        "userName": "cross-account-deploy",
        "arn": "arn:aws:iam::333333333333:role/cross-account-deploy"
      }
    }
  },
  "eventType": "AwsApiCall"
}

The type is now AssumedRole, the arn carries the session name deploy-session, and the sessionContext.sessionIssuer names cross-account-deploy. Follow that issuer back to the previous record and you land on m.chen-dev assuming the role. That is the chain made concrete: this ListBuckets traces to the role, the role traces to the user. Note one thing more. The source address here is 203.0.113.41, an external IP, while the user's own AssumeRole came from an internal 10.30.6.40.

The session that should belong to a deployment pipeline is being driven from outside the network, which is the kind of break in pattern the next section is about.

Two more principal shapes complete the picture. A service such as an EC2 instance or a Lambda function does not have a user; it has a role it assumes automatically, and its calls appear as an assumed-role session tied to that service role. Federated identities, where employees sign in through a company identity provider rather than holding IAM users, arrive through calls like AssumeRoleWithSAML or AssumeRoleWithWebIdentity and then operate as assumed-role sessions too.

The unifying idea is that almost everything in AWS ends up as either a user with a long-lived key or a session from an assumed role, and the access key prefix tells you which at a glance: AKIA is a long-lived key, ASIA is a temporary one from STS. That single distinction is an early triage signal. A long-lived AKIA key making sensitive calls is a different risk from a short-lived ASIA session, and an AKIA key appearing somewhere it never has is exactly the kind of leaked-credential signal Module 5 teaches you to hunt.

Why the attack lands here

Because authorization is the perimeter, compromise in AWS is almost always identity compromise. The attacker's goal is a valid credential and the permissions behind it: a leaked access key, a role they can assume, a federated session they can ride, an instance whose role they can steal. Once they have one, every control between them and your data evaluates at the identity layer and they pass it, because they are using a credential the system trusts.

This is why detection in AWS is identity-centric rather than network-centric. You cannot tell a malicious API call from a legitimate one by looking at the packets; they are identical. You tell them apart by context: which principal made the call, from what IP and tool, at what time, doing what, and whether that matches how the principal normally behaves. A key that has only ever called three APIs from one office IP suddenly enumerating the whole account from another continent is the signal, and it lives entirely in the identity record. Throughout this course you build the habit of profiling normal per principal so the deviation stands out.

The signals are concrete once you know to look for them, and none of them lives at the network layer.

A credential used from a geography the owner has never worked in, or from two distant places closer together in time than travel allows, is the classic one. A principal that has been dormant for months and suddenly wakes is another.

A change in calling tool is a third, from the console a person always uses to the SDK an automated attacker prefers. So is a sudden widening of behavior, where an identity that only ever touches a few APIs starts enumerating users, roles, and buckets.

All of these sit in the identity fields of CloudTrail, and all of them depend on knowing what normal looks like for the principal in question. Learning which fields carry which signal, and building that sense of normal for the principals in your environment, is the core investigative skill the rest of the course develops one attack at a time.

There is one more reason identity is where the danger concentrates: trust between accounts. The role assumption you saw earlier, where a development-account user assumes a role in the production account, is a deliberate, useful bridge, and it is also a path an attacker inherits the moment they compromise the development-account credential. Trust relationships defined in resource-based policies and role trust policies mean that holding one identity can grant reach into another account entirely, with the crossing recorded only as an ordinary AssumeRole.

This is why scoping an AWS incident means asking what a compromised principal can do in its own account and, just as importantly, which other accounts and roles it can reach, then following those edges wherever they lead. An investigation that stops at the account boundary stops short of where the attacker went.

Every path reaches your resources through one gate Console CLI and SDK CI/CD pipeline Instance role IAM authorization evaluated on every call Your resources There is no network position that bypasses the gate. The perimeter is the credential and what it may do.

Console, CLI, automation, and instance roles all reach resources through the same IAM authorization check. Defending and investigating AWS means working at that gate, not at the network edge.

Anti-Pattern

Hunting for the network intrusion.

Opening an AWS incident by looking for the breached firewall, the exploited port, or the inbound connection, the way you would on-premises. There usually is not one. The attacker authenticated with a credential the account already trusted and made ordinary API calls over the same encrypted channel everyone uses. Time spent searching the network for a break-in is time not spent on the identity record, where the actual story is. Start with the principal, the credential, and what it did.

Identity explains what the attacker is reaching for and where you investigate. It does not yet tell you the specific moves they make once they have a credential. AWS0.6 walks the attack classes you will learn to catch, from the leaked key through escalation, persistence, and exfiltration, and maps each to where it sits in the attacker's playbook.