Get startedGet started for free

Authorizing service access with IAM

1. Authorizing service access with IAM

Welcome back. We authenticated end users; now we authorize the services themselves. In this video, you'll learn how IAM, AWS Identity and Access Management, grants permissions to your application. We'll separate users, roles, and policies, use execution roles instead of long-lived keys, assume roles with STS for cross-account access, and apply least privilege right down to a single table. Let's get started.

2. The key in the commit

A developer hardcodes an access key to ship a fix fast, and commits it. A bot scans the public repo, finds the key, and runs up your bill. It was long-lived and over-permissioned, the worst combination. Roles and least privilege would have made this impossible.

3. IAM principals: users, roles, and policies

IAM has three building blocks. A principal is whoever makes a request: a user, role, federated identity, or AWS service. A policy lists which actions are allowed or denied on which resources. A role is a bundle of permissions an entity temporarily assumes, getting short-lived credentials. Picture a role as a uniform you put on: while you wear it you have exactly its permissions, the policy is the rulebook clipped to it, and the principal is whoever puts it on. The key distinction: a user has long-lived credentials you must protect and rotate, while a role is assumed on demand and expires automatically. On AWS, you reach for roles wherever you can.

4. Programmatic credentials done right

Every compute service gets credentials without storing keys. A Lambda function, which runs your code without managing servers, uses an execution role; an EC2 instance an instance profile; an ECS task a task role scoped to that task. In all three, AWS injects temporary credentials that rotate automatically, eliminating the long-lived access keys in code or config that leak and never expire.

5. AssumeRole and STS

Sometimes a service in one account needs access to another account, or just short-lived credentials for a task. AWS Security Token Service, or STS, handles this with AssumeRole. The caller asks STS to assume a role, and STS returns temporary credentials scoped to that role's permissions, with an expiry. This is the standard cross-account pattern: account B's role has a trust policy naming account A as allowed to assume it. Because the credentials expire on their own, there is nothing long-lived to leak.

6. Least privilege and policy structure

A policy statement has a few core parts: an Effect of Allow or Deny, the Actions it covers, and the Resources it applies to. Read down the statement on screen: Effect says Allow, Action names the one operation, Resource pins it to a single ARN, the Amazon Resource Name that uniquely identifies it, and the Condition block requires the call to arrive over an encrypted connection. Least privilege means each statement grants only the specific actions on the specific resources a workload truly needs, not a wildcard. Conditions tighten it further, restricting by source IP, time, or whether the request is encrypted. The practical approach is to start minimal and add a permission only when something legitimately fails, rather than starting broad and clawing access back later.

7. Where IAM stops and your code begins

IAM is powerful, but it has a boundary. IAM authorizes AWS API calls: can this role call PutItem on this table. What it cannot do is enforce your business rules, like "user A may only read user A's records." That fine-grained, per-record and per-tenant authorization lives in your application code, which checks the authenticated user against the data requested. The right model uses both layers: IAM controls what the service may touch in AWS, and your code controls which specific data each user may see.

8. A least-privilege execution role in practice

Let's make it concrete. A Lambda function needs to write orders to a single DynamoDB table. The least-privilege execution role grants exactly one action, dynamodb:PutItem, on exactly one resource, that table's ARN, and nothing else. No star on the action, no star on the resource, no access to other tables. If the function later genuinely needs to read the table, you add dynamodb:GetItem then, scoped to the same ARN. This is the habit that keeps a compromised function from becoming a compromised account. Specific actions, specific resources, and expand only on real need.

9. Let's practice!

Let's now go lock down some permissions.

Create Your Free Account

or

By continuing, you accept our Terms of Use, our Privacy Policy and that your data is stored in the USA.