Private Interview-Vorbereitung von Ali Chaghou — kein offizielles Nuvibit-Dokument.

Interview Coach · privat

Nuvibit Interview Coach · Ali Chaghou

Code lesen, Architektur erklären, ehrlich bleiben

Ich muss morgen nicht beweisen, dass ich eine fertige Landing Zone gebaut habe. Ich muss zeigen, dass ich Code lesen, Architekturentscheidungen erklären und ehrlich zwischen Implementierung, Stub und nächstem Schritt unterscheiden kann.

Ich zeige nicht: „Hier ist viel Terraform." Ich zeige:

  1. Hier ist die Ressource.
  2. Das würde in AWS entstehen.
  3. Das ist die Architekturentscheidung.
  4. Das ist die Grenze.
  5. Das wäre der nächste Schritt.

Meine Gesprächshaltung

  • Ruhig bleiben — Tempo rausnehmen, lieber einen Satz weniger.
  • Nicht größer sprechen als das Repo. Ein Modul tief, der Rest ehrlich umrissen.
  • Scope zuerst setzen, bevor ich Code öffne.
  • Code nicht nur zeigen, sondern erklären — Ressource, AWS-Wirkung, Entscheidung, Grenze.
  • Bei fehlenden Dingen ehrlich: „Das ist bewusst nicht implementiert und wäre mein nächster Schritt."

Opening für das Gespräch

Ich habe dieses Showcase nicht gebaut, um eine vollständige Landing Zone vorzutäuschen. Mir ging es darum, einen Kernbereich wirklich zu verstehen: das core-network. Ich möchte zeigen, wie ich eine Architekturidee in Terraform übersetze, welche Entscheidungen ich bewusst getroffen habe und wo ich die Grenzen offen benenne.

Code-Demo in 10 Minuten

  1. README.md
    Zeige: Status-Tabelle (implementiert vs. Stub).
    Sage: „Ich setze zuerst den Scope: Das ist ein Showcase, kein produktives Deployment."
    Nachfrage: „Warum nur ein Modul tief?" → ADR-001 in DECISIONS.md.
  2. docs/DECISIONS.md
    Zeige: ADR-001.
    Sage: „Hier sieht man, dass ich bewusst ein Modul tief gebaut habe, statt viele oberflächlich vorzutäuschen."
    Nachfrage: „Was hätte Breite gebracht?" → „Weniger Verteidigbarkeit. Tiefe zeigt Verständnis."
  3. modules/core-network/main.tf
    Zeige: Datei von oben.
    Sage: „Das ist der technische Kern. Ich gehe von oben nach unten durch die Ressourcen."
  4. aws_ec2_transit_gateway · Z. 48–78
    Sage: „Hier entsteht der zentrale Transit Gateway als Netzwerk-Hub."
    Nachfrage: „Warum TGW statt Peering?" → „Peering ist nicht transitiv und wird zum n²-Mesh; TGW ist ein transitiver Hub mit Segmentierung über Route Tables."
  5. default_route_table_association/propagation = "disable" · Z. 60/61
    Sage: „Die zentrale Entscheidung: Default-Association und -Propagation deaktiviert, damit jedes Attachment bewusst zugeordnet werden muss."
    Nachfrage: „Was passiert sonst?" → „Flaches Netz, jeder sieht jeden."
  6. aws_ec2_transit_gateway_route_table · Z. 85–93
    Sage: „Getrennte Route Tables für Hub, Prod, Dev und On-Prem — Segmentierung über Routing, nicht über Security Groups."
  7. aws_ec2_transit_gateway_vpc_attachment · Z. 101–121
    Sage: „Hier würden Spoke-VPCs an den TGW gehängt — parametrisiert, nicht auf eine Umgebung verdrahtet."
    Nachfrage: „Was ist appliance_mode_support (Z. 111)?" → „Stateful Inspection braucht Hin-/Rückweg über dieselbe AZ — deshalb der Schalter."
  8. association · Z. 128–133  |  propagation · Z. 143–148
    Sage: „Die wichtigste Stelle. Association = welche Route Table ein Attachment nutzt. Propagation = wo die Route dieses Attachments sichtbar wird."
    Nachfrage: „Unterschied in einem Satz?" → „Association = wohin ich route; Propagation = wer mich sieht."
  9. RAM · Z. 182–212
    Sage: „Der TGW wird per RAM geteilt: externe Principals ausgeschlossen (Z. 189), Share an die Workloads-OU (Z. 207–212)."
    Nachfrage: „Warum OU statt Account-IDs?" → „Neue Accounts in der OU erben den Share automatisch — kein Re-Sharing."
  10. modules/core-network/variables.tf
    Sage: „Hier das Modul-Interface: was ich steuern kann, was parametrisiert ist, was nur vorbereitet ist."
  11. network_firewall_enabled · variables.tf Z. 28
    Sage: „Das ist bewusst nur vorbereitet und nicht implementiert. Ich würde nicht behaupten, dass Network Firewall gebaut ist."

