Security Overview¶
Security on MDAPI is organised as independent layers, each of which is expected to hold on its own when another one fails. This page is the map: what each layer is, where it is documented in depth, and — for the controls that have no page of their own — how they work.
One principle runs through all of it: a control that is not measured is a control that is assumed. Every layer below is either tested on a schedule or watched by a probe that would notice if it stopped working. A green deployment proves only that something was deployed.
The layers¶
| Layer | Control | Detail |
|---|---|---|
| Edge | Per-service DNAT, protocol demultiplexing, ModSecurity WAF in blocking mode on every ingress | ModSecurity WAF, External Traffic Flow |
| Identity | Keycloak OIDC federated with OpenLDAP; authorisation lives in the directory, the IdP only publishes it | Authentication & Identity |
| Admission | Pod Security Standards at the baseline level, native ValidatingAdmissionPolicy in CEL |
below |
| Access | Continuous RBAC hygiene measurement | below |
| Runtime | Falco syscall detection on every node, modern eBPF, no kernel module | Runtime Detection |
| Supply chain | Secret scanning before commit, SBOM + CVE scanning at build time and against every running image | Supply Chain Security |
| Configuration | CIS Kubernetes Benchmark, weekly, alert on regression | CIS Kubernetes Benchmark |
| Secrets | Split-knowledge store with an on-premise customer fragment, and a rehearsed failover plane | Secret Management |
| Certificates | Automated issuance and delivery, internal PKI, Certificate Transparency monitoring | Certificates & PKI |
| Data | Two independent off-site copies, and a restore proven daily | Backups & Disaster Recovery |
Admission control¶
Two native mechanisms, and no third-party admission webhook.
Pod Security Standards are applied per namespace at the baseline level, in warn and audit mode first — every violation is measured before anything is refused. Namespaces whose workloads legitimately need more (storage drivers, the hypervisor stack, the node tuners) are exempted by name, each with the reason it cannot conform, rather than left unlabelled and forgotten.
ValidatingAdmissionPolicy rules are written in CEL and evaluated by the API server itself. There is no webhook to keep alive, so no additional point of failure in the admission path. A third-party policy engine earns its place when resources must be mutated or generated; refusing what breaks a rule needs neither.
Coverage is not assumed from configuration — an hourly probe derives it from live state on both sides. Three things learned the hard way shaped it:
- Conformity is judged on workload templates, not only on running pods. A namespace whose only workload is a CronJob, or whose pods exist only while a CI pipeline runs, looks perfectly conforming while idle. Label it on that basis and the policy breaks the job on its next run.
- Measuring live state is not enough; it has to be reconciled with the written intent. A drift of one namespace between the rollout plan and the cluster stayed invisible for a day, because the probe measured the cluster faithfully and nothing compared the two.
- A label declared in GitOps is not guaranteed to reach an existing namespace. Fleet stamps namespace labels at creation; on a namespace that already exists the declaration can silently do nothing while the bundle reports healthy. The probe exists partly to catch exactly that.
Access hygiene¶
A binding whose subject no longer exists is inert — until something recreates that namespace and account name, at which point the grant is live again and nobody decided it. A daily probe measures this across every ClusterRoleBinding and RoleBinding.
- Kubernetes' own RBAC is excluded by its label, not by its name. The platform ships bindings (labelled
kubernetes.io/bootstrapping=rbac-defaults) whose service accounts are created lazily or never. Without that filter the large majority of findings are noise, and the ones that matter are lost in it. Asystem:name prefix would be a guess; the label is what Kubernetes itself stamps. - Two classes are counted apart. A subject whose whole namespace is gone is strong evidence of a leftover. A namespace that exists but lacks the service account is weak — upstream charts routinely reference accounts they never create.
- Owner references that can never fire are counted too. A cluster-scoped object cannot be owned by a namespaced one: Kubernetes refuses the link, so garbage collection never removes the object, and the cascade only looks wired. An invalid owner reference is indistinguishable from a valid one on inspection — which is why it needs a number rather than a reader.
The probe reports; it never deletes. Removing a grant has a blast radius and stays a human decision.
Rehearsed, not assumed¶
Two recovery paths are exercised on a schedule, because a recovery path that has never run is a hypothesis:
- An off-site restore runs every day and proves the backups actually decrypt and read back — see Backups & Disaster Recovery.
- The secrets failover plane is drilled every quarter, including a parity check that the automation reads identical values through it. A store that answers with different content is worse than one that is down, because nothing fails loudly — see Secret Management.
Posture, on one screen per control¶
Each control above has a dashboard in a dedicated Security folder in Grafana — one screen per concern, each showing a number that could be bad, next to the reasoning that says what to do about it. A dashboard that can only show green proves nothing.
Posture alerts carry an internal component. A benchmark regression or a leftover grant is a finding, not an outage, and routing it to the public status page would degrade it in front of strangers for something no user can observe.
What this site deliberately does not publish
This site explains how each control is organised and what it taught. It does not list findings: which checks fail, how much of the estate a control covers, or which work is still open. Those live in an internal risk register, with an owner and a date each. A page that says where a platform is soft is a document for the wrong reader.