Skip to content
AWS core 3 min read

IAM: Identity & Access

Identity and Access Management (IAM) is the control plane for who can do what to which resources in your AWS account. Every API call - from the console, CLI, or SDK - is authenticated and authorized by IAM before anything happens. Get IAM right and the rest of AWS becomes a safe playground; get it wrong and you’ve handed out the keys to the kingdom.

The four core entities

IAM revolves around four building blocks.

  • Users — a long-lived identity for a person or legacy application, with optional console password and/or access keys.
  • Groups — a collection of users. You attach policies to the group, and membership grants those permissions. Groups are for managing humans, not machines.
  • Roles — an identity with permissions but no permanent credentials. Trusted entities (an EC2 instance, a Lambda function, another account, a federated user) assume the role and receive temporary credentials.
  • Policies — JSON documents that define permissions. They attach to users, groups, or roles.

The principle of least privilege

Grant only the permissions required to perform a task, and nothing more. Start from zero and add specific permissions as needs arise - never start from * and try to subtract.

Least privilege limits blast radius. If a credential leaks, the damage is bounded by exactly what that identity could do. A leaked admin key is a catastrophe; a leaked read-only-one-bucket key is an inconvenience.

Use IAM Access Analyzer and the “Last accessed” data in the console to prune permissions that are never used.

Anatomy of a policy

A policy is a JSON document of statements. Each statement has an Effect (Allow/Deny), Action(s), Resource(s), and optional Condition(s).

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ReadWriteOneBucket",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::devcraftly-uploads/*"
    },
    {
      "Sid": "ListThatBucket",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::devcraftly-uploads",
      "Condition": {
        "StringLike": { "s3:prefix": ["public/*"] }
      }
    }
  ]
}

This grants object read/write on a single bucket and listing of only the public/ prefix. Note the two different ARN forms: object-level actions target bucket/*, while bucket-level actions target the bucket itself.

Evaluation rule: an explicit Deny always wins. By default everything is denied; an Allow opens access; any matching Deny overrides all allows. Use explicit denies for guardrails (e.g. “never delete production logs”).

Roles vs users

AspectIAM UserIAM Role
CredentialsLong-lived (password / access keys)Temporary, auto-rotated (STS)
Best forIndividual humansApplications, services, cross-account, federation
On EC2/LambdaDiscouraged (keys on disk)Strongly preferred
RotationManualAutomatic

Whenever code running on AWS needs to call AWS, attach a role - never bake in user access keys. An EC2 instance profile or a Lambda execution role delivers short-lived credentials transparently.

MFA

Multi-factor authentication adds a second factor on top of the password. Require it everywhere humans sign in.

  • Mandatory on the root user and all privileged IAM users.
  • Enforce it with a policy condition like "aws:MultiFactorAuthPresent": "true" so sensitive actions are blocked unless MFA was used.
  • Prefer hardware keys (FIDO2/WebAuthn) or authenticator apps over SMS.

Access key best practices

Access keys are the number-one source of AWS account compromise. Treat them as radioactive.

  • Don’t create them when a role will do (EC2, Lambda, ECS, CodeBuild all support roles).
  • Never commit keys to source control; use git-secrets or similar pre-commit scanning.
  • Rotate keys regularly and delete unused ones.
  • Scope them with least-privilege policies - never attach AdministratorAccess to a service account.
  • Use IAM Identity Center (SSO) for human access to get short-lived credentials by default.

Best Practices

  • Lock away the root user with MFA; operate as a least-privilege IAM admin.
  • Attach policies to groups and roles, not directly to individual users.
  • Default to roles and temporary credentials; avoid long-lived access keys.
  • Write tightly scoped policies; reserve * resources for read-only or genuinely global actions.
  • Enable CloudTrail to audit every IAM action, and review IAM Access Analyzer findings.
  • Use permission boundaries and Service Control Policies (SCPs) to cap maximum permissions across teams and accounts.
Last updated June 1, 2026
Was this helpful?