Code-Reading-Runbook

Jede Karte: Was entsteht in AWS · Warum wichtig · Was ich sage · Nachfrage · Gute Antwort. Zeilennummern gegen den aktuellen Repo-Stand geprüft.

A · modules/core-network/main.tf

locals / attachment_propagationsZ. 21–43
AWSNichts direkt — Datenaufbereitung.
WarumPropagation ist n:m; Terraform braucht flache for_each-Keys.
Ich sage„Hier flatte ich die n:m-Beziehung Attachment→Route-Table auf flache Keys, weil Terraform flache Schlüssel braucht."
Nachfrage„Warum nicht count?"
Antwort„for_each mit sprechenden Keys ist stabil gegen Reihenfolge-Änderungen; count würde beim Einfügen neu indexieren."
aws_ec2_transit_gatewayZ. 48–78
AWSEin zentraler Transit Gateway (Netzwerk-Hub).
WarumDer Hub der ganzen LZ; count (Z. 49) = Master-Schalter.
Ich sage„Hier entsteht der zentrale Transit Gateway. Über transit_gateway_enabled lässt sich das ganze Modul abschalten."
Nachfrage„Warum TGW statt Peering?"
Antwort„Peering ist nicht transitiv und wird zum n²-Mesh; der TGW ist ein transitiver Hub mit Routing-Segmentierung."
default_route_table_association = "disable"Z. 60
AWSTGW ohne automatische Default-Association.
WarumSonst landet jedes Attachment in einer Default-RT → flaches Netz.
Ich sage„Die zentrale Entscheidung: jedes Attachment muss bewusst einer Route Table zugeordnet werden."
Nachfrage„Was passiert, wenn man das nicht tut?"
Antwort„Jedes Attachment sieht jedes andere — keine Segmentierung."
default_route_table_propagation = "disable"Z. 61
AWSTGW ohne automatische Default-Propagation.
WarumCIDRs sollen nur dort erscheinen, wo ich es will.
Ich sage„Gleiche Logik für Propagation — Routen erscheinen nur in den RTs, die ich explizit angebe."
Nachfrage„Fehleranfällig?"
Antwort„Eher sicherer: vergessene Propagation = stiller Connectivity-Verlust statt versehentlicher Vollvermaschung."
auto_accept_shared_attachments = "enable"Z. 66
AWSTGW akzeptiert geteilte Attachments automatisch.
WarumIn einer Account-Factory wäre manuelles Accept Toil.
Ich sage„Geteilte Attachments werden automatisch akzeptiert — sonst müsste ich jedes Spoke-Attachment manuell freigeben."
Nachfrage„Sicherheitsrisiko?"
Antwort„Begrenzt, weil der Share org-intern bleibt (allow_external_principals = false)."
aws_ec2_transit_gateway_route_tableZ. 85–93
AWSMehrere TGW Route Tables: hub, spoke-prod, spoke-dev, onprem.
WarumSegmentierung über Routing statt Security Groups.
Ich sage„Getrennte Route Tables pro Segment — Hub, Prod, Dev, On-Prem."
Nachfrage„Warum mehrere statt einer?"
Antwort„Jede RT ist eine eigene Routing-Sicht; getrennte Sichten = Segmentierung."
aws_ec2_transit_gateway_vpc_attachmentZ. 101–121
AWSVPC-Attachments zwischen Spoke-VPCs und TGW.
WarumParametrisiert (for_each über vpc_attachments) → wiederverwendbar.
Ich sage„Hier würden Spoke-VPCs an den TGW gehängt — parametrisiert, nicht auf eine Umgebung verdrahtet."
Nachfrage„Was ist appliance_mode_support (Z. 111)?"
Antwort„Stateful Inspection braucht Hin-/Rückweg über dieselbe AZ — sonst bricht die Prüfung. Pro Attachment schaltbar."
aws_ec2_transit_gateway_route_table_associationZ. 128–133
AWSVerknüpft je Attachment genau eine RT.
Warum„Wohin darf dieses Attachment routen?"
Ich sage„Association bestimmt, welche Route Table ein Attachment nutzt — genau eine."
Nachfrage„Warum nur eine?"
Antwort„Ein Attachment hat genau eine Routing-Sicht — mehr wäre mehrdeutig."
aws_ec2_transit_gateway_route_table_propagationZ. 143–148
AWSTrägt die CIDRs eines Attachments in n RTs ein.
Warum„Wer darf dieses Attachment erreichen?"
Ich sage„Propagation bestimmt, in welche RTs die CIDRs eingetragen werden — also wer es erreichen darf."
Nachfrage„Unterschied zu Association in einem Satz?"
Antwort„Association = wohin ich route; Propagation = wer mich sieht. Die Trennung ist das Segmentierungswerkzeug."
aws_ec2_transit_gateway_routeZ. 155–169
AWSStatische TGW-Routen inkl. Blackhole.
WarumFür alles, was Propagation nicht abdeckt (0.0.0.0/0 → Hub) oder gezieltes Blocken.
Ich sage„Statische Routen — etwa Default-Route der Spokes Richtung Hub, oder Blackhole zum Verwerfen."
Nachfrage„Wann Blackhole?"
Antwort„Wenn ich einen CIDR hart blocken will — die Route hat dann kein Ziel-Attachment."
aws_ram_sharing_with_organizationZ. 177–179
AWSAktiviert org-weites RAM-Sharing.
WarumVoraussetzung, um an eine OU statt an Account-IDs zu teilen.
Ich sage„Dieser org-weite Schalter ist nötig, um an eine OU teilen zu können — default aus, weil er ins Org-Baseline gehört."
Nachfrage„Warum default false?"
Antwort„Einmaliger Org-Schalter; doppeltes Management vermeide ich."
aws_ram_resource_share · allow_external_principals=falseZ. 182–194
AWSEin RAM Resource Share; externe Accounts ausgeschlossen (Z. 189).
WarumDie Hülle für Ressource + Principals; org-intern begrenzt.
Ich sage„Der Resource Share. allow_external_principals = false schließt alles außerhalb der Organisation aus."
Nachfrage„Warum nicht extern?"
Antwort„Der TGW soll nur org-intern teilbar sein — der Kreis möglicher Attacher ist begrenzt."
aws_ram_resource_associationZ. 197–202
AWSHängt den TGW an den Share.
WarumVerbindet die zu teilende Ressource mit der Share-Hülle.
Ich sage„Hier wird der TGW als zu teilende Ressource an den Share gehängt."
Nachfrage„Was teilt man genau?"
Antwort„Den TGW selbst — nicht die Route Tables; die bleiben im Network-Account."
aws_ram_principal_association · Workloads-OUZ. 207–212
AWSTeilt den Share an die Workloads-OU (principal Z. 210).
WarumNeue Accounts in der OU erben den TGW automatisch.
Ich sage„Der Principal ist die Workloads-OU, nicht eine Account-Liste — jeder neue Account erbt den Share automatisch."
Nachfrage„Warum OU statt Account-IDs?"
Antwort„Account-Factory-freundlich: kein Re-Sharing pro neuem Account."

