Interview Prep
A worked example: assessing your own readiness gap before a Senior Platform Engineer interview, section by section, weighted the way one real interview syllabus actually was.
Built from a real candidate’s résumé, a real job description, and a real interviewer-shared syllabus. The candidate’s name, employer, and every other identifying detail have been removed — the fit/gap analysis, model answers, and study priorities below are otherwise unchanged. Companion to Interview Q&A Reference, which has the flat, by-topic Q&A for every item covered here.
Before a big test, a good student doesn’t just study everything equally — they look at which topics the teacher said count for the most points, and start there. This page is one real student doing exactly that, out loud, so you can copy the method with your own test.
🟢 warm-up — definitional fluency. 🟡 medium — a structured answer plus a concrete example. 🔴 hard — scenario or trade-off depth.
IDP Reference Architecture — how the tools fit together
This is the whole guide on one page: an Internal Developer Platform built from the JD’s own toolchain. Follow the numbered badges ①–⑨ — they trace one feature from a developer’s pull request all the way to a provisioned, tagged, cost-tracked cloud resource.
Diagram scales to fit this column. Use “Enlarge diagram” above for a full-size, scrollable/zoomable view.
The flow, step by step
- A developer opens a PR. Branch protection, required reviews, and CODEOWNERS make the pull request the only path to production — nobody pushes to
mainor runskubectl applyby hand. - GitHub Actions builds and hardens the artifact. Build → test → Trivy/Mend scan (fail on critical CVEs) → cosign signature → SBOM, pushed to GHCR. The runner authenticates to the cloud with a per-run OIDC token — no long-lived cloud keys exist anywhere in CI.
- CI never touches the cluster. Its last act is opening a PR that bumps the image tag in the config repo. Deployment authority stays inside the cluster — that separation is the core GitOps security win.
- Flux pulls, renders, applies. source-controller fetches Git and OCI artifacts; kustomize-controller and helm-controller render the Helm values and Kustomize overlays in-cluster and apply them. Pull-based means cluster credentials never leave the cluster, and drift is auto-corrected on every reconcile.
- Everything passes the Kyverno gate. Admission webhooks verify the cosign signature, enforce an allowlisted registry, require resource requests/limits, block privileged pods, and mutate incoming objects to inject team and cost-center labels. RBAC is allow-only; what the gate rejects never reaches etcd.
- Workloads land in tenant namespaces. Each team gets a namespace with ResourceQuota + LimitRange (noisy-neighbor protection), default-deny NetworkPolicy (explicit allows only, including the DNS egress rule), RBAC bound to the team’s IdP group, and Pod Security “restricted”. This is deliberate soft multi-tenancy — for hostile or regulated tenants you escalate to dedicated node pools, vcluster, or separate clusters.
- Infrastructure is self-service via Crossplane. The team commits a namespaced Claim (
PostgresClaim) to the same config repo; Flux applies it; Crossplane’s Composition renders the Managed Resources and provisions through a per-team ProviderConfig federated to that team’s own cloud account — so Team A’s credentials can never create resources in Team B’s account, and the account boundary caps the blast radius. - Secrets never live in Git. External Secrets Operator pulls from Secrets Manager / Key Vault through workload identity (IRSA / Azure Workload Identity — an OIDC trust, no stored key) and materializes native Kubernetes Secrets per namespace, on a refresh interval, from a per-team SecretStore.
- FinOps closes the loop. Tags are enforced twice — force-patched by the Composition and backstopped by Kyverno — so every resource lands pre-tagged. Kubecost / Cost Explorer roll spend up per team and namespace for showback, with budgets and anomaly alerts; chargeback becomes a reporting decision, not an engineering project.
Where security lives (defense in depth)
- Supply chain: scan + sign + SBOM in CI → signature verified again at admission. A tampered or unscanned image is rejected before it runs.
- No standing credentials: CI uses per-run OIDC; pods use IRSA / Workload Identity; Crossplane providers federate per team. There is no static cloud key to leak anywhere in the picture.
- Pull-based GitOps: the CI system — the most commonly compromised link — holds zero cluster access.
- Admission as the choke point: Kyverno policies apply to every object regardless of who applies it — Flux, a human, or a controller. Policy can’t be bypassed by going around the pipeline.
- Runtime floor: RBAC allow-only, Pod Security “restricted”, default-deny NetworkPolicy, non-root pods, audit logs on.
- Secrets externalized: Git holds only
ExternalSecretreferences; actual values stay in the cloud secret store with its own audit trail.
Where multi-tenancy lives (layered boundaries)
- Namespace layer (soft): quota, limits, RBAC per team group, default-deny networking — stops accidents and API-level snooping, but tenants share a kernel and control plane.
- GitOps layer: per-tenant Flux reconcilers run under per-team ServiceAccounts — team-a’s Kustomization physically cannot write into team-b’s namespace.
- Control-plane layer: per-team ProviderConfig in Crossplane, each federated to a least-privilege role in that team’s own account — the credential-isolation gotcha from Section 3.5, solved structurally.
- Cloud layer (hard): account/subscription per team is the real blast-radius boundary — billing, IAM, and quota isolation the cluster can’t provide.
- Cost layer: enforced tags + namespace labels give per-tenant showback, so shared-platform economics stay visible and fair.
- Escalation path: namespace → dedicated node pool (taints) → vcluster → separate cluster, chosen by how hostile or regulated the tenant is.