learn-cyber-security-with-phoebe / Builder session 2 of 8
Learn Cyber Security with Phoebe · Builder session 2 of 8

Credential paths

Five of Ironwood's nine paths to the customers table walk through the credential door: a key that was committed to a public repository two years ago and still works, an analyst password with no second factor, an admin password with no second factor, and an admin role that was granted to the analyst one Friday to unblock a load and never taken back. Tonight puts all four edges on one graph, closes two of them with two controls, watches the path count fall from nine to six to five, and rotates a service key in the order that does not turn a security fix into an outage.

🟡 Core Platform and analytics engineers Anyone who owns a service account 45 min
0-3 · Welcome 3-20 · Four credential doors on one graph 20-40 · Build-along: close two of them 40-45 · Q&A
Part 0

Where tonight sits in the builder track

Session 1 drew the inventory: five lanes, three doors, nine paths to Ironwood's customers table, all unseen, and backups that go with the admin login. The credential door carries five of the nine, which makes it the first door to work on and the cheapest reduction on the whole ladder. Two controls tonight, MFA on every human login and rotation of the service key with the old one expired, remove four paths. The fifth credential edge, the Friday admin grant, is a privilege problem rather than a credential problem, and it stays open until least privilege closes it at the end of the ladder.

Live = presented in the 45 minutes Self-study = the full depth, after class 🔍 Every diagram zooms

★ What you walk out with tonight. The four credential edges on your own inventory, each with the control that closes it written in the "closed by" column. One service key rotated in the five-step order, with the old key confirmed to no longer authenticate, which is the step most rotations skip. A list of every human login without a second factor. And two numbers from Ironwood's ladder: MFA takes paths from 9 to 6, rotation takes them from 6 to 5.

LiveWhy credentials are the first door to close3 min▶

A credential edge is an attacker using a real identity's proof: the password, the key, the token, the session. Once they hold it, every control downstream sees a legitimate user. Grants, network policy, row-level security, all of it behaves correctly, because the warehouse is doing what the credential tells it to. That is why the credential door carries more paths than any other on Ironwood's graph, and why closing it changes the count more than any other single move.

It is also the cheapest door. MFA on human logins is a setting. Rotating a key is an afternoon if done in the right order, and a bad night if done in the wrong one. Neither requires a new product, and together they take Ironwood from nine paths to five before the storage, supply-chain and detection work has even started.

Real world

Ironwood's platform team knew about the key in the repository history. It had been "on the list" for eighteen months. The reason it was never rotated was not laziness; it was that nobody could say which pipelines depended on it, and the one time somebody tried, the 06:00 load failed and the rotation was reverted. The key stayed valid because the rotation had been done in the wrong order, and the failure taught the team that rotation was dangerous rather than that the order was wrong.

Self-studyFive words for tonight3 min▶
  • Credential edge - a move on the graph where the attacker acquires a real identity's proof: reads a key from history, phishes a password, steals a session token. Downstream of it, they are the user.
  • Second factor - proof that the person holding the password also holds a thing or a property: a device, a hardware key, a biometric. It closes the phishing edge because the password alone is no longer enough.
  • Rotation - issuing a new credential and retiring the old one. The retiring is the security event; the issuing is the plumbing that makes retiring survivable.
  • Expiry - the property that a credential stops working on a date whether or not anyone remembers it. A key with no expiry is a permanent door, and Ironwood's two-year-old key had none.
  • Privilege edge - a move where a credential the attacker already holds reaches more than it should: the Friday admin grant. Not a credential problem; a grant problem, closed by least privilege.
Part 1 · covers the four credential edges, the two controls, and what each does to the count

Four credential edges, two controls

9 min live

Every credential edge on Ironwood's inventory is closed by a control drawn as a gate on the graph. Two of the gates are tonight's. One belongs to the access-control course and is drawn here so the path it leaves open is honest.