B · modules/core-network/variables.tf

transit_gateway_enabledZ. 22
WirkungAn/aus für TGW + alles im Modul.
Ich sage„Master-Schalter, damit z. B. eine Sandbox-Stage ganz ohne TGW auskommt."
network_firewall_enabled · vorbereitet, nicht gebautZ. 28
WirkungNichts — wird akzeptiert, aber ignoriert.
Ich sage„Bewusst nur vorbereitet und nicht implementiert. Ich behaupte nicht, dass Network Firewall gebaut ist."
Nachfrage„Warum drinlassen?"
Antwort„Damit eine spätere Erweiterung das Modul-Interface nicht bricht."
transit_gateway_route_tablesZ. 90
WirkungListe der Segmente → die RTs.
Ich sage„Hier definiere ich die Segmente: hub, spoke-prod, spoke-dev, onprem — erweiterbar über die Liste."
vpc_attachments · associated_route_table vs. propagate_toZ. 104
WirkungPro Attachment: eine Assoc-RT + Liste Propagation-RTs.
Ich sage„Das Herz des Interface: pro Attachment genau eine assoziierte RT und eine Liste, wohin propagiert wird."
Nachfrage„Validierst du die RT-Namen?"
Antwort„Aktuell nicht — Referenzfehler fielen beim Plan auf; eine validation wäre ein sinnvoller nächster Schritt."
transit_gateway_static_routesZ. 124
WirkungStatische/Blackhole-Routen.
Ich sage„Ergänzt Propagation für Default- und Block-Fälle."
enable_ram_share · workloads_ou_arn · enable_ram_organization_sharingZ. 143 · 149 · 160
WirkungRAM-Share an/aus · OU-Principal · org-weiter Schalter.
Ich sage„Sharing ist separat schaltbar; Principal ist die OU; der org-weite Schalter ist default aus, weil er ins Org-Baseline gehört."

