# Dev, Staging und Prod vom ersten Tag an: warum ein Dreierteam nicht warten sollte

„Wir trennen die Umgebungen später, wenn wir Nutzer haben.“ Diesen Satz haben wir von jedem kleinen Team gehört, mit dem wir gearbeitet haben, und wir haben ihn selbst gesagt. Er klingt nach Umsicht: bau keine Infrastruktur, die du noch nicht brauchst. Tatsächlich ist er ein Kredit, aufgenommen zum schlechtestmöglichen Zinssatz, und dieser Artikel ist der Tilgungsplan.

Wir haben [die Anleitung geschrieben](/de/blog/aws-three-accounts-one-cdk-codebase), wie man drei AWS-Konten aus einer CDK-Codebasis betreibt. Dies ist das Warum, gerichtet an das Team, das ein Konto mit allem darin hat und einen guten Grund, es noch ein Quartal so zu lassen.

## Was „später“ kostet

Umgebungen am ersten Tag zu trennen ist ein Tag Arbeit. Sie im sechsten Monat zu trennen ist eine Woche. Sie im achtzehnten Monat zu trennen ist ein Monat, plus ein Risiko, das Sie nicht beziffern können. Die Kosten wachsen nicht linear; sie wachsen mit der Anzahl der Dinge, die Zustand und Namen angesammelt haben.

<div class="article-figure">
<svg viewBox="0 0 900 260" width="100%" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Diagramm des Aufwands, Umgebungen zu trennen, gegen das Alter des Projekts. Am ersten Tag ist es etwa ein Tag. Im sechsten Monat etwa eine Woche, weil Datenbank, Secrets und DNS echte Daten und echte Namen haben. Im achtzehnten Monat etwa ein Monat, mit einem schattierten Risikoband, weil Produktionsdaten ohne Ausfall aus dem geteilten Konto bewegt werden müssen und jede Integration auf das alte Konto zeigt. Eine zweite flache Linie zeigt die laufenden Kosten von drei Umgebungen von Anfang an: etwa 60 Dollar im Monat.">
<g font-family="Inter,system-ui,sans-serif" font-size="12">
<text x="20" y="24" fill="#f1f3ff" font-size="14" font-weight="700">Aufwand für die Trennung der Umgebungen vs. Projektalter</text>
<line x1="70" y1="220" x2="870" y2="220" stroke="#9aa3c7"/><line x1="70" y1="40" x2="70" y2="220" stroke="#9aa3c7"/>
<text x="70" y="240" text-anchor="middle" fill="#9aa3c7" font-size="10">Tag 1</text><text x="370" y="240" text-anchor="middle" fill="#9aa3c7" font-size="10">Monat 6</text><text x="770" y="240" text-anchor="middle" fill="#9aa3c7" font-size="10">Monat 18</text>
<text x="64" y="216" text-anchor="end" fill="#9aa3c7" font-size="10">1 Tag</text><text x="64" y="150" text-anchor="end" fill="#9aa3c7" font-size="10">1 Woche</text><text x="64" y="60" text-anchor="end" fill="#9aa3c7" font-size="10">1 Monat</text>
<path d="M70,214 C200,212 300,180 370,150 C500,110 650,80 770,56" fill="none" stroke="#ff6b8a" stroke-width="2.5"/>
<path d="M600,90 C700,70 770,56 800,50 L800,120 C740,110 650,120 600,130 Z" fill="#ff6b8a" opacity="0.12"/>
<text x="700" y="140" text-anchor="middle" fill="#ff6b8a" font-size="10">+ Risiko: Prod-Daten aus einem geteilten Konto bewegen</text>
<circle cx="70" cy="214" r="5" fill="#4fffb0"/><text x="84" y="206" fill="#4fffb0" font-size="11">3 Konten, 1 Config-Map, je 1 OIDC-Rolle</text>
<circle cx="370" cy="150" r="5" fill="#ffd166"/><text x="384" y="146" fill="#ffd166" font-size="11">Datenbank, Secrets, DNS haben Namen und Daten</text>
<circle cx="770" cy="56" r="5" fill="#ff6b8a"/><text x="760" y="46" text-anchor="end" fill="#ff6b8a" font-size="11">jede Integration zeigt auf das alte Konto</text>
<line x1="70" y1="200" x2="870" y2="200" stroke="#4fffb0" stroke-width="1.5" stroke-dasharray="5,4"/><text x="868" y="196" text-anchor="end" fill="#4fffb0" font-size="10">laufende Kosten von 3 Umgebungen ab Tag 1: ~$60 / Monat</text>
</g>
</svg>
</div>