start the credential edge the gate what it yields the estate the prize Internet Insider key in repo, 2 years phished analyst phished admin rotation MFA MFA ETL service key analyst login admin login Friday admin grant gate: least privilege, access course own account, no door to close Warehouse customers rotation closes the leaked copy only. the CI runner still holds the current key legitimately: closed in session 4 9 nothing on 6 + MFA on humans 5 + key rotation 1 at the end, after least privilege takes the last 3 to 1 Four credential edges. Two gates tonight take nine paths to five. The third gate belongs to the access course.
🔍 Click to zoom - four credential edges, the gate on each, and 9 to 6 to 5 beneath.
LiveThe key committed two years ago, and why rotation closes one path and not two3 min▶

A service key in a public repository's history is the most durable door on the graph. It does not phish anyone, it does not need luck, and it works from anywhere until somebody revokes it. Deleting the file from the repository does nothing: the commit that added it is still in history, and history is what a scanner reads. The only thing that closes the edge is the key no longer authenticating.

On Ironwood's ladder, rotation takes the count from 6 to 5, one path, even though two paths run through the ETL service key. The second is the CI runner, whose environment holds the key legitimately because it runs the pipeline. When the key is rotated the runner gets the new key, so a malicious package in the build still reaches a valid credential. Rotation closes the leaked copy; it cannot close the legitimate holder. That path is closed by pinning and verifying dependencies in session 4, and the distinction is exactly what the graph is for.

Real world

Ironwood's key had been committed in a connection-test script by a contractor whose account was deactivated eighteen months before the alert. The account was gone; the key it had committed was not. Enumerating identities found nothing wrong. Enumerating credentials, which means reading history, found the door.

LiveTwo phished passwords, one control: MFA takes 9 to 63 min▶

A phished password is a credential edge from the internet to a human login. On Ironwood's graph there are two: the analyst's and the admin's. Both are closed by the same control, because a second factor means the password alone no longer opens the door. The attacker still has the password; it has stopped being sufficient.

MFA removes three paths, not two, and the third is instructive. The phished analyst login reaches the warehouse directly, and it also reaches the admin login through the Friday grant. Closing the door at the internet closes both routes that start behind it. That is why MFA is the single highest-value edge removal on the graph: it is at the front of the chain, and everything behind it falls with it. 9 to 6.

What MFA does not do is touch the insider. The analyst's own login is their own; there is no phishing edge to close, and the Friday grant behind it remains. That is where the 6 comes from: the two paths that phishing opened and the one it opened through the grant are gone, and the insider's two are untouched.

LiveThe Friday admin grant: a credential edge that belongs to another control3 min▶

One Friday a load failed, the analyst needed to fix it, and somebody granted them the admin role to unblock the afternoon. The load ran. The grant stayed, for two years, because nobody had the job of taking grants back. On the graph it is an edge from the analyst login to the admin login, and it is the reason the analyst's own login is worth two paths on Ironwood's ladder: one as themselves, one as admin.

Nothing tonight closes it. MFA closes the door in front of the analyst login for an outsider; it does nothing about what the login reaches once somebody legitimate is behind it. Rotation is about keys. The control that closes this edge is least privilege, meaning the analyst role reads what the analyst's work requires and the admin grant is gone, and that is the territory of the access-control course, where grants, role hierarchy and access review are taught properly. It is drawn as a gate here so the count is honest: after every other control on the ladder, the three paths that remain include this one, and least privilege takes the last three to one.

Write the Friday grant on your own inventory as an edge with the closed-by cell reading "least privilege", not as a note. An edge gets counted. A note gets forgotten, which is how it survived two years the first time.

Self-studySession tokens: the credential edge behind the login4 min▶