C · modules/core-network/outputs.tf

transit_gateway_id / _arn · one(...)-LogikZ. 5–13
InhaltTGW-ID/ARN, sonst null.
Warum sauberone() liefert sauber null bei count=0 statt Index-Fehler bei [0].
Ich sage„Ich nutze one() statt [0], damit die Outputs auch bei deaktiviertem TGW sauber null liefern."
Nachfrage„Was macht one() genau?"
Antwort„Gibt das einzige Element einer Liste zurück, bei leerer Liste null — passt zum count-Muster."
transit_gateway_route_table_ids · vpc_attachment_ids · ram_resource_share_arnZ. 24 · 29 · 34
InhaltMaps Name→ID; Share-ARN oder null.
WarumStabile, sprechende Referenzen für nachgelagerte Module.
Ich sage„Maps von Segment-/Attachment-Name auf ID — saubere Referenzen nach außen."

D · modules/organizations/main.tf

aws_organizations_organization · Trusted ServicesZ. 36–48
AWSDie Organization + Trusted-Service-Access (CloudTrail, Config, GuardDuty, SecurityHub, Access Analyzer, RAM, EC2, RDS).
Ich sage„Die Organization mit aktivierten Trusted Services."
Nachfrage„Hast du GuardDuty etc. konfiguriert?"
Antwort„Nein — nur als Trusted Service freigegeben; die Konfiguration ist Stub (security-tooling)."
OUs · root_ous + workload_envsZ. 51–68
AWSTop-OUs (security, workloads, sandbox) + verschachtelte prod/staging/dev/sandbox.
Ich sage„Drei Top-OUs plus vier Umgebungs-OUs unter workloads."
Basis-SCPs · DenyRootUserAccess + RequireMFAForConsoleZ. 71 · 92 · 119
AWSZwei SCPs, am Root angehängt.
Ich sage„Zwei Basis-SCPs: Root-User sperren und MFA erzwingen."
Nachfrage„Ist das euer Guardrail-Set?"
Antwort (nicht zu groß)„Das sind Basis-SCPs. Ein vollständiges, OU-differenziertes Set ist als guardrails-Stub umrissen, nicht gebaut."

E · modules/account-factory/main.tf