Im sechsten Monat hat die Datenbank echte Daten und einen echten Namen. Secrets wurden an drei Stellen kopiert. DNS zeigt auf Dinge. Auf jemandes Laptop gibt es ein Profil namens `default`, das in das einzige Konto deployt, das es gibt. Produktion aus diesem Konto herauszuziehen heißt, [zustandsbehaftete Ressourcen in neue Stacks zu importieren](/de/blog/cloudformation-500-resource-limit-split-a-stack), jeden Webhook und jede Integration umzuhängen, jedes geteilte Secret zu rotieren, und das ohne Ausfall. Wir haben es gemacht. Es ist ein Projekt mit Runbook, und das Runbook hat einen Rollback-Abschnitt, und den möchte man lieber nicht brauchen.

## Die drei Dinge, die in einem Konto schiefgehen

Wir argumentieren nicht aus der Theorie. Jedes davon ist einem Team passiert, mit dem wir gearbeitet haben, und eines davon uns.

**Testdaten in Produktion, oder Produktionsdaten im Test.** Mit einem Konto ist „die Datenbank“ ein Cluster, und die Trennung ist ein Schemaname oder ein Tabellenpräfix. Ein Migrationsskript mit falschem `search_path`, ein Seed-Befehl in der falschen Shell, eine Analyseabfrage auf die falsche Tabelle: jedes ist ein Ein-Zeichen-Fehler, und jedes ist passiert. In getrennten Konten ist der Falsches-Konto-Fehler immer noch möglich, aber er erfordert das Annehmen einer anderen Rolle, und das Deploy-Tooling kann [das ohne expliziten Flag verweigern](/de/blog/same-tag-deploy-and-the-deploy-script-without-ci).

**Ein Deploy, der für Dev gedacht war.** [Unser Vorfall](/de/blog/cloudformation-deleted-our-app-runner-services): ein `cdk deploy` von einem Laptop, mit falschem Kontext, löschte jeden App-Runner-Service in einer Umgebung. Es war die Dev-Umgebung, im Dev-Konto, und der Gesamtschaden war ein Nachmittag. Derselbe Befehl löscht in einem Ein-Konto-Setup die Produktion. Die Kontogrenze hat den Fehler nicht verhindert; sie hat ihn begrenzt. Das ist der ganze Wert.

**Der Hotfix „nur dieses eine Mal“.** Ein Konto ohne Staging bedeutet, dass der einzige Ort, an dem ein Fix getestet werden kann, die Produktion ist. Also geht der Fix nach Produktion, und er funktioniert, und der nächste auch, und irgendwann ist der Deploy-Prozess des Teams „auf main pushen und zuschauen“. Die Gewohnheit ist keine Dummheit. Sie ist die rationale Antwort darauf, nirgends sonst hinschauen zu können. Geben Sie den Leuten ein Staging-Konto für $20 im Monat, und sie nutzen es, weil es da ist.

## Was „vom ersten Tag an“ tatsächlich heißt

Der Einwand gegen frühe Trennung ist meist das Bild einer Landing Zone: Control Tower, eine Organisation mit einem Dutzend OUs, Service Control Policies, ein Shared-Services-Konto, zentralisiertes Logging, ein Netzwerkkonto mit Transit Gateway. Das ist ein Monat Arbeit und das Richtige für ein Unternehmen mit fünfzig Engineers. Es ist das Falsche für drei, und es ist nicht das, was wir vorschlagen.

Das Minimum, das fast den gesamten Wert einfängt:

| Am ersten Tag tun | Überspringen, bis Sie es brauchen |
|---|---|
| Eine AWS Organization mit drei Mitgliedskonten: dev, staging, prod | Control Tower, Landing-Zone-Beschleuniger |
| Eine `config`-Map in der CDK-Codebasis, nach Umgebung geschlüsselt | Organisationseinheiten jenseits der Standard-OU |
| Eine [OIDC-Deploy-Rolle pro Konto](/de/blog/github-oidc-deploy-roles-per-aws-account), nach Branch eingeschränkt | Service Control Policies |
| `RemovalPolicy.RETAIN` und Löschschutz in Prod | Shared-Services- oder Netzwerkkonten |
| Eine konsolidierte Abrechnungsansicht, nach Umgebung getaggt | Zentralisiertes CloudTrail in ein Sicherheitskonto |
| Ein Deploy-Skript, das Prod ohne `--env prod --yes` verweigert | Kontenübergreifendes VPC-Peering |

Das ist ein Tag. Der CDK-Diff von einer Umgebung auf drei ist die Config-Map und der `env`-Kontextwert; alles andere im Stack ist bereits parametrisiert oder sollte es sein. Und die drei Konten kosten in Minimalgröße, mit pausiertem Aurora und App Runner bei 0,25 vCPU, [etwa $60 im Monat mehr](/de/blog/aws-bill-of-a-three-person-startup) als eines. Das ist der gesamte Aufpreis, und er ist weniger als eine Stunde des Engineers, der sonst die Migration im achtzehnten Monat machen würde.

## Was Sie am zweiten Tag bekommen

Trennung ist nicht nur eine Sicherheitseigenschaft. Sie macht mehrere andere gute Dinge möglich, und die sind es, die sie bezahlen:

- **[Preview-Umgebungen pro Pull Request](/de/blog/preview-environments-per-pull-request-on-aws)** brauchen einen Ort, an dem jeder alles deployen kann, ohne zu fragen. Das ist das Dev-Konto, mit einer permissiven OIDC-Trust-Policy, die in Prod inakzeptabel wäre.
- **Ein Produktions-Deploy, den ein Mensch freigibt**, braucht ein GitHub-Environment mit Reviewern und eine Rolle, die nur dieses Environment annehmen kann. Das ist die Trust Policy des Prod-Kontos.
- **Ehrliche Kostenverfolgung.** „Was kostet Produktion?“ ist ein Filter auf die Konto-ID, kein archäologisches Projekt durch Tags.
- **Explosionsradius für Zugangsdaten.** Ein geleakter Dev-Schlüssel kann Prod-Daten nicht anfassen, weil er nicht in diesem Konto ist. Wir haben [unsere langlebigen Schlüssel ohnehin gelöscht](/de/blog/github-oidc-deploy-roles-per-aws-account), aber die Grenze ist die Schicht darunter.
- **Härtung, die sich pro Umgebung unterscheidet, ohne Verzweigung im Code.** DESTROY in Dev, RETAIN in Prod, Point-in-Time-Recovery in Staging und Prod an, aus einer Tabelle in einer Datei.

Nichts davon ist in einem einzelnen Konto möglich, ohne die Isolation darin von Hand nachzubauen, mit IAM-Policies, die schwerer richtig hinzubekommen sind als die Kontogrenze, die sie nachahmen.

## Der Ein-Konto-Fall, der tatsächlich in Ordnung ist

Wenn Sie einen Prototyp bauen, der in acht Wochen weggeworfen wird, ist ein Konto in Ordnung, und die Trennung wäre Verschwendung. Der Test ist, ob es eine Datenbank mit Daten gibt, deren Verlust Sie traurig machen würde. Der Tag, an dem die Antwort ja lautet, ist der Tag, an dem Sie über den Prototyp hinaus sind, und der kommt meist früher, als das Team denkt: das erste Mal, dass sich ein echter Nutzer registriert, das erste Mal, dass eine Rechnung erzeugt wird, das erste Mal, dass jemand sagt „lass das nicht gegen die echte laufen“.

Tun Sie es an diesem Tag, nicht am Tag des Vorfalls.

Wenn Sie ein Konto mit allem darin haben und das Tag-eins-Setup nachrüsten möchten, bevor es zum Monat-achtzehn-Projekt wird, [sprechen Sie mit uns](/contact). Wir haben beides gemacht, und das erste ist viel günstiger.