After a login succeeds, the warehouse or its SSO provider issues a session token, and every subsequent request presents the token rather than the password. A stolen token is therefore a credential edge that bypasses both the password and the second factor, because the login already happened. It is the reason MFA is a very large reduction and not a complete one.

  • Short session lifetimes shrink the window in which a stolen token works. A token that lives for eight hours is a smaller door than one that lives for thirty days.
  • Binding a session to the device or the network it started from makes a token useless when presented from anywhere else. Not every provider supports it; where it exists it is the strongest of these.
  • Revoking sessions when a credential is rotated or a login is disabled. Changing a password does not end a session that is already open unless the sessions are ended too. Rotation and revocation are two separate actions.
  • Where the token lives is a credential-lane inventory item: a browser, a notebook's cached connection, a laptop's config file. Session 1's credential lane includes these; the login history shows which are in use.

Ironwood's graph does not model token theft as a separate edge, because the controls above are properties of the login edge rather than a new door. On your own inventory, write the session lifetime next to each human login. A number you cannot find is a finding.

Self-studyThe four edges in one table2 min▶
EdgePaths it carriesClosed byLadder effectOwner
Internet, public repo, ETL service key1Key rotation, old key expired6 to 5Tonight
Internet, phished analyst, analyst login2, one of them via the Friday grantMFA9 to 6, with the next rowTonight
Internet, phished admin, admin login1MFA9 to 6, with the previous rowTonight
Analyst login, admin login (Friday grant)1 remaining after MFA, the insider'sLeast privilege3 to 1, at the end of the ladderAccess-control course

Five paths through the credential door at the start. Four closed tonight, one handed on with its name and its control written down.

Part 2 · covers the rotation order, verifying the old key is dead, service accounts, and MFA fatigue

Rotation that does not break the ETL, and MFA that people keep

8 min live

Both of tonight's controls fail in the same way when done carelessly: they look finished and are not. A rotated key that still authenticates, and an MFA rollout that people learn to approve without reading, each leave the door exactly where it was with a fresh coat of paint on it.

the order that works 1 · Create the new key 2 · Store it in the secrets manager 3 · Repoint the pipeline to it 4 · Verify a full run succeeds 5 · Revoke the old, confirm it is refused the old key stays valid through steps 1 to 4, so nothing breaks. step 5 is the security event. without step 5, and without confirming the refusal, the door has a new coat of paint and nothing else. the wrong branch Revoke the old key first 06:00 load fails, nobody has the new key outage, then a rushed fix under pressure rotation reverted, old key back in service the lesson learned: "rotation is dangerous" wrong lesson Revoke last, then confirm the old key is refused. Revoking first is how a security fix becomes an outage.
🔍 Click to zoom - five steps in the order that works, and the branch that taught Ironwood the wrong lesson.
LiveThe rotation sequence, and why revoke is step five3 min▶

Rotation is five steps and the order is the whole discipline. New key first. Store it in the secrets manager, so that the pipeline reads it from there and not from a file or an environment variable somebody will commit next year. Repoint the pipeline to the new key. Verify a full run succeeds, not a connection test, a run, because the connection test is how Ironwood's key got committed in the first place. Then, and only then, revoke the old key.

Through steps one to four the old key is still valid, which means nothing can break: the pipeline has two working keys and is using one of them. Step five is the only step that changes the security of the estate, and it is the one that is safe to take by the time you reach it, because everything that depends on the key has already been proven to work without it. Revoking first inverts this. The pipeline has zero working keys, the load fails, and the fix is done at 06:00 under pressure, which is when the old key gets put back.

Warehouses that support two key slots on a service account exist for exactly this sequence. Set the new key in the second slot, repoint, verify, then unset the first slot. Where there is one slot, create a second service account with the same grants, migrate to it, and retire the first. The shape is the same; the slot is just where the second key lives.

LiveThe old key must actually stop authenticating2 min▶

A rotation is finished when the old key is refused, not when the new key works. The two are different facts and most rotation checklists verify only the first. Ironwood's key had been "rotated" once before the incident: a new key was issued and the pipeline moved to it, and the old key was left in place "for a few days, in case". The few days became eighteen months. The public repository still held a key that authenticated. The door had a new coat of paint.