aws_organizations_account · Audit / Log-Archive / WorkloadZ. 54 · 62 · 70
AWSMember-Accounts über die Organizations-API.
Ich sage„Hier werden Core- und Workload-Accounts erstellt."
Nachfrage„Läuft das?"
Antwort„Die Logik ist da, aber nicht standalone validierbar und nicht angewendet."
aws_iam_role.account_baseline · root-Kopplung + bekannte GrenzeZ. 90–110
AWSIAM-Rolle OrganizationAccountAccessRole mit ExternalId-Condition.
Grenze 1Referenziert data.aws_partition / aws_caller_identity aus dem Root (Z. 99) → validiert nicht standalone.
Grenze 2for_each legt sie mehrfach mit demselben Namen im selben Account an → Namenskonflikt beim apply. Korrekt wäre Erstellung per Provider-Alias im jeweiligen Member-Account.
Grenze 3time_sleep.wait_for_accounts (Z. 80) ist nicht per depends_on an die Rolle verdrahtet → der Wait greift derzeit nicht. Nur bei apply relevant.
Ich sage„Hier eine Cross-Account-Baseline-Rolle. Die bekannten Grenzen benenne ich offen: Root-Kopplung, Rollen-Namenskonflikt und der nicht verdrahtete time_sleep — alle nur bei apply relevant, mein nächster Fix."

Harte Fragen, ruhige Antworten

Hast du das wirklich deployed?
Gut „Nein — bewusst nicht. Kein State-Backend, alle Checks laufen offline."
Vermeiden „Ja, in meinem Account."
Zeigen main.tf (backend-Block), DECISIONS ADR-007.
Ruhig Das ist meine Linie, kein Makel.
Warum ist es nicht production-ready?
Gut „Kein apply, account-factory ist root-gekoppelt, kein CI — bewusster Scope."
Vermeiden „Es ist im Grunde fertig."
Zeigen ARCHITECTURE.md Status-Tabelle.
Ruhig Scope ehrlich = Stärke, nicht Schwäche.
Wie würdest du es production-ready machen?
Gut „Sandbox-apply, account-factory-Rollen per Provider-Alias im Member-Account, Inspection-Layer, OIDC-CI, echtes State-Backend."
Vermeiden Vage bleiben.
Zeigen DECISIONS ADR-007, account-factory.
Ruhig Ich kenne den Weg, auch wenn ich ihn nicht gegangen bin.
Warum Transit Gateway? Warum nicht VPC Peering?
Gut „Peering ist nicht transitiv und wird zum n²-Mesh; TGW ist ein zentraler, transitiver Hub mit Segmentierung über Route Tables."
Vermeiden „TGW ist halt neuer/besser."
Zeigen core-network/main.tf.
Ruhig Konkret am Mesh-Problem festmachen.
Was ist Association vs. Propagation?
Gut „Association = wohin ein Attachment routet (genau eine RT). Propagation = in welche RTs seine CIDRs eingetragen werden, also wer es erreicht (n RTs)."
Vermeiden „Beides verbindet halt VPCs."
Zeigen main.tf Z. 128–148, README-Tabelle.
Ruhig Diese Antwort sitzt auswendig.
Wie verhinderst du, dass Dev Prod erreicht?
Gut „Getrennte RTs; spoke-prod hat keine Route aufs Dev-Attachment — keine Route, keine Verbindung."
Vermeiden „Security Groups."
Zeigen DECISIONS ADR-003.
Ruhig Isolation durch Abwesenheit einer Route.
Wo ist Network Firewall?
Gut „Nicht implementiert — Interface vorbereitet (network_firewall_enabled akzeptiert, ignoriert; appliance_mode pro Attachment). Nächster Layer."
Vermeiden So tun, als sei sie da.
Zeigen variables.tf Z. 28, ADR-007.
Ruhig Offen benennen wirkt souverän.
Wo wird Security erzwungen?
Gut „Auf Netzwerkebene durch Segmentierung, allow_external_principals=false, Basis-SCPs. Stateful Inspection fehlt bewusst."
Vermeiden „Überall, security-by-design."
Zeigen core-network + organizations.
Ruhig Konkret statt Schlagwort.
Was hast du persönlich gebaut?
Gut „Das core-network-Modul Zeile für Zeile, die ADRs, die Org-Struktur — inspiriert von den Nuvibit-Docs, aber selbst geschrieben und entschieden."
Vermeiden Vage bleiben.
Zeigen core-network/main.tf, DECISIONS.md.
Ruhig Ich kenne jede Entscheidung.
Was ist nur Stub?
Gut „Acht Module: vpc, ipam, route53, identity-center, log-archive, security-tooling, guardrails, parameters — als README-Schnittstelle, nicht als Fassade."
Vermeiden Stubs als Code verkaufen.
Zeigen README Status-Tabelle, modules/<name>/README.md.
Ruhig Stub heißt: ehrlich umrissen.
Was würdest du als nächsten Schritt bauen?
Gut „Eine Inspection-VPC am Hub (aws_networkfirewall_firewall), ein Inspection-Attachment im hub-Segment, 0.0.0.0/0-Default der Spokes dorthin."
Vermeiden „Eigentlich nichts mehr."
Zeigen DECISIONS ADR-007.
Ruhig Ich habe ein klares nächstes Ziel.
Wie würdest du CI/CD dafür bauen?
Gut „PR-Pipeline: fmt/validate/plan über eine OIDC-Rolle, kein langlebiger Key; apply nur auf main mit Approval."
Vermeiden „Hab ich schon." (.github ist leer)
Zeigen — (ehrlich: noch nicht vorhanden).
Ruhig Konzept ist klar, Umsetzung offen.
Wie würdest du das testen?
Gut „Heute fmt/validate. Echt: terraform plan gegen Sandbox, dann Connectivity-Test (Reachability Analyzer) prod↔dev."
Vermeiden „Terraform testet sich selbst."
Zeigen README Schnellstart (offline-Checks).
Ruhig Zwischen statisch und echt unterscheiden.
Wo könnte dein Code aktuell noch verbessert werden?
Gut „account-factory-Rolle per Provider-Alias im Member-Account; parent_id-Vergleich gegen null statt ''; das ganze Repo einmal fmt-clean; eine validation für RT-Namen."
Vermeiden „Ist eigentlich alles gut."
Zeigen account-factory, organizations.
Ruhig Selbstkritik zeigt Seniorität.

