---
title: "Who Deploys the Deployers?"
date: "2026-08-11"
publish_date: "2026-09-17"
excerpt: "The GitHub Actions role that deploys my infrastructure is itself created by that infrastructure. Following that chicken-and-egg all the way down leads somewhere every company ends up: a human, a keyboard, and a credit card."
tags: ["aws", "security", "devops", "cdk"]
author: "Martin Harris"
canonical: "https://blog.nakomis.com/2026-08-11-who-deploys-the-deployers"
approved: true
---

# Who Deploys the Deployers?

![A stack of turtles ascending into clouds, each turtle carrying a small server on its back, and at the very bottom a person sitting at a desk holding a bank card](images/who-deploys-the-deployers-1.png)

My blog-pipeline project deploys itself from GitHub Actions. The workflow assumes an IAM role via OIDC, the role trusts the specific repo and branch, least privilege throughout — all thoroughly modern and correct.

The role is created by CDK. It's a stack in the repo, `GithubCiStack`, right alongside the stacks it exists to deploy.

Spot the problem. The first deployment cannot run through CI, because there is no role for the workflow to assume until something deploys the stack that creates the role. So the repo's README has a section titled "First deployment", and that section says, in effect: run `cdk deploy` from your laptop, once, as yourself. There's no way around it. The pipeline's own identity has to be bootstrapped by something that isn't the pipeline.

That little chicken-and-egg annoyed me enough to follow it properly, and it goes somewhere more interesting than a README caveat.

## How companies make this disappear

Every sizeable company I've worked with recently enforces the same rule: *nobody can deploy to production directly*. All changes go through the pipeline. And yet somebody clearly set the pipeline up — so how do they square it?

The answer, in practice, is that repo creation is a product. There's a `create-new-github-repo` app — an internal service you fill in a form for. That app, not the application repo, provisions the repository, the OIDC trust relationship, and the deploy role. The application repo never contains the bootstrap of its own deploy identity; by the time a developer pushes their first commit, the identity already exists, conjured by something they never see.

So "nobody can deploy directly" is true — *for the app repo*. The privilege hasn't gone anywhere. It has moved into the repo-factory's identity, out of sight of the people the rule applies to.

## The generalisation

This is the pattern everywhere you look: automation never *eliminates* a privileged credential. It *relocates* and *concentrates* it.

The repo-factory has an identity. That identity was granted by something — the platform team's bootstrap pipeline, probably. Which was set up under the account structure. Which was created by the landing-zone tooling. Which runs in the AWS Organisation. Each layer honestly says "no human deploys through me", and each layer was brought into existence by the layer below.

![A vast automated factory of conveyor belts and robotic arms assembling other robotic arms, receding into the distance, with one small door at the far end marked by a single warm light](images/who-deploys-the-deployers-2.png)

## The floor

The chain is not infinite. Turtles all the way down has a floor, and the floor is a person.

In every company that uses AWS — or GCP, or Azure — there is a human who, once, sat at a keyboard, created the Organisation, entered root credentials, and typed in a credit card number. There is no automating that first act, for two reasons that are worth separating. The first is mechanical: there was nothing yet to do the automating. The second is more fundamental: a payment instrument is a real-world commitment, and a machine cannot make it on its own authority. Somebody with the legal standing to spend the company's money had to bind the company to the bill.

Every pipeline, every OIDC federation, every least-privilege role, every "nobody can deploy to prod" control in the estate ultimately descends from that one human act of typing sixteen digits.

## Where the trust rests

Which reframes the question I started with. The interesting question is never "can this be fully automated?" — it can't, not all the way down, and pretending otherwise just hides the residue. The question is: *where does the trust finally rest, and is that the right place?*

Good security engineering is not the removal of the trusted human. It's making that human **few** (a handful of people, not whoever got there first), **deliberate** (a documented break-glass act, not an ambient capability), **audited** (the act leaves a record), and **rarely invoked** (the credential lives in a safe, not a shell profile). And — the part that's easy to skip — being honest that they exist.

A pipeline that pretends no one holds the keys is more dangerous than one that knows exactly who does. The pretence doesn't remove the keyholder; it just removes the audit trail, the rotation policy and the conversation about whether it should be them.

My version of all this is one line in a README: the first `cdk deploy` is manual, it's me, and it says so. Small estate, same shape. Somebody deploys the deployers. Better to write their name down.

---

*Martin Harris connects cloud infrastructure to the real world. If your entire zero-trust architecture rests on someone once reading a credit card number over their shoulder, you're in the right place.*


{{donate}}