Confirming the refusal is two checks. First, attempt to authenticate with the old key from a test host you control and expect a refusal; that is a test of your own credential against your own warehouse, and it is the only proof that revocation happened. Second, read the login history for the service account after the revocation timestamp and confirm that every successful authentication used the new key's fingerprint. A successful login on the old key after step five means step five did not happen, whatever the console said.

Then write the expiry date of the new key into the inventory file, because a key with no expiry is the same door two years from now. The inventory's credential lane carries an expiry column for exactly this reason.

LiveService accounts cannot do MFA, so they need a different shape3 min▶

MFA is a human control. It works because a person is present to hold a device and approve a prompt. A service account runs at 02:00 with nobody present, so a second factor is not available to it, and a password on a service account is a credential that can be phished from whoever knows it and can be committed to a repository by whoever uses it. The pattern that replaces MFA for a service account has three parts, and it is a pattern rather than a product.

  • Key-pair or federated authentication instead of a password. A private key that never leaves the secrets manager, or a short-lived token issued by the platform's own identity to the workload, so there is no long-lived secret to leak. Either way there is nothing to type and therefore nothing to phish.
  • Network allowlisting on the service account. The key authenticates only from the addresses where the pipeline runs. A leaked key that works from anywhere is Ironwood's baseline; a leaked key that works from three addresses is a much smaller door. This is the one thing the perimeter-only over-correction on the ladder gets right, and on a service account it is correct rather than an over-correction.
  • Expiry and rotation on a schedule, written into the inventory, so that the key that leaks next year has already stopped working by the time anyone reads it out of history.

None of this replaces the query log. A service account with a key pair, an allowlist and an expiry date still reads the customers table every night, and detection in session 5 is how you would notice it reading eleven thousand more rows than usual.

Self-studyMFA fatigue: the honest limit of a human control3 min▶

A second factor that a person approves is a control that depends on the person reading the prompt. Send enough prompts at the wrong hour and some fraction of people approve one to make it stop. This is not a failure of the person; it is the predictable behaviour of a control that turned a security decision into an interruption. It is also the reason MFA on Ironwood's ladder is a reduction from 9 to 6 and not a claim that phishing is solved.

  • Number matching, where the prompt shows a code that must be typed from the login screen, means an approval requires the person to be at the screen that started it. It converts "tap to approve" into "prove you are the one logging in".
  • Phishing-resistant factors, hardware keys and platform authenticators bound to the site's origin, do not produce a prompt an attacker can trigger from elsewhere. They are the strongest option and the one to use for admin logins first.
  • Fewer prompts: a session lifetime that means people authenticate a few times a week rather than a dozen times a day keeps the prompt meaningful. A control people meet forty times a day is a control they stop reading.
  • A prompt nobody sent is an alert. When a person reports an unexpected prompt, that is the phished-password edge being attempted in real time, and it is the cheapest detection on the whole estate. Make reporting it one tap, and make sure somebody reads the reports.

The professional norm is to state the limit plainly: MFA closes the phishing edge for the majority of attempts and raises the cost of the rest. It is a very large reduction, it is not zero, and the rest of the ladder exists because it is not zero.

Build-along

Close two doors on your own estate

★ 20 min · everyone builds

Every command here runs against your own repositories and your own warehouse, and every one of them closes or checks a door rather than walking through one. Bring the inventory file from session 1 and the count from the homework grep. If you have neither, use Ironwood's inventory and one test service account.

Run the secret scan over your own git history and count the hits. Every repository that has ever deployed to the warehouse, all branches, the full history. The count is the finding. Do nothing with the individual hits yet.

★ Try it now · your own repositories only git log -p --all | grep -iE 'password|secret|api[_-]?key|BEGIN (RSA|EC) PRIVATE' | wc -l # then list the commits that carry a hit, so each one can be traced to an account: git log --all --format='%h %ad %an' --date=short -S'PRIVATE KEY' | head

