This is an automated email from the ASF dual-hosted git repository. junkaixue pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/helix.git
commit 0d22039fec86982ef7110466dba81c12e3b56257 Author: Jarek Potiuk <[email protected]> AuthorDate: Thu Jun 4 04:41:26 2026 +0200 Revise threat model per PMC review (junkaixue) Generated-by: Claude Code --- THREAT_MODEL.md | 196 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 113 insertions(+), 83 deletions(-) diff --git a/THREAT_MODEL.md b/THREAT_MODEL.md index 12ed826c3..0188d8514 100644 --- a/THREAT_MODEL.md +++ b/THREAT_MODEL.md @@ -1,16 +1,17 @@ -# Apache Helix — Threat Model (v1 draft) +# Apache Helix — Threat Model (v1) -**Status:** v1 draft, authored by the ASF Security Team for the Helix PMC to -review. Drafted against `apache/helix` (default branch `master`), 2026-06-02. +**Status:** v1, authored by the ASF Security Team and ratified by the Helix PMC. +Drafted against `apache/helix` (default branch `master`), 2026-06-02; PMC review +folded 2026-06-04 (Junkai Xue). **Provenance legend:** *(documented)* — from the project's README / repo structure / docs; *(maintainer)* — ratified by a Helix PMC member; *(inferred)* — reasoned from architecture / domain norms, **not yet confirmed** (each has a matching §14 item). -**Draft confidence:** documented ~10 · maintainer 0 · inferred ~22. A -react-to-me draft — the Helix PMC (Junkai Xue, Jiajun Wang) confirms/corrects, -especially the §14 items. +**Draft confidence:** documented ~10 · maintainer ~24 · inferred ~3. The Helix +PMC (Junkai Xue) confirmed the §14 items; the few remaining *(inferred)* tags +mark genuinely-open details (see §14). **Revision triggers:** a change to the helix-rest auth model; a change to how Helix authenticates/authorizes against the metadata store (ZooKeeper); a new @@ -31,7 +32,8 @@ trusted. is the control-plane source of truth; Helix components read/write it to coordinate. Helix is embedded by an operator's application (the participant hosts the operator's resources). It is not a standalone secure-by-default - service. *(inferred — Q1)* + service. The control components run independent of user data. *(maintainer — + Q1)* ## §2 Scope and intended use @@ -45,160 +47,188 @@ dirs)* | Family | Path | Role / trust notes | |---|---|---| -| Cluster-management core | `helix-core` | Controller / Participant / Spectator roles; computes + applies state transitions via the metadata store. *(documented)* | -| **Admin REST service** | `helix-rest` | Network-facing HTTP API to create/modify clusters, resources, instances, configs. The **primary network trust boundary** — who may call it, with what auth. *(inferred — Q5)* | +| Cluster-management core | `helix-core` | Controller / Participant / Spectator roles; computes + applies state transitions via the metadata store. They run independent of user data. *(maintainer — Q1,Q2)* | +| **Admin REST service** | `helix-rest` | Network-facing HTTP API to create/modify clusters, resources, instances, configs. Shipped as a **skeleton**: the operator implements the authentication mechanism, and the **default is no auth**. The primary network trust boundary. *(maintainer — Q5)* | | Metadata-store access | `zookeeper-api`, `meta-client`, `metadata-store-directory-common` | The ZooKeeper-backed control plane Helix reads/writes. Whoever can write these znodes controls the cluster. *(documented — dirs)* | -| Gateway / Agent | `helix-gateway`, `helix-agent` | Additional participant-integration surfaces (e.g. gRPC gateway, external-process agent). Network/IPC profile pending confirmation. *(inferred — Q8)* | +| Gateway / Agent | `helix-gateway`, `helix-agent` | Additional participant-integration surfaces. A **pluggable framework** — the user supplies the implementation. *(maintainer — Q8)* | | Distributed lock | `helix-lock` | ZK-backed locks; correctness/liveness, not a direct attack surface. *(inferred)* | -| Recipes / website / tests | `recipes`, `website`, `*/test` | Examples + docs, not the shipped runtime. *(inferred — Q3)* | +| Recipes / website / tests | `recipes`, `website`, `*/test` | Examples + docs, not the shipped runtime. *(maintainer — Q3)* | **In scope:** the core + helix-rest + metadata-store access + gateway/agent. **Intended caller trust:** the operator and the application embedding the Participant/Spectator are **trusted**; the **helix-rest caller** and **anyone who can reach the ZooKeeper ensemble** are where untrusted actors appear. -*(inferred — Q2)* +*(maintainer — Q2)* ## §3 Out of scope (explicit non-goals) - `recipes/`, `website/`, `*/test`, build files — not the shipped runtime. - *(inferred — Q3)* + *(maintainer — Q3)* - **ZooKeeper's own security** (its authN/authZ, ACL enforcement, transport) — - Helix relies on a correctly-secured ensemble; hardening ZK is the operator's. - *(inferred — Q6)* + ZooKeeper runs as a **separate service**; maintaining/securing it is **not + Helix's responsibility**, and Helix sets **no ACLs** on the znodes it creates. + *(maintainer — Q6)* - **The security of the resources Helix manages** — the databases/services/ partitions hosted by Participants are the operator's applications, not Helix. - *(inferred — Q1)* + *(maintainer — Q1)* - Build / release / supply-chain hygiene. Per rubric §1. *(documented — rubric)* ## §4 Trust boundaries and data flow 1. **Client → helix-rest.** A network client issues cluster-admin operations (create cluster, add/drop resource, change config, enable/disable instance). - The high-value boundary: auth/authz on management actions + transport - security. *(inferred — Q5,Q7)* + helix-rest ships as a skeleton with **no default auth**; the operator + implements authentication. This is the high-value boundary. *(maintainer — + Q5)* 2. **Any actor → ZooKeeper metadata store.** The real control plane. An actor who can write the cluster's znodes can redirect partitions, disable nodes, - or rewrite the state model — bypassing helix-rest entirely. Helix relies on - ZK ACLs / network isolation here. *(inferred — Q6)* + or rewrite the state model — bypassing helix-rest entirely. ZooKeeper access + goes through the **ZooKeeper client's own authz** mechanism; Helix does not + set ACLs on the znodes it creates. *(maintainer — Q6,Q7)* 3. **Controller ↔ Participant ↔ Spectator (via the store).** Components coordinate by reading/writing znodes; they trust the store's contents. - Malformed/forged znode data is a conditional surface (Q9). *(inferred — Q9)* + They run independent of user data. Malformed/forged znode data is a + conditional surface (§7, Q9). *(maintainer — Q2,Q9)* 4. **Operator/application → embedded Participant/Spectator.** In-process, - trusted — the app already controls what it hosts. *(inferred — Q2)* + trusted — the app already controls what it hosts. *(maintainer — Q2)* ## §5 Assumptions about the environment JVM; a reachable ZooKeeper ensemble (the control plane); the helix-rest listen interface; network reachability between Controller, Participants, and the -ensemble; system trust store if TLS is used. *(inferred — Q11)* +ensemble; system trust store if TLS is used. *(maintainer — Q11)* ## §6 Assumptions about inputs — per-parameter trust | Input | Source | Trusted? | Notes | |---|---|---|---| -| helix-rest requests (cluster/resource/instance/config ops) | Network client | **Untrusted-capable** | Auth/authz is the boundary — can an unauthenticated client administer a cluster? (Q5) | -| ZooKeeper znode data (ideal state, external view, configs, messages) | The ensemble | Trusted-by-reliance | Forged/corrupt znodes if an attacker can write ZK (Q6,Q9). | -| Cluster / resource / instance configuration | Operator (via REST or API) | Trusted | Operator-supplied control input. *(inferred)* | -| State-model definitions | Operator/app | Trusted | Defines legal transitions; operator's. *(inferred)* | -| The managed resources' own data/traffic | Operator's app | Pass-through | Helix coordinates placement; it doesn't handle the resource payloads. *(inferred)* | +| helix-rest requests (cluster/resource/instance/config ops) | Network client | **Untrusted-capable** | helix-rest is a skeleton; operator implements auth; **default is no auth** (Q5). | +| ZooKeeper znode data (ideal state, external view, configs, messages) | The ensemble | Trusted-by-reliance | ZK access is gated by the ZK client's own authz; forged/corrupt znodes if an attacker can write ZK (Q6,Q9). *(maintainer — Q6,Q7)* | +| Cluster / resource / instance configuration | Operator (via REST or API) | Trusted | Operator-supplied control input. *(maintainer — Q2)* | +| State-model definitions | Operator/app | Trusted | Defines legal transitions; operator's. *(maintainer — Q2)* | +| The managed resources' own data/traffic | Operator's app | Pass-through | Helix coordinates placement; it doesn't handle the resource payloads. *(maintainer — Q1)* | ## §7 Adversary model - **Out of scope:** the operator and the application embedding Helix — they - already control the cluster and what it hosts. *(inferred — Q2)* -- **In scope:** a **remote actor against helix-rest** (administering a cluster - they shouldn't), an actor who can **reach/write the ZooKeeper ensemble** + already control the cluster and what it hosts. In-domain components + (Controller/Participant/Spectator) run independent of user data and are + trusted. *(maintainer — Q2)* +- **In scope:** a **remote actor against helix-rest** (the API ships with no + default auth, so on an unprotected deployment an unauthenticated caller can + administer a cluster), an actor who can **reach/write the ZooKeeper ensemble** (full control-plane compromise), and a **network MITM** between components / - on the REST channel. *(inferred — Q5,Q6,Q7)* + on the REST channel. *(maintainer — Q5,Q6)* - **Conditional:** an actor who can inject **malformed znode data** that a - Controller/Participant/Spectator parses. *(inferred — Q9)* + Controller/Participant/Spectator parses. *(maintainer — Q9)* -## §8 Security properties the project provides *(all pending PMC confirmation)* +## §8 Security properties the project provides -- **helix-rest access control:** the admin API is expected to enforce - authentication/authorization on cluster-mutating operations (default posture - is the key question). *(inferred — Q5)* — violation symptom: an - unauthenticated client mutates cluster state on a default deployment; - severity: critical. +- **helix-rest access control:** helix-rest is a **skeleton** — it does **not** + provide authentication by default; the operator implements the auth mechanism. + A default deployment will accept unauthenticated cluster-mutating requests. + *(maintainer — Q5)* — violation symptom for a deployment that *has* + implemented auth: an unauthenticated client mutates cluster state despite the + operator's auth layer; severity: critical. (An out-of-the-box unauthenticated + deployment is the documented default, not a defect — see §9, §11.) - **Metadata-store integrity reliance:** Helix behaves correctly given a - trustworthy ZK ensemble; it relies on ZK ACLs for control-plane integrity. - *(inferred — Q6)* -- **Transport security:** TLS available for helix-rest and for the ZK - connection where supported. *(inferred — Q7)* + trustworthy ZK ensemble; ZooKeeper is a separate service and access is gated + by the ZK client's own authz. Helix sets no ACLs on the znodes it creates. + *(maintainer — Q6,Q7)* - **Robustness to malformed znode data:** parsing store contents should fail - safe rather than crash/corrupt. *(inferred — Q9)* + safe rather than crash/corrupt. *(maintainer — Q9)* ## §9 Security properties the project does *not* provide +- **helix-rest provides no built-in authentication.** It is a skeleton; auth is + the operator's to implement, and the default is no auth. *(maintainer — Q5)* - **Not a sandbox / not an isolation boundary** for the resources it manages — Helix places and transitions them; their security is the operator's app. - *(inferred — Q1)* -- **No defense if ZooKeeper is open/unauthenticated.** If an attacker can write - the ensemble, Helix's coordination is fully subvertible — that is a ZK - hardening responsibility, not a Helix defect. *(inferred — Q6)* -- **No first-party authorization model beyond what helix-rest / ZK ACLs - enforce** — Helix does not add per-tenant RBAC on top. *(inferred — Q5,Q10)* + *(maintainer — Q1)* +- **No defense if ZooKeeper is open/unauthenticated.** ZooKeeper is a separate + service that is not Helix's responsibility to secure; Helix sets no ACLs on + the znodes it creates. If an attacker can write the ensemble, Helix's + coordination is fully subvertible. *(maintainer — Q6)* +- **No first-party authorization model** — Helix does not add per-tenant RBAC. + Authorization is **helix-rest-auth (operator-implemented) + ZK ACLs**. + *(maintainer — Q5,Q10)* - **No guarantee against a hostile Controller/Participant** already inside the - trust domain (they hold ZK write access by design). *(inferred — Q2)* + trust domain (they hold ZK write access by design). *(maintainer — Q2)* ## §10 Downstream (operator) responsibilities -- **Secure ZooKeeper** — ACLs, authentication, and network isolation of the - ensemble; it is the control plane. *(inferred — Q6)* -- **Lock down helix-rest** — authenticate it, don't expose the admin API to an - untrusted network, restrict who can mutate clusters. *(inferred — Q5)* +- **Secure ZooKeeper** — it runs as a separate service that Helix does not + manage; the operator handles its authz (via the ZK client), authentication, + and network isolation. Helix sets no ACLs on the znodes it creates, so any + ZNode-level access control is the operator's. *(maintainer — Q6,Q7)* +- **Implement helix-rest auth** — helix-rest ships as a skeleton with no default + auth; the operator implements the authentication mechanism, must not expose + the admin API to an untrusted network, and restricts who can mutate clusters. + *(maintainer — Q5)* +- **Supply gateway/agent implementations** — these are a pluggable framework; + the operator provides the implementation and its trust/network controls. + *(maintainer — Q8)* - Network-isolate Controller / Participants / ensemble; use TLS on sensitive - channels. *(inferred — Q7)* -- Secure the resources Helix manages (their own auth/encryption). *(inferred — Q1)* + channels. *(inferred — Q7a)* +- Secure the resources Helix manages (their own auth/encryption). *(maintainer + — Q1)* ## §11 Known misuse patterns - An **open / unauthenticated ZooKeeper ensemble** reachable from an untrusted - network → full control-plane takeover. *(inferred — Q6)* -- **helix-rest exposed with weak/no auth** to an untrusted network → anyone can - administer clusters. *(inferred — Q5)* -- Treating Helix as a security boundary for the hosted resources. *(inferred — Q1)* + network → full control-plane takeover. ZK is a separate service the operator + secures. *(maintainer — Q6)* +- **helix-rest exposed without an operator-supplied auth layer** to an untrusted + network → anyone can administer clusters (no auth is the default). *(maintainer + — Q5)* +- Treating Helix as a security boundary for the hosted resources. *(maintainer + — Q1)* -### §11a Known non-findings (recurring false positives) *(seed — PMC to expand, Q18a)* +### §11a Known non-findings (recurring false positives) - "Helix reads and writes ZooKeeper znodes / a Participant takes itself offline / the Controller drives state transitions" — **by design**; that is - the coordination function, not a vuln. *(inferred — Q1)* -- "Helix trusts the data in ZooKeeper" — relies on a secured ensemble (§10); - ZK hardening is downstream, not a Helix code defect. *(inferred — Q6)* -- "Code in `recipes/` does X" — examples, not the shipped runtime. *(inferred — Q3)* + the coordination function, not a vuln. *(maintainer — Q1)* +- "Helix trusts the data in ZooKeeper" — relies on a secured, separate ZK + service (§10); ZK hardening is downstream, not a Helix code defect. + *(maintainer — Q6)* +- "helix-rest has no authentication" — by design; it is a skeleton and auth is + operator-implemented, default none. *(maintainer — Q5)* +- "Code in `recipes/` does X" — examples, not the shipped runtime. *(maintainer + — Q3)* +- **Findings reported from the Helix UI** — the Helix UI is **already + deprecated**; reports against it are not actionable. *(maintainer — Q18a)* ## §12 Conditions that would change this model A change to the helix-rest auth/authz model; a change to how Helix authenticates against the metadata store; a new network-facing component (gateway/agent); a change to what znode data is trusted or how it's parsed. -*(inferred)* +*(maintainer)* ## §13 Triage dispositions | Disposition | When | Section | |---|---|---| -| **VALID** | Violates a §8 property under the §7 adversary (esp. unauth helix-rest admin, crash on malformed znode data) in in-scope code | §7, §8 | -| **OUT-OF-MODEL** | Adversary is the trusted operator/app or an in-domain component; or code in `recipes`/`website`/tests | §3, §7 | -| **DOWNSTREAM-RESPONSIBILITY** | ZK hardening, helix-rest exposure, network isolation, the managed resources' own security | §10 | -| **DISCLAIMED** | A §9 non-guarantee (not a sandbox; no defense if ZK is open; no first-party RBAC) | §9 | +| **VALID** | Violates a §8 property under the §7 adversary (e.g. auth bypass against an operator's helix-rest auth layer, crash on malformed znode data) in in-scope code | §7, §8 | +| **OUT-OF-MODEL** | Adversary is the trusted operator/app or an in-domain component; helix-rest's no-default-auth posture itself; reports from the deprecated Helix UI; or code in `recipes`/`website`/tests | §3, §7, §11a | +| **DOWNSTREAM-RESPONSIBILITY** | ZK hardening, helix-rest auth implementation/exposure, gateway/agent implementation, network isolation, the managed resources' own security | §10 | +| **DISCLAIMED** | A §9 non-guarantee (no built-in helix-rest auth; not a sandbox; no defense if ZK is open; no first-party RBAC) | §9 | | **MODEL-GAP** | Plausible, not covered → escalate to PMC | §12 | ## §14 Open questions for the maintainers -1. **(Q1)** Confirm framing: Helix coordinates placement/state of operator-owned resources; it is not a security/isolation boundary for them. -2. **(Q2)** Confirm the operator + embedding application + in-domain components (Controller/Participant/Spectator) are trusted (out of the adversary model). -3. **(Q3)** Confirm out-of-scope: `recipes/`, `website/`, tests, build. -4. **(Q5)** **helix-rest is the crux:** what is its *default* auth posture? Can a default deployment accept unauthenticated cluster-mutating requests, or is auth required / is it bound to an internal interface? Any built-in authz on who can administer which clusters? -5. **(Q6)** ZooKeeper trust: is "secure the ensemble (ACLs/auth/isolation)" an operator responsibility, and does Helix rely on ZK ACLs for control-plane integrity? Does Helix set ACLs on the znodes it creates? -6. **(Q7)** TLS: available/default for helix-rest and for the ZK client connection? -7. **(Q9)** Robustness: should a Controller/Participant/Spectator tolerate malformed/forged znode data without crashing, or is store integrity fully assumed? -8. **(Q8)** What are the trust/network profiles of `helix-gateway` and `helix-agent` (new-ish surfaces)? Are they network-facing, and authenticated? -9. **(Q10)** Is any first-party authorization (per-tenant/per-cluster RBAC) provided, or is that entirely helix-rest-auth + ZK ACLs? -10. **(Q11)** Confirm the environment assumptions (JVM, ZK ensemble, REST interface) worth stating. -11. **(Q18a)** What do scanners most often report against Helix that you consider non-findings? (Expand §11a.) -12. **(meta)** OK to land this as `THREAT_MODEL.md` with the `AGENTS.md → SECURITY.md → THREAT_MODEL.md` chain (this PR creates all three)? +Q1, Q2, Q3, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q18a, and the meta question were +confirmed by the Helix PMC (Junkai Xue, 2026-06-04) and folded above as +*(maintainer)*. The remaining open items are narrower: + +1. **(Q7a)** TLS posture: is TLS available/default for the helix-rest listen + interface, and for the ZooKeeper client connection? (The PMC confirmed ZK + access goes through the ZK client's own authz, but the transport-encryption + default for each channel is not yet stated.) *(inferred)* +2. **(Q-lock)** Confirm `helix-lock` (ZK-backed distributed locks) carries no + direct external attack surface beyond the ZK-control-plane exposure already + captured in §4.2 — i.e. correctness/liveness only. *(inferred)* ## §15 Machine-readable companion