Drei Zeitvarianten

5 Minuten

  1. README — Scope/Status
  2. DECISIONS — ein Modul tief
  3. core-network/main.tf — disable + Association/Propagation
  4. eine Grenze nennen

Kernbotschaft„Ein Modul tief — ich verstehe TGW-Segmentierung."

10 Minuten

  1. README + DECISIONS
  2. TGW + disable
  3. Association / Propagation
  4. RAM an OU
  5. Scope-Grenze Network Firewall

Kernbotschaft„Ich treffe bewusste, dokumentierte Entscheidungen."

20 Minuten

  1. 10-Minuten-Plan
  2. + variables.tf (Interface)
  3. + outputs.tf (one-Logik)
  4. + organizations (OUs/SCPs)
  5. + account-factory (ehrlich)
  6. + Stubs + nächste Schritte

Kernbotschaft„Ich weiß, was ich gebaut habe, was nicht — und warum."

Wenn ich unsicher werde, sage ich:

  • „Das ist in diesem Showcase bewusst nicht implementiert. Ich habe es als nächsten Schritt dokumentiert."
  • „Ich möchte hier nicht größer sprechen als das Repo ist."
  • „Ich kann erklären, was gebaut ist, was Stub ist und was ich als nächstes sauber ergänzen würde."
  • „Der Fokus liegt auf core-network, nicht auf einer vollständigen Landing Zone."
  • „Ich habe das nicht deployed, weil ich kein produktives Setup vortäuschen wollte."

Drei Sätze, die ich fast auswendig kann

  • „Ich habe bewusst keinen fertigen Landing-Zone-Anspruch formuliert, sondern ein Terraform-Showcase gebaut, das einen Kernbereich sauber erklärt: das core-network."
  • „Die wichtigste Designentscheidung ist, Default Association und Default Propagation am Transit Gateway zu deaktivieren, damit Segmentierung nicht zufällig, sondern bewusst entsteht."
  • „Was nicht implementiert ist, benenne ich offen — zum Beispiel Network Firewall, echtes Deployment, CI/CD und produktive Betriebsfähigkeit."
← zurück zur Übersichtsseite