Ironwood's count was 3: the ETL key, a test-database password in a notebook, and a token for a tool that had been decommissioned. All three go on the inventory; only one of them still opened anything.

For each hit, identify the service account and what depends on it. Which user does the key belong to, what does that user hold grants on, and which pipelines have authenticated as it recently. The last question is the one that prevents the outage, and it is answered from the login history, not from memory.

★ Try it now · who is this key, and who uses it show grants to user etl_service; -- every client that authenticated as the account in the last 30 days: this is the dependency list select client_ip, reported_client_type, count(*) as logins, max(event_timestamp) as last_seen from login_history where user_name = 'ETL_SERVICE' and event_timestamp > dateadd(day, -30, current_timestamp()) group by 1, 2 order by logins desc;

Column names vary by warehouse; the shape does not. Three addresses and one client type is a pipeline. Fourteen addresses and four client types is a key that has been shared, and every one of them has to be repointed before step five.

Rotate one key by the five-step sequence. New key, secrets manager, repoint, verify a full run, then revoke. On a warehouse with two key slots the shape is below; the private key is generated on a host you control and goes straight into the secrets manager, never into a file in a repository.

★ Try it now · the five steps, revoke last -- 1 create: generate the key pair on a trusted host; the private half goes to the secrets manager -- 2 store: secrets manager path warehouse/etl_service/key_2 (never a repo, never an env file) -- 3 repoint: register the new public key in the second slot while the old one still works alter user etl_service set rsa_public_key_2 = '<REDACTED public key>'; -- then point the pipeline's connection at the secrets-manager path for key_2 -- 4 verify: run the full pipeline, not a connection test, and check it read key_2 -- 5 revoke, only after 4 succeeds: alter user etl_service unset rsa_public_key;

Ironwood's previous attempt ran step five first and reverted at 06:10. In this order there is nothing to revert, because by step five the pipeline has already proven it does not need the old key.

Confirm the old key no longer authenticates. Two checks, both against your own account. Attempt a connection with the old key from a test host and expect a refusal. Then read the login history after the revocation and confirm every success carries the new key's fingerprint. A rotation without this step is a rotation on paper.

★ Try it now · prove the refusal -- from a test host, with the OLD key only: expect "authentication failed" and nothing else -- then confirm from the log that no success used the old key after the revoke timestamp select event_timestamp, is_success, first_authentication_factor, client_ip from login_history where user_name = 'ETL_SERVICE' and event_timestamp > '<revoke timestamp>' order by event_timestamp;

Write the new key's expiry date into the inventory's credential lane while the window is open. A key without an expiry is tonight's door again in two years.

List every human login without a second factor from the user inventory. Not the service accounts, which need the key-pair pattern instead. Every row on this list is a phishing edge on your graph, and the admins go first.

★ Try it now · the phishing edges, by name -- humans only, still enabled, no second factor enrolled; column names vary by warehouse select name, default_role, last_success_login from users where type is null and disabled = false and has_mfa = false order by case when default_role like '%ADMIN%' then 0 else 1 end, last_success_login desc;

Ironwood's list had eleven names, two of them admins. MFA on all eleven is the 9-to-6 rung, and the two admins are the half of it that matters most.

Write the two edges you just closed into the inventory file's "closed by" column, with the date. The file is what session 8 scores. An edge whose closed-by cell is filled and dated is a path that the bench will no longer count; an edge that was closed but not written down is a control nobody can find next year.

★ The inventory file after tonight # from -> to | the move | closed by | seen by internet -> repo | public repo holds a committed key | | repo -> svc_key | key read out of repo history | key rotation, old key refused, 2026-09-08 | internet -> user_analyst | phished password, no second factor | mfa, all humans, 2026-09-08 | internet -> admin | phished admin password, no second factor | mfa, all humans, 2026-09-08 | user_analyst -> admin | admin role granted on a Friday, never revoked | least privilege (access course) | ci_runner -> svc_key | runner environment holds the current key | pinned dependencies (session 4) |

