Overview
A night job should open one bronze prefix, not the whole company. Least privilege is a JSON statement, not a slogan.
On this page7 sections
The picture
A bronze reader is GetObject / storage.objects.get / Blob read on one prefix, not * on *.
Identity and Access Management (IAM on AWS and GCP, Azure RBAC plus Entra ID) answers three questions: who is making the request, on which resource, and which action are they performing. Every cloud API call is checked against these rules before it executes.
Users are people: a developer's Google account, an AWS IAM user, an Entra ID identity. Roles are job titles that bundle permissions together. Service accounts (GCP), IAM roles assumed by compute (AWS), and managed identities (Azure) are how pipelines authenticate without a human password.
If you have ever set file permissions on Linux (read, write, execute for owner, group, others), IAM is the same idea scaled to thousands of cloud resources. Instead of chmod 644, you write a policy document that says 'this service account may read objects in this one bucket prefix.'
Why this shape
Imagine you work at a fintech company. Your pipeline reads customer transactions from a storage bucket and writes aggregated reports to a warehouse. Without IAM, any employee (or any compromised laptop) could read raw transaction data, delete production tables, or exfiltrate the entire lake. Least privilege means granting the smallest action and resource scope that still lets the job finish.
storage.objects.get on gs://lake/bronze/orders/* is a dock badge for one aisle. Action * on Resource * is a master key left on the forklift. The difference between these two is the difference between a routine Tuesday and an incident that makes the news.
Walk the boxes
This browser cannot call a real IAM API. The exercise parses a simulated policy document, the same dict-as-environment trick you used in Config and secrets. The skill transfers directly: when you open a real IAM console, you will recognize principals, actions, resources, and effects.
Python dicts as config
You practiced reading nested dicts as config in Core Python. IAM policies are just nested JSON with specific field names: Principal, Action, Resource, Effect.
Mental model: people, job titles, and robots
Users are humans: the reviewer's Google account, an IAM user, an Entra ID user. Roles are job titles bound to identities: an AWS IAM role, a GCP IAM role binding, an Azure role assignment. Service accounts (GCP), instance/task roles (AWS), and managed identities or service principals (Azure) are robots. Pipelines authenticate as robots. Sharing the reviewer's user keys with the scheduler is how keys leak into Git.
What a statement is allowed to say
AWS policy JSON, GCP IAM bindings, and Azure RBAC say the same three things in different envelopes.
| Field | Least privilege | Incident waiting to happen |
|---|---|---|
| Principal / member | This DAG's service account | The whole org group |
| Action / role | s3:GetObject, storage.objects.get, Blob read | * or Owner |
| Resource | gs://lake/bronze/orders/* or an ARN prefix | * |
| Effect | Allow that one aisle | Allow plus a forgotten Deny |
Secret stores sit next to IAM: AWS Secrets Manager, GCP Secret Manager, Azure Key Vault. The Config and secrets lesson already taught os.environ and 'do not print the token.' IAM decides which robot may read that secret.
Worked example: two statements, one master key
You scan the policy the way you would scan a SQL GRANT. ListBronzePrefix names object-get on a bronze prefix. AdminEverywhere is Allow, Action *, Resource *. Your function returns that Sid. In a real console you would replace * with a role like roles/storage.objectViewer (GCP), AmazonS3ReadOnlyAccess scoped to a bucket (AWS), or Storage Blob Data Reader on one container (Azure).
A matching example
Run the example below in this tab. Read the input, follow the code, then check the output matches what you expect.
POLICY = {
"Statement": [
{"Sid": "ListBronzePrefix", "Effect": "Allow",
"Action": ["storage.objects.get"], "Resource": "gs://lake/bronze/*"},
{"Sid": "AdminEverywhere", "Effect": "Allow",
"Action": "*", "Resource": "*"},
]
}
def overpermissioned(policy):
for stmt in policy["Statement"]:
action = stmt["Action"]
star = action == "*" or (isinstance(action, list) and "*" in action)
if stmt.get("Effect") == "Allow" and star and stmt["Resource"] == "*":
return stmt["Sid"]
return None
print(overpermissioned(POLICY))# Count how many statements follow least-privilege (no wildcards)
def count_least_privilege(policy):
count = 0
for stmt in policy["Statement"]:
action = stmt["Action"]
has_star = action == "*" or (isinstance(action, list) and "*" in action)
resource_star = stmt["Resource"] == "*"
if not has_star and not resource_star:
count += 1
return count
print(f"Least-privilege statements: {count_least_privilege(POLICY)}")
print(f"Overpermissioned statements: {len(POLICY['Statement']) - count_least_privilege(POLICY)}")Wrong and right
The wrong version grants Owner so onboarding finishes before lunch. The right version grants object-get on bronze/orders/* and a separate binding if the job must write silver. Rotate keys when people leave. Prefer short-lived role assumption over long-lived access keys.
Star is never temporary
Teams grant Action * 'just for testing' and forget to revoke. Treat any wildcard in a real policy as a bug to fix this sprint, not a convenience to revisit later.
Least privilege is a review question
On an incident, ask: which identity ran, which verb, which resource. If the answer is star, that is the finding, even if the DAG is green now.
- Users are people. Jobs run as service accounts, task roles, or managed identities.
- Name verbs and prefixes. * on * is a bug, not a bootstrap.
- This tab parses JSON. The real IAM console is still Outside Lakebench.
Common beginner questions
What happens if I just use my personal account for everything?
Your pipeline works until you leave the company or change your password. Service accounts (robots) do not take vacations, forget passwords, or have MFA prompts at 2 AM. Pipelines must authenticate as robots.
Why are there so many role names?
Cloud vendors ship hundreds of predefined roles for granularity. You rarely need to memorize them. Search for the verb you need (e.g., 'storage read') and pick the narrowest predefined role that covers it.
Is IAM the same as authentication?
Authentication proves who you are (login). Authorization (IAM) decides what you may do after login. Both are required. IAM is the authorization layer.
What comes next
The next lesson covers object storage, where your data actually lives. IAM decides who can read and write those objects. You will see how bucket prefixes and IAM scopes work together.
Practice
Run Sample and confirm AdminEverywhere is the Sid that fails least privilege. Then complete Exercise: implement overpermissioned(policy) and store that Sid in result.
Practicals · load into the editor
After you read the theory, run these in the pane on the right. They execute in this tab, no cluster.