There is a file open in front of me that can never be allowed to leave this machine.
A small block of plain text, in a folder full of other small blocks of plain text.
And every one of its neighbors exists to be shared. Copied. Published.
Inside this one is the key to an account named superadmin.
Administrator access. Not a nickname. That is the actual permission, spelled out.
resource "aws_iam_user" "superadmin" {
name = "superadmin"
path = "/limitless/"
}
resource "aws_iam_access_key" "superadmin" {
user = aws_iam_user.superadmin.name
}
resource "aws_iam_user_policy_attachment" "superadmin_access" {
user = aws_iam_user.superadmin.name
policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}
One key. It can read the company mail, tear down the cluster, or stand up a hundred machines and bill every one of them to the same card.
And it is on disk because the project asked for it.
Directly above the line that mints that key sits a note. These keys have administrator access. Protect them well.
And underneath the warning, the instructions. How to pull the secret back out, and hand it to the command line tool.
# Note: These keys have superadmin access! Protect them well.
# To see the secret key, use:
# terraform console
# nonsensitive(module.iam.AWS_ACCESS_KEY_ID)
# nonsensitive(module.iam.AWS_SECRET_ACCESS_KEY)
# aws configure
That is the bargain the tooling makes with you. It will not take a secret out of the air. It wants it written down.
Right next to your work.
And the folder it lands in is a folder that remembers everything.
Version control has no delete key. Taking the file out tomorrow does not take it out. It writes a note saying the file went away underneath the perfect copy it is still holding.
Committed once is committed permanently... on every machine that ever pulled this project down.
So today, the work is one line.
The ignore list grows by a single entry: credentials.json. Never picked up. Never sent anywhere.
It lands right under the private keys, which sit under the variable files a stock template already flagged as likely to hold passwords.
# keys
*.pem
credentials.json
It is not clever. It never executes, and nobody will ever watch it work.
That is the entire job.
The ignore list is the only file here written completely in the negative. A running tally of every mistake somebody decided, ahead of time, not to make.
And a line like that only saves you if you write it before the day you need it.
One Line
Welcome back.
I want to be upfront about the scale of today's work, because it's going to sound like a joke.
Today's work is one line. Not one file. One line, appended to the bottom of an existing list.
And I'm going to spend the rest of this episode on it, because the line is a decision, and the decision has a blast radius that is genuinely difficult to overstate.
The line is the name of a file. credentials.json. It goes into the ignore list — the file that tells version control which files to pretend it can't see.
So the first question is the only interesting one. Why does a file with that name exist on this machine at all?
Superadmin
For that, we have to look at the identity module, which is where this project defines who is allowed to do what.
Most of that file is what you'd hope for. There's a directory of real people, each with a given name, a family name, and a work address. There's a group called Internal Users, and everybody lands in it. There's a permission set scoped to exactly one thing — mail access — and that permission set gets assigned to the group.
resource "aws_identitystore_group" "internal_users" {
identity_store_id = tolist(data.aws_ssoadmin_instances.limitless.identity_store_ids)[0]
display_name = "Internal Users"
description = "Users with a basic level of access"
}
resource "aws_ssoadmin_permission_set" "workmail" {
instance_arn = tolist(data.aws_ssoadmin_instances.limitless.arns)[0]
name = "WorkMail"
description = "Access to WorkMail"
}
resource "aws_ssoadmin_managed_policy_attachment" "workmail_full" {
instance_arn = tolist(data.aws_ssoadmin_instances.limitless.arns)[0]
managed_policy_arn = "arn:aws:iam::aws:policy/AmazonWorkMailFullAccess"
permission_set_arn = aws_ssoadmin_permission_set.workmail.arn
}
That's single sign-on. People log in as themselves, get a short-lived session, and that session can do one job.
And then, sitting above all of that, there's a different kind of thing entirely.
A user account named superadmin.
With an access key minted for it.
And one policy attached, by name: Administrator Access.
That's not a label somebody typed. It's the canonical managed policy — the one that grants every action, on every resource, in the account. Not "most things." Not "everything except billing." Every action. Every resource.
A Permanent, Portable Grant
And it's worth being precise about what an access key actually is, because it's a different animal from the sign-on sessions we just talked about.
A session is issued to a person who proved who they were, it's scoped, and it expires — usually in hours. If it leaks, it leaks with a clock on it.
An access key is two strings. An identifier, and a secret. It has no expiry. It doesn't care where the request came from, what machine, what country, what time of day. Anyone holding both strings is that user, completely, until somebody actively goes and turns the key off.
So the key we're talking about is a permanent, portable, unconditional grant of total control over the account.
What That Concretely Reaches
And it's worth spending ten seconds on what that concretely reaches, because "admin access" is one of those phrases that goes abstract the moment you say it.
Everything we've built in this project so far is downstream of that key. The mail for two companies — the mailboxes themselves, and the records that decide where inbound messages land. The staff directory. The cluster, and everything running on it. The client sites. The zones, which means the ability to point any of those names anywhere.
It also reaches things nobody built. Holding that key, you can create machines. As many as the account will allow, in every region, and the bill for all of them lands on the same card. That's the failure mode that shows up most often in practice, and it's rarely subtle — it's usually the largest invoice the company has ever received, arriving about a week after nobody noticed anything.
And it reaches the audit trail, which is the part people forget. Total control includes control over the record of what was done.
You Can't Bootstrap Single Sign-On Using Single Sign-On
So why does a key like that exist at all, when the same file goes to real trouble to give everybody else scoped, expiring sessions?
Because you can't bootstrap single sign-on using single sign-on.
Something has to create the identity service before anybody can log into it. Something has to hold enough authority to grant authority. That first credential can't come from the system it's building, so it comes from outside, and it necessarily outranks everything it makes.
Every system with an identity layer has one of these somewhere. The root account, the break-glass credential, the key in the safe. This project's version is written down, in the open, with a comment above it explaining what it is — which is a more honest arrangement than most.
But it does mean the two strings are the most valuable object anywhere in this repository, by a wide margin.
Protect Them Well
Now. The outputs file. This is the part I actually want to walk through slowly, because it's a genuinely elegant piece of documentation and it's also the reason today's line is necessary.
At the top of that file is a comment. Two sentences.
These keys have superadmin access. Protect them well.
And then, directly underneath that warning, the instructions for how to get them out.
Four steps. Open the interactive console. Ask for the identifier. Ask for the secret. Hand both to the command line tool's configuration command.
# Note: These keys have superadmin access! Protect them well.
# To see the secret key, use:
# terraform console
# nonsensitive(module.iam.AWS_ACCESS_KEY_ID)
# nonsensitive(module.iam.AWS_SECRET_ACCESS_KEY)
# aws configure
output "AWS_ACCESS_KEY_ID" {
value = aws_iam_access_key.superadmin.id
description = "Access Key for Superuser"
}
output "AWS_SECRET_ACCESS_KEY" {
value = aws_iam_access_key.superadmin.secret
sensitive = true
description = "Secret Access Key for Superuser"
}
I don't say that as a gotcha. That is a good comment. Whoever wrote it knew somebody would need to do this, understood that they'd be doing it in a hurry, and wrote down the recipe so it wouldn't get improvised badly at eleven at night. Warning first, then the procedure. That's the right order.
A Guardrail, and Its Official Documented Bypass
But look at what the recipe has to defeat to work.
The secret output is marked sensitive. That's a real flag in the language, and it does a real thing: it stops the value from being printed. Run a plan, run an apply, list your outputs — the tool prints the words "sensitive value" and refuses to show it.
So the recipe wraps each one in a function whose entire purpose is to strip that flag off. There is a built-in function that exists solely to say: yes, I know this was marked sensitive, show it to me anyway.
A guardrail, and its official documented bypass, four lines apart in the same file.
And I want to be clear that this isn't a flaw in the design. It's an honest one. The flag was never a security boundary — it's a shield against accidental disclosure, against the value scrolling past in a terminal that's being screen-shared, or landing in a build log that gets kept for ninety days. Deliberate retrieval was always supposed to be possible. That's what makes it a guardrail instead of a wall.
It Doesn't Protect the State File
There's a second thing that flag doesn't do, and it matters more.
It doesn't protect the state file.
When this tool builds anything, it writes down everything it built, and everything it learned, into a state file. That's how it knows what already exists. And every attribute goes in there — including the secret half of that key, in the clear, as plain readable text. The sensitive marking governs what gets displayed. It has nothing to say about what gets stored.
Which the project already knows. The ignore list has covered state files from the beginning, and it also covers variable files, and it does so under a comment that ships with the standard template — one that says, in so many words, that those files are likely to contain passwords, private keys, and other secrets, and should not be part of version control.
# .tfstate files
*.tfstate
*.tfstate.*
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
# password, private keys, and other secrets. These should not be part of version
# control as they are data points which are potentially sensitive and subject
# to change depending on the environment.
*.tfvars
*.tfvars.json
So the pattern is established. Anything that ends up holding a secret gets a line. Today just adds one more category to a list that was already doing this job.
Next to Your Work
So back to the file itself. Where does a file with that name come from?
I'm genuinely not certain, and I'd rather say so than guess confidently. The command line tool's own configuration step writes to a hidden folder in the home directory, not into the project. So this is probably something else — a helper, an extension, a language library — writing its own credential file the way a lot of tools do.
But here's the part that isn't uncertain at all. This project is developed inside a container, and the container is configured to mount the project folder as the workspace. That's the whole point of the setup: everybody who opens it gets the same tools, at the same versions, pointed at the same directory.
So the working directory is the repository. A tool that writes a credential file "next to your work" has written it inside a folder that version control is watching.
Nobody chose that. It's just where you happen to be standing.
Deleting Is an Append
And the folder you happen to be standing in is a folder that remembers everything.
This is the mechanism I most want you to leave with, because most people's mental model of version control is wrong in exactly the way that hurts here.
The intuition is that a repository is a folder with an undo button. Files go in, files come out, and the history is a log of what changed. Under that model, deleting a file removes it, and the log just notes that it went away.
That's not how it works.
When you commit a file, its exact contents get stored as an object, named by a hash of those contents. The commit points at a snapshot, the snapshot points at that object, and the object is now a permanent resident of the database.
Delete the file tomorrow and you create a new snapshot that doesn't mention it. That's all. The old snapshot still exists, still points at the same object, and the object is still sitting there, byte-for-byte intact, one command away from anybody who has the repository.
There's no delete. Deleting is an append.
You Cannot Delete It
Which is why the cleanup, if it ever comes to that, is so much worse than people expect.
Getting the object out means rewriting history — recomputing every commit from the bad one forward, which changes every identifier downstream of it. Anybody with a copy now has a divergent history and has to be told, by hand, what to do about it.
And that's just your copy. Every clone that ever ran still has the object. Every fork. Every build agent with a cached checkout. If it went to a hosted service, that service may still serve the object by its hash even after the branch stops referencing it.
So the honest version is: you cannot delete it. You can only turn the key off and issue a new one, and then go find every place the old one was configured.
Which, for a key with Administrator Access, means the rotation is the easy part. Working out what happened while the key was out there is the hard part.
Minutes, Not Days
And the window is not generous. Public code hosts are continuously crawled by automated scanners looking for exactly this shape of string. Credentials pushed to a public repository have been observed getting used in minutes. Not days. Minutes.
Which is a strange kind of mercy, honestly. The fast version is survivable, because you find out. The version that ruins your year is the one where nothing happens for eight months.
The Absence of a Decision
Now, it's worth being clear about what actually goes wrong here, because it isn't villains and it isn't carelessness.
Committing a file takes two steps. You stage it, then you commit what's staged. And essentially nobody stages files one at a time. You stage everything in the current directory, with a command most people have bound to two keystrokes, or you click the button in the editor that says stage all changes.
That command doesn't know which of those files you meant. It sweeps the folder. And the credential file is sitting in the folder, because that's where the tool that wrote it decided to put it.
So the failure isn't a decision anybody makes. It's the absence of one — a reflex that works correctly ten thousand times and then, once, picks up something extra. Usually while you're finishing something else, thinking about something else, at the end of a day.
Which is why the defense has to be structural rather than behavioral. You can't solve this by being careful, because the whole problem is that the action is one you take without being careful, on purpose, because being careful about it every single time would be unbearable.
An ignored file simply isn't in the sweep. It doesn't appear as a change, so the reflex can't catch it. The guardrail sits at the level where the mistake actually happens.
Written Today, It's Complete Protection
So. One line. And there's a detail in how the ignore list works that makes the timing of that line the entire point.
The ignore list only governs files version control isn't already tracking.
If a file has never been committed, adding its name means it stays invisible — it won't show up as a change, it won't get swept into a broad "add everything" command, it won't be sitting there tempting you at the end of a long day.
But if the file has already been committed, adding the name does nothing at all. Version control keeps tracking it. Every future edit still gets recorded. The pattern is silently ignored, because the file has already been claimed.
So this line is only worth anything because of when it was written. Written today, it's complete protection. Written after the fact, it's a comment.
That's the whole shape of the thing. It's a mistake you can only prevent, never fix.
Under Keys
And where it lands is worth a moment too.
It goes at the very bottom, under a heading that says, simply, keys. The only other entry under there is the pattern for private key files — certificates, signing keys, the things that let a machine prove it's the machine it says it is.
So the new line joins a category, and the category is one somebody already thought about. That's the difference between a codebase that has a habit and a codebase that has a pile of one-off fixes.
Written Entirely in the Negative
I've been thinking about what kind of file the ignore list actually is, and I keep landing in the same place.
It's the only file in this repository written entirely in the negative.
Everything else here describes something that should exist. A network, a mailbox, a certificate, a user. Run it and the world gets bigger. Every one of those files is a promise about what will be built.
The ignore list is the opposite. It never executes. It builds nothing, it starts no process, and no server anywhere is running because of it. It's a list of things that should not happen.
Which makes it, if you read it end to end, a fairly moving document. It's a running tally of every specific way somebody decided, ahead of time, not to get hurt. State files, because they hold everything. Variable files, because the template warned about them. Crash logs, because those capture whatever was in memory. Private keys, because obviously. And now a credential file, because somebody looked at where their tools write things and thought about it for thirty seconds.
# Crash log files
crash.log
crash.*.log
Nothing Was Built Today
So let's total it up.
Nothing was built today. No resource was created, no permission was changed, no address was moved. Run the plan before and after and it produces the identical result — because the change isn't infrastructure. It's a note to the tooling about what to keep out.
The key still exists. It still has Administrator Access. The warning above it still says protect them well, and the recipe underneath still explains exactly how to pull the secret out and put it on a disk. All of that is unchanged, and all of it is deliberate — that key is how the account gets built.
What changed is that the place the secret lands is now a place the repository refuses to look.
Nobody will ever be thanked for this line. It doesn't run, it can't be tested, it will never appear in a demonstration, and the outcome it produces is indistinguishable from the outcome where nobody bothered.
That's most of the good work in this business. Not the thing you build. The thing that quietly never happens.
Version control has no delete key.
And a line like this only saves you if you write it before the day you need it.