The count in the first step is a number to report, not a list to publish. The hits themselves are credentials, even the dead ones, and they stay in the incident team's notes and nowhere else. The inventory file records that a key was in history and that it was rotated; it never records the key.

Homework

Before session 3

30 min
  1. Rotate every remaining hit from the scan by the five-step sequence, one per day, revoke last, refusal confirmed. Write the expiry of each new key into the inventory.
  2. Enrol every admin login in a phishing-resistant second factor this week and every other human login within the month. Write the session lifetime for each next to it; a lifetime nobody can find is a finding.
  3. For every service account, record which of the three parts of the pattern it has: key-pair or federated authentication, a network allowlist, a scheduled expiry. Three blanks is Ironwood's baseline.
  4. Find the Friday grants on your estate: every role granted to a human that is wider than their job, with the date it was granted and whether anyone owns taking it back. Do not revoke them tonight; write them as edges with "least privilege" in the closed-by cell, and take the list to whoever runs access review.
Check yourself

Three questions

Why is revoking the old key the fifth step of a rotation and not the first?

Revoking first leaves the pipeline with zero working keys, the load fails at 06:00, and the fix under pressure is to put the old key back. Ironwood's key survived eighteen months on exactly that lesson.

Two of Ironwood's paths run through the ETL service key, yet rotation takes the count from 6 to 5, one path. Which path stays open, and why?

A malicious package in the build still reaches a valid key after rotation, because the runner needs a valid key to run the pipeline. That edge is closed by pinning and verifying dependencies, not by rotation.

MFA on every human login closes the phishing door in front of the analyst. Why does the Friday admin grant still count as a path afterwards?

MFA removes what an outsider can do with a stolen password. It does nothing about what a legitimate login reaches once someone is behind it. The analyst is worth two paths until the grant is gone, and that is the last rung of the ladder, 3 to 1.

Sources covered

What tonight maps to

✓ Credential paths on a data estate Keys in git history, phished passwords with no second factor, session tokens, the Friday admin grant. MFA 9 to 6, rotation 6 to 5 on the attack-path bench.
✓ Secret scanning of your own history and key rotation with expiry Widely documented practice, taught as a pattern with the reason: the five-step order, revoke last, confirm the refusal, record the expiry. No vendor claims.
✓ Service-account authentication pattern Key-pair or federated authentication, network allowlisting, scheduled expiry, as the replacement for a second factor that a workload cannot hold.
◐ Grants, role hierarchy, secrets hygiene, access review Assumed, not taught; the access-control course owns them. Here they appear as the edge the Friday grant leaves open until least privilege closes it, 3 to 1.
◐ NIST CSF 2.0 - Protect function Tonight's two controls are Protect outcomes. The six functions and where each lands on a data estate are leader session 2.
· Phishing techniques, credential cracking, offensive tooling Not covered by design. Every step stops at the door, the control that closes it, and the log that would see it used.

Session 2 cheat sheet

Four credential edgesKey in repo history, phished analyst, phished admin, the Friday admin grant. Five of nine paths.
MFA: 9 to 6Closes the phishing door for analysts and admins, and everything behind it. Does not touch the insider.
Rotation: 6 to 5Closes the leaked copy of the key. The CI runner holds the current key legitimately; that path is pinning, session 4.
Revoke lastNew key, secrets manager, repoint, verify a full run, then revoke. Revoke first is how a fix becomes an outage.
Prove the refusalOld key refused from a test host, and no success on it in the login history after the revoke. Otherwise the door has new paint.
Service accountsNo MFA possible. Key-pair or federated auth, network allowlist, scheduled expiry. Still logged.
MFA fatigue is realNumber matching, phishing-resistant keys for admins, fewer prompts, and an unexpected prompt is an alert.
The Friday grantAn edge, not a note. Closed-by reads "least privilege"; it takes the last 3 paths to 1 at the end of the ladder.