You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@kvrocks.apache.org by "potiuk (via GitHub)" <gi...@apache.org> on 2026/05/31 01:21:07 UTC
[PR] Add draft threat model + SECURITY.md + AGENTS.md for security-model discoverability [kvrocks-controller]
potiuk opened a new pull request, #397:
URL: https://github.com/apache/kvrocks-controller/pull/397
**This is a draft proposal for the Kvrocks PMC to review — please correct, reject, or discuss as needed.** Nothing here is a requirement; the maintainers are the decision-makers.
This is the companion to the `apache/kvrocks` threat-model PR, covering the **control plane** (its trust surface differs from the data node). It adds `THREAT_MODEL.md` + `SECURITY.md` + `AGENTS.md` so a scan agent can follow `AGENTS.md → SECURITY.md → THREAT_MODEL.md`.
Draft-first, mostly inferred (~12 documented / 0 maintainer / ~40 inferred); every `*(inferred)*` claim routes to a numbered **§14** question.
The **wave-1** question is the whole ballgame for a control plane:
- Does the controller API/UI have **any built-in authentication/authorization**, or is it **network-trust only** (the `config.yaml` shows no API-auth knob and default `addr` is `127.0.0.1:9379`)? If network-trust-only, is fronting it with an operator auth proxy the *supported* posture — so an "unauthenticated admin API" report is `BY-DESIGN` rather than `VALID`?
Also flagged: TLS posture, SSRF via node registration, and how managed-node admin credentials are stored.
Context: the ASF Security team is preparing the project for an automated agentic security scan we're piloting; a discoverable threat model keeps that scan's output signal-rich. Drafted via the [threat-model-producer](https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573) rubric. If you'd rather author it yourselves, close this PR and we'll regroup.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@kvrocks.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Add draft threat model + SECURITY.md + AGENTS.md for security-model discoverability [kvrocks-controller]
Posted by "potiuk (via GitHub)" <gi...@apache.org>.
potiuk commented on PR #397:
URL: https://github.com/apache/kvrocks-controller/pull/397#issuecomment-4618469969
Thanks @git-hulk — pushed a revision folding your answers in: no built-in authn/authz today, so the unauthenticated API is expected behavior (with auth tracked in #390); TLS via a fronting proxy (Nginx) rather than built-in; credentials stored in the backing store; node addresses validated as real Kvrocks nodes; the metadata store + peer nodes trusted as honest (trusted-environment requirement); and split-brain handling deferred to the store engine (majority-win with Raft/ETCD/ZK). Residual items kept as §14 questions for the PMC. Ready when you are.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@kvrocks.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Add draft threat model + SECURITY.md + AGENTS.md for security-model discoverability [kvrocks-controller]
Posted by "codecov-commenter (via GitHub)" <gi...@apache.org>.
codecov-commenter commented on PR #397:
URL: https://github.com/apache/kvrocks-controller/pull/397#issuecomment-4585372245
## [Codecov](https://app.codecov.io/gh/apache/kvrocks-controller/pull/397?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) Report
:white_check_mark: All modified and coverable lines are covered by tests.
:white_check_mark: Project coverage is 49.69%. Comparing base ([`6c56470`](https://app.codecov.io/gh/apache/kvrocks-controller/commit/6c564700d621ef30a182bad1bfeff0aa13db6ea7?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)) to head ([`d37cce6`](https://app.codecov.io/gh/apache/kvrocks-controller/commit/d37cce6d153d02b1ca700b199d618d11afc3f952?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)).
:warning: Report is 107 commits behind head on unstable.
<details><summary>Additional details and impacted files</summary>
```diff
@@ Coverage Diff @@
## unstable #397 +/- ##
============================================
+ Coverage 43.38% 49.69% +6.30%
============================================
Files 37 45 +8
Lines 2971 4103 +1132
============================================
+ Hits 1289 2039 +750
- Misses 1544 1838 +294
- Partials 138 226 +88
```
| [Flag](https://app.codecov.io/gh/apache/kvrocks-controller/pull/397/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | Coverage Δ | |
|---|---|---|
| [unittests](https://app.codecov.io/gh/apache/kvrocks-controller/pull/397/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `49.69% <ø> (+6.30%)` | :arrow_up: |
Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#carryforward-flags-in-the-pull-request-comment) to find out more.
</details>
[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/apache/kvrocks-controller/pull/397?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).
<details><summary> :rocket: New features to boost your workflow: </summary>
- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@kvrocks.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Add draft threat model + SECURITY.md + AGENTS.md for security-model discoverability [kvrocks-controller]
Posted by "git-hulk (via GitHub)" <gi...@apache.org>.
git-hulk commented on code in PR #397:
URL: https://github.com/apache/kvrocks-controller/pull/397#discussion_r3334415951
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,273 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, not yet reviewed by the Kvrocks PMC.** Produced by the ASF Security team via
+ the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / 0 maintainer / ~40 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **The config exposes no built-in
+ authentication knob**, so by default this role is *unauthenticated* and gated only by `addr` /
+ network reachability *(inferred — `config/config.yaml` has no API-auth section; default `addr` is
+ localhost; `server/middleware` present but role unconfirmed)*. This is the load-bearing §14 wave-1 item.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** beyond the TLS the controller supports.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With no built-in auth (pending §14), the boundary is effectively the
+network ACL around `:9379` *(inferred)*.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership. An actor who can write the store can redirect the controller *(inferred)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured *(inferred)*. Node addresses supplied via the API are an **SSRF / connect-to-arbitrary-host**
+ vector if the caller is untrusted (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model if reachable by a client the deployment treats as untrusted
+ (which, absent built-in auth, is "anyone who can reach the port" — see §14 wave-1).
+- A finding in **store handling** is in-model if reachable from API input or from store contents an
+ attacker could influence.
+- A finding in the **node client** (e.g. SSRF, credential mishandling) is in-model if a node address or
+ connection parameter is attacker-influenceable via the API.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them *(inferred)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes *(inferred)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it without a fronting auth proxy is the risk |
+| API authentication | **none present in config** | Control plane appears unauthenticated | **Open (wave-1):** is there *any* API/UI auth, and is "network-trust only" the supported posture? |
+| API/UI TLS | *(unconfirmed)* | Plaintext control-plane traffic | **Open (wave-1)** |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | **yes** (absent auth, any API client) | front with authn/authz; network ACL |
+| API: add node | **node address/host:port** | **yes** | restrict who may register nodes (SSRF surface) |
+| Web UI | form/query fields | **yes** | output encoding; CSRF protection; auth |
+| metadata store reads | topology/leadership records | from a **trusted** store *(inferred)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(inferred)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** an actor who can reach the controller API or web UI but is not the operator —
+ realistically present whenever the API is exposed beyond a trusted network without a fronting auth layer.
+ Capabilities: call any API endpoint (create/delete clusters, add/remove nodes, **force failover**,
+ migrate slots), register node addresses (SSRF), drive the UI.
+- **Goals:** seize administrative control of managed Kvrocks clusters; cause data movement/loss via slot
+ migration or failover; make the controller connect to attacker-chosen hosts; read/modify topology.
+- **Out of model:** the operator, anyone with `config.yaml` / store / managed-node credentials, and
+ (pending §14) a malicious peer controller or a compromised metadata store.
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane assumed to run on a trusted network; all *(inferred)* pending §14.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election safety (single active controller).** HA controllers coordinate via the store so that
+ conflicting administrative actions are serialized *(inferred)*. *Symptom:* two controllers issuing
+ conflicting cluster ops. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — UNRESOLVED.** Whether the API/UI authenticate callers at all is the
+ central open question (§14 wave-1); absent that, the controller claims **no** access-control property and
+ relies entirely on §10 network controls.
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication by default** *(inferred)* — exposing `:9379` (or the UI) to an
+ untrusted network without a fronting auth proxy yields an **unauthenticated administrative control plane**
+ over every managed cluster.
+- **No transport encryption guarantee by default** for the API/UI; store TLS is off unless configured.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store and its peers** — it is not a defence against a tampered store
+ or a Byzantine peer controller (pending §14).
+- **No SSRF protection on registered node addresses** *(inferred)* — the controller connects to host:port
+ values it is given; an untrusted caller who can add nodes can aim those connections.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but (pending §14) may have no authentication at
+ all* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator:** unauthenticated admin-API exposure; CSRF/XSS on the web
+UI; SSRF via node registration; plaintext control traffic; an unsecured ETCD that anyone can rewrite.
+
+## §10 Downstream (operator) responsibilities
+
+- **Do not expose the API/UI to an untrusted network without an authenticating reverse proxy / network ACL**
+ (until/unless built-in auth is confirmed).
+- Enable TLS for the API/UI, for the store connection (`etcd.tls`), and for managed-node connections on
+ untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes.
+- Restrict who may register node addresses (SSRF surface).
+
+## §11 Known misuse patterns
+
+- Binding the controller API to `0.0.0.0` on a shared network without fronting authentication.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it is not.
+
+## §11a Known non-findings (recurring false positives)
+
+*(v0 seed — PMC's real list is the key §14 input.)*
+
+- **"Unauthenticated admin API / no login on the UI"** against the default config — by design *if* the PMC
+ rules network-trust the supported posture (else it is `VALID`); resolved in §14 wave-1.
+- **"ETCD has no auth/TLS"** — operator-configured store, defaults documented (§3/§10).
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Introduction (or confirmation) of built-in API/UI authentication/authorization — would add §8 properties
+ and shrink §9/§10.
+- A change to the default `addr` / TLS posture.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening (e.g. add CSRF tokens, SSRF allow-list). | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability. | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS default, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+**Wave 1 — the central auth question (§2/§5a/§8/§9):**
+1. Does the controller API have **any built-in authentication/authorization** (token, mTLS, basic-auth), or
+ is it **network-trust only**? If the latter, is exposing it behind an operator's own auth proxy the
+ *supported* posture, so an "unauthenticated API" report is `BY-DESIGN`? *Proposed:* network-trust only
+ today; operator fronts it; unauth-on-trusted-network is by design, unauth-on-untrusted-network is misuse.
Review Comment:
No, we don't support the built-in authentication and authorization for now. So, it's expected behavior to expose an "unauthenticated API". But the community is planning to do this in #390.
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,273 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, not yet reviewed by the Kvrocks PMC.** Produced by the ASF Security team via
+ the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / 0 maintainer / ~40 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **The config exposes no built-in
+ authentication knob**, so by default this role is *unauthenticated* and gated only by `addr` /
+ network reachability *(inferred — `config/config.yaml` has no API-auth section; default `addr` is
+ localhost; `server/middleware` present but role unconfirmed)*. This is the load-bearing §14 wave-1 item.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** beyond the TLS the controller supports.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With no built-in auth (pending §14), the boundary is effectively the
+network ACL around `:9379` *(inferred)*.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership. An actor who can write the store can redirect the controller *(inferred)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured *(inferred)*. Node addresses supplied via the API are an **SSRF / connect-to-arbitrary-host**
+ vector if the caller is untrusted (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model if reachable by a client the deployment treats as untrusted
+ (which, absent built-in auth, is "anyone who can reach the port" — see §14 wave-1).
+- A finding in **store handling** is in-model if reachable from API input or from store contents an
+ attacker could influence.
+- A finding in the **node client** (e.g. SSRF, credential mishandling) is in-model if a node address or
+ connection parameter is attacker-influenceable via the API.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them *(inferred)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes *(inferred)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it without a fronting auth proxy is the risk |
+| API authentication | **none present in config** | Control plane appears unauthenticated | **Open (wave-1):** is there *any* API/UI auth, and is "network-trust only" the supported posture? |
+| API/UI TLS | *(unconfirmed)* | Plaintext control-plane traffic | **Open (wave-1)** |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | **yes** (absent auth, any API client) | front with authn/authz; network ACL |
+| API: add node | **node address/host:port** | **yes** | restrict who may register nodes (SSRF surface) |
+| Web UI | form/query fields | **yes** | output encoding; CSRF protection; auth |
+| metadata store reads | topology/leadership records | from a **trusted** store *(inferred)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(inferred)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** an actor who can reach the controller API or web UI but is not the operator —
+ realistically present whenever the API is exposed beyond a trusted network without a fronting auth layer.
+ Capabilities: call any API endpoint (create/delete clusters, add/remove nodes, **force failover**,
+ migrate slots), register node addresses (SSRF), drive the UI.
+- **Goals:** seize administrative control of managed Kvrocks clusters; cause data movement/loss via slot
+ migration or failover; make the controller connect to attacker-chosen hosts; read/modify topology.
+- **Out of model:** the operator, anyone with `config.yaml` / store / managed-node credentials, and
+ (pending §14) a malicious peer controller or a compromised metadata store.
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane assumed to run on a trusted network; all *(inferred)* pending §14.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election safety (single active controller).** HA controllers coordinate via the store so that
+ conflicting administrative actions are serialized *(inferred)*. *Symptom:* two controllers issuing
+ conflicting cluster ops. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — UNRESOLVED.** Whether the API/UI authenticate callers at all is the
+ central open question (§14 wave-1); absent that, the controller claims **no** access-control property and
+ relies entirely on §10 network controls.
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication by default** *(inferred)* — exposing `:9379` (or the UI) to an
+ untrusted network without a fronting auth proxy yields an **unauthenticated administrative control plane**
+ over every managed cluster.
+- **No transport encryption guarantee by default** for the API/UI; store TLS is off unless configured.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store and its peers** — it is not a defence against a tampered store
+ or a Byzantine peer controller (pending §14).
+- **No SSRF protection on registered node addresses** *(inferred)* — the controller connects to host:port
+ values it is given; an untrusted caller who can add nodes can aim those connections.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but (pending §14) may have no authentication at
+ all* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator:** unauthenticated admin-API exposure; CSRF/XSS on the web
+UI; SSRF via node registration; plaintext control traffic; an unsecured ETCD that anyone can rewrite.
+
+## §10 Downstream (operator) responsibilities
+
+- **Do not expose the API/UI to an untrusted network without an authenticating reverse proxy / network ACL**
+ (until/unless built-in auth is confirmed).
+- Enable TLS for the API/UI, for the store connection (`etcd.tls`), and for managed-node connections on
+ untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes.
+- Restrict who may register node addresses (SSRF surface).
+
+## §11 Known misuse patterns
+
+- Binding the controller API to `0.0.0.0` on a shared network without fronting authentication.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it is not.
+
+## §11a Known non-findings (recurring false positives)
+
+*(v0 seed — PMC's real list is the key §14 input.)*
+
+- **"Unauthenticated admin API / no login on the UI"** against the default config — by design *if* the PMC
+ rules network-trust the supported posture (else it is `VALID`); resolved in §14 wave-1.
+- **"ETCD has no auth/TLS"** — operator-configured store, defaults documented (§3/§10).
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Introduction (or confirmation) of built-in API/UI authentication/authorization — would add §8 properties
+ and shrink §9/§10.
+- A change to the default `addr` / TLS posture.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening (e.g. add CSRF tokens, SSRF allow-list). | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability. | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS default, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+**Wave 1 — the central auth question (§2/§5a/§8/§9):**
+1. Does the controller API have **any built-in authentication/authorization** (token, mTLS, basic-auth), or
+ is it **network-trust only**? If the latter, is exposing it behind an operator's own auth proxy the
+ *supported* posture, so an "unauthenticated API" report is `BY-DESIGN`? *Proposed:* network-trust only
+ today; operator fronts it; unauth-on-trusted-network is by design, unauth-on-untrusted-network is misuse.
+2. Does the **web UI** authenticate, and does it have **CSRF** protection on state-changing calls?
Review Comment:
None of them.
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,273 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, not yet reviewed by the Kvrocks PMC.** Produced by the ASF Security team via
+ the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / 0 maintainer / ~40 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **The config exposes no built-in
+ authentication knob**, so by default this role is *unauthenticated* and gated only by `addr` /
+ network reachability *(inferred — `config/config.yaml` has no API-auth section; default `addr` is
+ localhost; `server/middleware` present but role unconfirmed)*. This is the load-bearing §14 wave-1 item.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** beyond the TLS the controller supports.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With no built-in auth (pending §14), the boundary is effectively the
+network ACL around `:9379` *(inferred)*.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership. An actor who can write the store can redirect the controller *(inferred)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured *(inferred)*. Node addresses supplied via the API are an **SSRF / connect-to-arbitrary-host**
+ vector if the caller is untrusted (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model if reachable by a client the deployment treats as untrusted
+ (which, absent built-in auth, is "anyone who can reach the port" — see §14 wave-1).
+- A finding in **store handling** is in-model if reachable from API input or from store contents an
+ attacker could influence.
+- A finding in the **node client** (e.g. SSRF, credential mishandling) is in-model if a node address or
+ connection parameter is attacker-influenceable via the API.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them *(inferred)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes *(inferred)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it without a fronting auth proxy is the risk |
+| API authentication | **none present in config** | Control plane appears unauthenticated | **Open (wave-1):** is there *any* API/UI auth, and is "network-trust only" the supported posture? |
+| API/UI TLS | *(unconfirmed)* | Plaintext control-plane traffic | **Open (wave-1)** |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | **yes** (absent auth, any API client) | front with authn/authz; network ACL |
+| API: add node | **node address/host:port** | **yes** | restrict who may register nodes (SSRF surface) |
+| Web UI | form/query fields | **yes** | output encoding; CSRF protection; auth |
+| metadata store reads | topology/leadership records | from a **trusted** store *(inferred)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(inferred)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** an actor who can reach the controller API or web UI but is not the operator —
+ realistically present whenever the API is exposed beyond a trusted network without a fronting auth layer.
+ Capabilities: call any API endpoint (create/delete clusters, add/remove nodes, **force failover**,
+ migrate slots), register node addresses (SSRF), drive the UI.
+- **Goals:** seize administrative control of managed Kvrocks clusters; cause data movement/loss via slot
+ migration or failover; make the controller connect to attacker-chosen hosts; read/modify topology.
+- **Out of model:** the operator, anyone with `config.yaml` / store / managed-node credentials, and
+ (pending §14) a malicious peer controller or a compromised metadata store.
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane assumed to run on a trusted network; all *(inferred)* pending §14.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election safety (single active controller).** HA controllers coordinate via the store so that
+ conflicting administrative actions are serialized *(inferred)*. *Symptom:* two controllers issuing
+ conflicting cluster ops. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — UNRESOLVED.** Whether the API/UI authenticate callers at all is the
+ central open question (§14 wave-1); absent that, the controller claims **no** access-control property and
+ relies entirely on §10 network controls.
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication by default** *(inferred)* — exposing `:9379` (or the UI) to an
+ untrusted network without a fronting auth proxy yields an **unauthenticated administrative control plane**
+ over every managed cluster.
+- **No transport encryption guarantee by default** for the API/UI; store TLS is off unless configured.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store and its peers** — it is not a defence against a tampered store
+ or a Byzantine peer controller (pending §14).
+- **No SSRF protection on registered node addresses** *(inferred)* — the controller connects to host:port
+ values it is given; an untrusted caller who can add nodes can aim those connections.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but (pending §14) may have no authentication at
+ all* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator:** unauthenticated admin-API exposure; CSRF/XSS on the web
+UI; SSRF via node registration; plaintext control traffic; an unsecured ETCD that anyone can rewrite.
+
+## §10 Downstream (operator) responsibilities
+
+- **Do not expose the API/UI to an untrusted network without an authenticating reverse proxy / network ACL**
+ (until/unless built-in auth is confirmed).
+- Enable TLS for the API/UI, for the store connection (`etcd.tls`), and for managed-node connections on
+ untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes.
+- Restrict who may register node addresses (SSRF surface).
+
+## §11 Known misuse patterns
+
+- Binding the controller API to `0.0.0.0` on a shared network without fronting authentication.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it is not.
+
+## §11a Known non-findings (recurring false positives)
+
+*(v0 seed — PMC's real list is the key §14 input.)*
+
+- **"Unauthenticated admin API / no login on the UI"** against the default config — by design *if* the PMC
+ rules network-trust the supported posture (else it is `VALID`); resolved in §14 wave-1.
+- **"ETCD has no auth/TLS"** — operator-configured store, defaults documented (§3/§10).
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Introduction (or confirmation) of built-in API/UI authentication/authorization — would add §8 properties
+ and shrink §9/§10.
+- A change to the default `addr` / TLS posture.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening (e.g. add CSRF tokens, SSRF allow-list). | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability. | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS default, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+**Wave 1 — the central auth question (§2/§5a/§8/§9):**
+1. Does the controller API have **any built-in authentication/authorization** (token, mTLS, basic-auth), or
+ is it **network-trust only**? If the latter, is exposing it behind an operator's own auth proxy the
+ *supported* posture, so an "unauthenticated API" report is `BY-DESIGN`? *Proposed:* network-trust only
+ today; operator fronts it; unauth-on-trusted-network is by design, unauth-on-untrusted-network is misuse.
+2. Does the **web UI** authenticate, and does it have **CSRF** protection on state-changing calls?
+ *Proposed:* same as the API; CSRF is a hardening item.
+3. Is **TLS** supported/expected for the API and managed-node connections? *Proposed:* operator-configurable;
Review Comment:
No, users can us TLS proxy like Nginx or something else to do that.
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,273 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, not yet reviewed by the Kvrocks PMC.** Produced by the ASF Security team via
+ the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / 0 maintainer / ~40 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **The config exposes no built-in
+ authentication knob**, so by default this role is *unauthenticated* and gated only by `addr` /
+ network reachability *(inferred — `config/config.yaml` has no API-auth section; default `addr` is
+ localhost; `server/middleware` present but role unconfirmed)*. This is the load-bearing §14 wave-1 item.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** beyond the TLS the controller supports.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With no built-in auth (pending §14), the boundary is effectively the
+network ACL around `:9379` *(inferred)*.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership. An actor who can write the store can redirect the controller *(inferred)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured *(inferred)*. Node addresses supplied via the API are an **SSRF / connect-to-arbitrary-host**
+ vector if the caller is untrusted (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model if reachable by a client the deployment treats as untrusted
+ (which, absent built-in auth, is "anyone who can reach the port" — see §14 wave-1).
+- A finding in **store handling** is in-model if reachable from API input or from store contents an
+ attacker could influence.
+- A finding in the **node client** (e.g. SSRF, credential mishandling) is in-model if a node address or
+ connection parameter is attacker-influenceable via the API.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them *(inferred)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes *(inferred)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it without a fronting auth proxy is the risk |
+| API authentication | **none present in config** | Control plane appears unauthenticated | **Open (wave-1):** is there *any* API/UI auth, and is "network-trust only" the supported posture? |
+| API/UI TLS | *(unconfirmed)* | Plaintext control-plane traffic | **Open (wave-1)** |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | **yes** (absent auth, any API client) | front with authn/authz; network ACL |
+| API: add node | **node address/host:port** | **yes** | restrict who may register nodes (SSRF surface) |
+| Web UI | form/query fields | **yes** | output encoding; CSRF protection; auth |
+| metadata store reads | topology/leadership records | from a **trusted** store *(inferred)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(inferred)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** an actor who can reach the controller API or web UI but is not the operator —
+ realistically present whenever the API is exposed beyond a trusted network without a fronting auth layer.
+ Capabilities: call any API endpoint (create/delete clusters, add/remove nodes, **force failover**,
+ migrate slots), register node addresses (SSRF), drive the UI.
+- **Goals:** seize administrative control of managed Kvrocks clusters; cause data movement/loss via slot
+ migration or failover; make the controller connect to attacker-chosen hosts; read/modify topology.
+- **Out of model:** the operator, anyone with `config.yaml` / store / managed-node credentials, and
+ (pending §14) a malicious peer controller or a compromised metadata store.
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane assumed to run on a trusted network; all *(inferred)* pending §14.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election safety (single active controller).** HA controllers coordinate via the store so that
+ conflicting administrative actions are serialized *(inferred)*. *Symptom:* two controllers issuing
+ conflicting cluster ops. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — UNRESOLVED.** Whether the API/UI authenticate callers at all is the
+ central open question (§14 wave-1); absent that, the controller claims **no** access-control property and
+ relies entirely on §10 network controls.
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication by default** *(inferred)* — exposing `:9379` (or the UI) to an
+ untrusted network without a fronting auth proxy yields an **unauthenticated administrative control plane**
+ over every managed cluster.
+- **No transport encryption guarantee by default** for the API/UI; store TLS is off unless configured.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store and its peers** — it is not a defence against a tampered store
+ or a Byzantine peer controller (pending §14).
+- **No SSRF protection on registered node addresses** *(inferred)* — the controller connects to host:port
+ values it is given; an untrusted caller who can add nodes can aim those connections.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but (pending §14) may have no authentication at
+ all* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator:** unauthenticated admin-API exposure; CSRF/XSS on the web
+UI; SSRF via node registration; plaintext control traffic; an unsecured ETCD that anyone can rewrite.
+
+## §10 Downstream (operator) responsibilities
+
+- **Do not expose the API/UI to an untrusted network without an authenticating reverse proxy / network ACL**
+ (until/unless built-in auth is confirmed).
+- Enable TLS for the API/UI, for the store connection (`etcd.tls`), and for managed-node connections on
+ untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes.
+- Restrict who may register node addresses (SSRF surface).
+
+## §11 Known misuse patterns
+
+- Binding the controller API to `0.0.0.0` on a shared network without fronting authentication.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it is not.
+
+## §11a Known non-findings (recurring false positives)
+
+*(v0 seed — PMC's real list is the key §14 input.)*
+
+- **"Unauthenticated admin API / no login on the UI"** against the default config — by design *if* the PMC
+ rules network-trust the supported posture (else it is `VALID`); resolved in §14 wave-1.
+- **"ETCD has no auth/TLS"** — operator-configured store, defaults documented (§3/§10).
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Introduction (or confirmation) of built-in API/UI authentication/authorization — would add §8 properties
+ and shrink §9/§10.
+- A change to the default `addr` / TLS posture.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening (e.g. add CSRF tokens, SSRF allow-list). | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability. | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS default, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+**Wave 1 — the central auth question (§2/§5a/§8/§9):**
+1. Does the controller API have **any built-in authentication/authorization** (token, mTLS, basic-auth), or
+ is it **network-trust only**? If the latter, is exposing it behind an operator's own auth proxy the
+ *supported* posture, so an "unauthenticated API" report is `BY-DESIGN`? *Proposed:* network-trust only
+ today; operator fronts it; unauth-on-trusted-network is by design, unauth-on-untrusted-network is misuse.
+2. Does the **web UI** authenticate, and does it have **CSRF** protection on state-changing calls?
+ *Proposed:* same as the API; CSRF is a hardening item.
+3. Is **TLS** supported/expected for the API and managed-node connections? *Proposed:* operator-configurable;
+ plaintext acceptable only on trusted networks.
+
+**Wave 2 — store, nodes, SSRF (§4/§6/§9):**
+4. How are **managed-node admin credentials** stored and used (in the store? in config?), and what protects
+ them at rest? *Proposed:* operator-supplied; stored in the metadata store; protected at the store layer.
Review Comment:
We expected to store credentials inside the store.
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,273 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, not yet reviewed by the Kvrocks PMC.** Produced by the ASF Security team via
+ the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / 0 maintainer / ~40 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **The config exposes no built-in
+ authentication knob**, so by default this role is *unauthenticated* and gated only by `addr` /
+ network reachability *(inferred — `config/config.yaml` has no API-auth section; default `addr` is
+ localhost; `server/middleware` present but role unconfirmed)*. This is the load-bearing §14 wave-1 item.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** beyond the TLS the controller supports.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With no built-in auth (pending §14), the boundary is effectively the
+network ACL around `:9379` *(inferred)*.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership. An actor who can write the store can redirect the controller *(inferred)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured *(inferred)*. Node addresses supplied via the API are an **SSRF / connect-to-arbitrary-host**
+ vector if the caller is untrusted (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model if reachable by a client the deployment treats as untrusted
+ (which, absent built-in auth, is "anyone who can reach the port" — see §14 wave-1).
+- A finding in **store handling** is in-model if reachable from API input or from store contents an
+ attacker could influence.
+- A finding in the **node client** (e.g. SSRF, credential mishandling) is in-model if a node address or
+ connection parameter is attacker-influenceable via the API.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them *(inferred)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes *(inferred)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it without a fronting auth proxy is the risk |
+| API authentication | **none present in config** | Control plane appears unauthenticated | **Open (wave-1):** is there *any* API/UI auth, and is "network-trust only" the supported posture? |
+| API/UI TLS | *(unconfirmed)* | Plaintext control-plane traffic | **Open (wave-1)** |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | **yes** (absent auth, any API client) | front with authn/authz; network ACL |
+| API: add node | **node address/host:port** | **yes** | restrict who may register nodes (SSRF surface) |
+| Web UI | form/query fields | **yes** | output encoding; CSRF protection; auth |
+| metadata store reads | topology/leadership records | from a **trusted** store *(inferred)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(inferred)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** an actor who can reach the controller API or web UI but is not the operator —
+ realistically present whenever the API is exposed beyond a trusted network without a fronting auth layer.
+ Capabilities: call any API endpoint (create/delete clusters, add/remove nodes, **force failover**,
+ migrate slots), register node addresses (SSRF), drive the UI.
+- **Goals:** seize administrative control of managed Kvrocks clusters; cause data movement/loss via slot
+ migration or failover; make the controller connect to attacker-chosen hosts; read/modify topology.
+- **Out of model:** the operator, anyone with `config.yaml` / store / managed-node credentials, and
+ (pending §14) a malicious peer controller or a compromised metadata store.
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane assumed to run on a trusted network; all *(inferred)* pending §14.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election safety (single active controller).** HA controllers coordinate via the store so that
+ conflicting administrative actions are serialized *(inferred)*. *Symptom:* two controllers issuing
+ conflicting cluster ops. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — UNRESOLVED.** Whether the API/UI authenticate callers at all is the
+ central open question (§14 wave-1); absent that, the controller claims **no** access-control property and
+ relies entirely on §10 network controls.
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication by default** *(inferred)* — exposing `:9379` (or the UI) to an
+ untrusted network without a fronting auth proxy yields an **unauthenticated administrative control plane**
+ over every managed cluster.
+- **No transport encryption guarantee by default** for the API/UI; store TLS is off unless configured.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store and its peers** — it is not a defence against a tampered store
+ or a Byzantine peer controller (pending §14).
+- **No SSRF protection on registered node addresses** *(inferred)* — the controller connects to host:port
+ values it is given; an untrusted caller who can add nodes can aim those connections.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but (pending §14) may have no authentication at
+ all* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator:** unauthenticated admin-API exposure; CSRF/XSS on the web
+UI; SSRF via node registration; plaintext control traffic; an unsecured ETCD that anyone can rewrite.
+
+## §10 Downstream (operator) responsibilities
+
+- **Do not expose the API/UI to an untrusted network without an authenticating reverse proxy / network ACL**
+ (until/unless built-in auth is confirmed).
+- Enable TLS for the API/UI, for the store connection (`etcd.tls`), and for managed-node connections on
+ untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes.
+- Restrict who may register node addresses (SSRF surface).
+
+## §11 Known misuse patterns
+
+- Binding the controller API to `0.0.0.0` on a shared network without fronting authentication.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it is not.
+
+## §11a Known non-findings (recurring false positives)
+
+*(v0 seed — PMC's real list is the key §14 input.)*
+
+- **"Unauthenticated admin API / no login on the UI"** against the default config — by design *if* the PMC
+ rules network-trust the supported posture (else it is `VALID`); resolved in §14 wave-1.
+- **"ETCD has no auth/TLS"** — operator-configured store, defaults documented (§3/§10).
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Introduction (or confirmation) of built-in API/UI authentication/authorization — would add §8 properties
+ and shrink §9/§10.
+- A change to the default `addr` / TLS posture.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening (e.g. add CSRF tokens, SSRF allow-list). | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability. | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS default, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+**Wave 1 — the central auth question (§2/§5a/§8/§9):**
+1. Does the controller API have **any built-in authentication/authorization** (token, mTLS, basic-auth), or
+ is it **network-trust only**? If the latter, is exposing it behind an operator's own auth proxy the
+ *supported* posture, so an "unauthenticated API" report is `BY-DESIGN`? *Proposed:* network-trust only
+ today; operator fronts it; unauth-on-trusted-network is by design, unauth-on-untrusted-network is misuse.
+2. Does the **web UI** authenticate, and does it have **CSRF** protection on state-changing calls?
+ *Proposed:* same as the API; CSRF is a hardening item.
+3. Is **TLS** supported/expected for the API and managed-node connections? *Proposed:* operator-configurable;
+ plaintext acceptable only on trusted networks.
+
+**Wave 2 — store, nodes, SSRF (§4/§6/§9):**
+4. How are **managed-node admin credentials** stored and used (in the store? in config?), and what protects
+ them at rest? *Proposed:* operator-supplied; stored in the metadata store; protected at the store layer.
+5. Are **node addresses** registered via the API validated/allow-listed, or will the controller connect to
+ any host:port given (SSRF)? *Proposed:* currently connects as given; allow-listing is a hardening item.
Review Comment:
Yes, all node addresses are allowed, but it will validate if it's a Kvrocks node. So I think we don't need to harden.
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,273 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, not yet reviewed by the Kvrocks PMC.** Produced by the ASF Security team via
+ the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / 0 maintainer / ~40 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **The config exposes no built-in
+ authentication knob**, so by default this role is *unauthenticated* and gated only by `addr` /
+ network reachability *(inferred — `config/config.yaml` has no API-auth section; default `addr` is
+ localhost; `server/middleware` present but role unconfirmed)*. This is the load-bearing §14 wave-1 item.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** beyond the TLS the controller supports.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With no built-in auth (pending §14), the boundary is effectively the
+network ACL around `:9379` *(inferred)*.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership. An actor who can write the store can redirect the controller *(inferred)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured *(inferred)*. Node addresses supplied via the API are an **SSRF / connect-to-arbitrary-host**
+ vector if the caller is untrusted (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model if reachable by a client the deployment treats as untrusted
+ (which, absent built-in auth, is "anyone who can reach the port" — see §14 wave-1).
+- A finding in **store handling** is in-model if reachable from API input or from store contents an
+ attacker could influence.
+- A finding in the **node client** (e.g. SSRF, credential mishandling) is in-model if a node address or
+ connection parameter is attacker-influenceable via the API.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them *(inferred)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes *(inferred)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it without a fronting auth proxy is the risk |
+| API authentication | **none present in config** | Control plane appears unauthenticated | **Open (wave-1):** is there *any* API/UI auth, and is "network-trust only" the supported posture? |
+| API/UI TLS | *(unconfirmed)* | Plaintext control-plane traffic | **Open (wave-1)** |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | **yes** (absent auth, any API client) | front with authn/authz; network ACL |
+| API: add node | **node address/host:port** | **yes** | restrict who may register nodes (SSRF surface) |
+| Web UI | form/query fields | **yes** | output encoding; CSRF protection; auth |
+| metadata store reads | topology/leadership records | from a **trusted** store *(inferred)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(inferred)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** an actor who can reach the controller API or web UI but is not the operator —
+ realistically present whenever the API is exposed beyond a trusted network without a fronting auth layer.
+ Capabilities: call any API endpoint (create/delete clusters, add/remove nodes, **force failover**,
+ migrate slots), register node addresses (SSRF), drive the UI.
+- **Goals:** seize administrative control of managed Kvrocks clusters; cause data movement/loss via slot
+ migration or failover; make the controller connect to attacker-chosen hosts; read/modify topology.
+- **Out of model:** the operator, anyone with `config.yaml` / store / managed-node credentials, and
+ (pending §14) a malicious peer controller or a compromised metadata store.
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane assumed to run on a trusted network; all *(inferred)* pending §14.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election safety (single active controller).** HA controllers coordinate via the store so that
+ conflicting administrative actions are serialized *(inferred)*. *Symptom:* two controllers issuing
+ conflicting cluster ops. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — UNRESOLVED.** Whether the API/UI authenticate callers at all is the
+ central open question (§14 wave-1); absent that, the controller claims **no** access-control property and
+ relies entirely on §10 network controls.
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication by default** *(inferred)* — exposing `:9379` (or the UI) to an
+ untrusted network without a fronting auth proxy yields an **unauthenticated administrative control plane**
+ over every managed cluster.
+- **No transport encryption guarantee by default** for the API/UI; store TLS is off unless configured.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store and its peers** — it is not a defence against a tampered store
+ or a Byzantine peer controller (pending §14).
+- **No SSRF protection on registered node addresses** *(inferred)* — the controller connects to host:port
+ values it is given; an untrusted caller who can add nodes can aim those connections.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but (pending §14) may have no authentication at
+ all* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator:** unauthenticated admin-API exposure; CSRF/XSS on the web
+UI; SSRF via node registration; plaintext control traffic; an unsecured ETCD that anyone can rewrite.
+
+## §10 Downstream (operator) responsibilities
+
+- **Do not expose the API/UI to an untrusted network without an authenticating reverse proxy / network ACL**
+ (until/unless built-in auth is confirmed).
+- Enable TLS for the API/UI, for the store connection (`etcd.tls`), and for managed-node connections on
+ untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes.
+- Restrict who may register node addresses (SSRF surface).
+
+## §11 Known misuse patterns
+
+- Binding the controller API to `0.0.0.0` on a shared network without fronting authentication.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it is not.
+
+## §11a Known non-findings (recurring false positives)
+
+*(v0 seed — PMC's real list is the key §14 input.)*
+
+- **"Unauthenticated admin API / no login on the UI"** against the default config — by design *if* the PMC
+ rules network-trust the supported posture (else it is `VALID`); resolved in §14 wave-1.
+- **"ETCD has no auth/TLS"** — operator-configured store, defaults documented (§3/§10).
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Introduction (or confirmation) of built-in API/UI authentication/authorization — would add §8 properties
+ and shrink §9/§10.
+- A change to the default `addr` / TLS posture.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening (e.g. add CSRF tokens, SSRF allow-list). | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability. | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS default, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+**Wave 1 — the central auth question (§2/§5a/§8/§9):**
+1. Does the controller API have **any built-in authentication/authorization** (token, mTLS, basic-auth), or
+ is it **network-trust only**? If the latter, is exposing it behind an operator's own auth proxy the
+ *supported* posture, so an "unauthenticated API" report is `BY-DESIGN`? *Proposed:* network-trust only
+ today; operator fronts it; unauth-on-trusted-network is by design, unauth-on-untrusted-network is misuse.
+2. Does the **web UI** authenticate, and does it have **CSRF** protection on state-changing calls?
+ *Proposed:* same as the API; CSRF is a hardening item.
+3. Is **TLS** supported/expected for the API and managed-node connections? *Proposed:* operator-configurable;
+ plaintext acceptable only on trusted networks.
+
+**Wave 2 — store, nodes, SSRF (§4/§6/§9):**
+4. How are **managed-node admin credentials** stored and used (in the store? in config?), and what protects
+ them at rest? *Proposed:* operator-supplied; stored in the metadata store; protected at the store layer.
+5. Are **node addresses** registered via the API validated/allow-listed, or will the controller connect to
+ any host:port given (SSRF)? *Proposed:* currently connects as given; allow-listing is a hardening item.
+6. Does the controller **trust the metadata store and peer controllers** as honest (out of §7), or should a
+ tampered store / Byzantine peer be modelled? *Proposed:* trusted; out of scope.
+
+**Wave 3 — properties & §11a (§8/§11a):**
+7. What **failover-correctness / split-brain** guarantees does the controller make, and under what store/peer
Review Comment:
It depends on the store engine. For example, it will have majority-win behavior if we're using the Raft/ETCD/ZK store as its store.
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,273 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, not yet reviewed by the Kvrocks PMC.** Produced by the ASF Security team via
+ the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / 0 maintainer / ~40 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **The config exposes no built-in
+ authentication knob**, so by default this role is *unauthenticated* and gated only by `addr` /
+ network reachability *(inferred — `config/config.yaml` has no API-auth section; default `addr` is
+ localhost; `server/middleware` present but role unconfirmed)*. This is the load-bearing §14 wave-1 item.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** beyond the TLS the controller supports.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With no built-in auth (pending §14), the boundary is effectively the
+network ACL around `:9379` *(inferred)*.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership. An actor who can write the store can redirect the controller *(inferred)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured *(inferred)*. Node addresses supplied via the API are an **SSRF / connect-to-arbitrary-host**
+ vector if the caller is untrusted (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model if reachable by a client the deployment treats as untrusted
+ (which, absent built-in auth, is "anyone who can reach the port" — see §14 wave-1).
+- A finding in **store handling** is in-model if reachable from API input or from store contents an
+ attacker could influence.
+- A finding in the **node client** (e.g. SSRF, credential mishandling) is in-model if a node address or
+ connection parameter is attacker-influenceable via the API.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them *(inferred)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes *(inferred)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it without a fronting auth proxy is the risk |
+| API authentication | **none present in config** | Control plane appears unauthenticated | **Open (wave-1):** is there *any* API/UI auth, and is "network-trust only" the supported posture? |
+| API/UI TLS | *(unconfirmed)* | Plaintext control-plane traffic | **Open (wave-1)** |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | **yes** (absent auth, any API client) | front with authn/authz; network ACL |
+| API: add node | **node address/host:port** | **yes** | restrict who may register nodes (SSRF surface) |
+| Web UI | form/query fields | **yes** | output encoding; CSRF protection; auth |
+| metadata store reads | topology/leadership records | from a **trusted** store *(inferred)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(inferred)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** an actor who can reach the controller API or web UI but is not the operator —
+ realistically present whenever the API is exposed beyond a trusted network without a fronting auth layer.
+ Capabilities: call any API endpoint (create/delete clusters, add/remove nodes, **force failover**,
+ migrate slots), register node addresses (SSRF), drive the UI.
+- **Goals:** seize administrative control of managed Kvrocks clusters; cause data movement/loss via slot
+ migration or failover; make the controller connect to attacker-chosen hosts; read/modify topology.
+- **Out of model:** the operator, anyone with `config.yaml` / store / managed-node credentials, and
+ (pending §14) a malicious peer controller or a compromised metadata store.
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane assumed to run on a trusted network; all *(inferred)* pending §14.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election safety (single active controller).** HA controllers coordinate via the store so that
+ conflicting administrative actions are serialized *(inferred)*. *Symptom:* two controllers issuing
+ conflicting cluster ops. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — UNRESOLVED.** Whether the API/UI authenticate callers at all is the
+ central open question (§14 wave-1); absent that, the controller claims **no** access-control property and
+ relies entirely on §10 network controls.
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication by default** *(inferred)* — exposing `:9379` (or the UI) to an
+ untrusted network without a fronting auth proxy yields an **unauthenticated administrative control plane**
+ over every managed cluster.
+- **No transport encryption guarantee by default** for the API/UI; store TLS is off unless configured.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store and its peers** — it is not a defence against a tampered store
+ or a Byzantine peer controller (pending §14).
+- **No SSRF protection on registered node addresses** *(inferred)* — the controller connects to host:port
+ values it is given; an untrusted caller who can add nodes can aim those connections.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but (pending §14) may have no authentication at
+ all* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator:** unauthenticated admin-API exposure; CSRF/XSS on the web
+UI; SSRF via node registration; plaintext control traffic; an unsecured ETCD that anyone can rewrite.
+
+## §10 Downstream (operator) responsibilities
+
+- **Do not expose the API/UI to an untrusted network without an authenticating reverse proxy / network ACL**
+ (until/unless built-in auth is confirmed).
+- Enable TLS for the API/UI, for the store connection (`etcd.tls`), and for managed-node connections on
+ untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes.
+- Restrict who may register node addresses (SSRF surface).
+
+## §11 Known misuse patterns
+
+- Binding the controller API to `0.0.0.0` on a shared network without fronting authentication.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it is not.
+
+## §11a Known non-findings (recurring false positives)
+
+*(v0 seed — PMC's real list is the key §14 input.)*
+
+- **"Unauthenticated admin API / no login on the UI"** against the default config — by design *if* the PMC
+ rules network-trust the supported posture (else it is `VALID`); resolved in §14 wave-1.
+- **"ETCD has no auth/TLS"** — operator-configured store, defaults documented (§3/§10).
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Introduction (or confirmation) of built-in API/UI authentication/authorization — would add §8 properties
+ and shrink §9/§10.
+- A change to the default `addr` / TLS posture.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening (e.g. add CSRF tokens, SSRF allow-list). | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability. | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS default, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+**Wave 1 — the central auth question (§2/§5a/§8/§9):**
+1. Does the controller API have **any built-in authentication/authorization** (token, mTLS, basic-auth), or
+ is it **network-trust only**? If the latter, is exposing it behind an operator's own auth proxy the
+ *supported* posture, so an "unauthenticated API" report is `BY-DESIGN`? *Proposed:* network-trust only
+ today; operator fronts it; unauth-on-trusted-network is by design, unauth-on-untrusted-network is misuse.
+2. Does the **web UI** authenticate, and does it have **CSRF** protection on state-changing calls?
+ *Proposed:* same as the API; CSRF is a hardening item.
+3. Is **TLS** supported/expected for the API and managed-node connections? *Proposed:* operator-configurable;
+ plaintext acceptable only on trusted networks.
+
+**Wave 2 — store, nodes, SSRF (§4/§6/§9):**
+4. How are **managed-node admin credentials** stored and used (in the store? in config?), and what protects
+ them at rest? *Proposed:* operator-supplied; stored in the metadata store; protected at the store layer.
+5. Are **node addresses** registered via the API validated/allow-listed, or will the controller connect to
+ any host:port given (SSRF)? *Proposed:* currently connects as given; allow-listing is a hardening item.
+6. Does the controller **trust the metadata store and peer controllers** as honest (out of §7), or should a
+ tampered store / Byzantine peer be modelled? *Proposed:* trusted; out of scope.
+
+**Wave 3 — properties & §11a (§8/§11a):**
+7. What **failover-correctness / split-brain** guarantees does the controller make, and under what store/peer
+ assumptions? *Proposed:* correct given a healthy store and a quorum of honest peers.
+8. What do scanners/researchers most often report here that the PMC considers a **non-finding**? (Seeds §11a.)
Review Comment:
No report yet.
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,273 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, not yet reviewed by the Kvrocks PMC.** Produced by the ASF Security team via
+ the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / 0 maintainer / ~40 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **The config exposes no built-in
+ authentication knob**, so by default this role is *unauthenticated* and gated only by `addr` /
+ network reachability *(inferred — `config/config.yaml` has no API-auth section; default `addr` is
+ localhost; `server/middleware` present but role unconfirmed)*. This is the load-bearing §14 wave-1 item.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** beyond the TLS the controller supports.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With no built-in auth (pending §14), the boundary is effectively the
+network ACL around `:9379` *(inferred)*.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership. An actor who can write the store can redirect the controller *(inferred)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured *(inferred)*. Node addresses supplied via the API are an **SSRF / connect-to-arbitrary-host**
+ vector if the caller is untrusted (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model if reachable by a client the deployment treats as untrusted
+ (which, absent built-in auth, is "anyone who can reach the port" — see §14 wave-1).
+- A finding in **store handling** is in-model if reachable from API input or from store contents an
+ attacker could influence.
+- A finding in the **node client** (e.g. SSRF, credential mishandling) is in-model if a node address or
+ connection parameter is attacker-influenceable via the API.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them *(inferred)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes *(inferred)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it without a fronting auth proxy is the risk |
+| API authentication | **none present in config** | Control plane appears unauthenticated | **Open (wave-1):** is there *any* API/UI auth, and is "network-trust only" the supported posture? |
+| API/UI TLS | *(unconfirmed)* | Plaintext control-plane traffic | **Open (wave-1)** |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | **yes** (absent auth, any API client) | front with authn/authz; network ACL |
+| API: add node | **node address/host:port** | **yes** | restrict who may register nodes (SSRF surface) |
+| Web UI | form/query fields | **yes** | output encoding; CSRF protection; auth |
+| metadata store reads | topology/leadership records | from a **trusted** store *(inferred)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(inferred)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** an actor who can reach the controller API or web UI but is not the operator —
+ realistically present whenever the API is exposed beyond a trusted network without a fronting auth layer.
+ Capabilities: call any API endpoint (create/delete clusters, add/remove nodes, **force failover**,
+ migrate slots), register node addresses (SSRF), drive the UI.
+- **Goals:** seize administrative control of managed Kvrocks clusters; cause data movement/loss via slot
+ migration or failover; make the controller connect to attacker-chosen hosts; read/modify topology.
+- **Out of model:** the operator, anyone with `config.yaml` / store / managed-node credentials, and
+ (pending §14) a malicious peer controller or a compromised metadata store.
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane assumed to run on a trusted network; all *(inferred)* pending §14.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election safety (single active controller).** HA controllers coordinate via the store so that
+ conflicting administrative actions are serialized *(inferred)*. *Symptom:* two controllers issuing
+ conflicting cluster ops. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — UNRESOLVED.** Whether the API/UI authenticate callers at all is the
+ central open question (§14 wave-1); absent that, the controller claims **no** access-control property and
+ relies entirely on §10 network controls.
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication by default** *(inferred)* — exposing `:9379` (or the UI) to an
+ untrusted network without a fronting auth proxy yields an **unauthenticated administrative control plane**
+ over every managed cluster.
+- **No transport encryption guarantee by default** for the API/UI; store TLS is off unless configured.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store and its peers** — it is not a defence against a tampered store
+ or a Byzantine peer controller (pending §14).
+- **No SSRF protection on registered node addresses** *(inferred)* — the controller connects to host:port
+ values it is given; an untrusted caller who can add nodes can aim those connections.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but (pending §14) may have no authentication at
+ all* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator:** unauthenticated admin-API exposure; CSRF/XSS on the web
+UI; SSRF via node registration; plaintext control traffic; an unsecured ETCD that anyone can rewrite.
+
+## §10 Downstream (operator) responsibilities
+
+- **Do not expose the API/UI to an untrusted network without an authenticating reverse proxy / network ACL**
+ (until/unless built-in auth is confirmed).
+- Enable TLS for the API/UI, for the store connection (`etcd.tls`), and for managed-node connections on
+ untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes.
+- Restrict who may register node addresses (SSRF surface).
+
+## §11 Known misuse patterns
+
+- Binding the controller API to `0.0.0.0` on a shared network without fronting authentication.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it is not.
+
+## §11a Known non-findings (recurring false positives)
+
+*(v0 seed — PMC's real list is the key §14 input.)*
+
+- **"Unauthenticated admin API / no login on the UI"** against the default config — by design *if* the PMC
+ rules network-trust the supported posture (else it is `VALID`); resolved in §14 wave-1.
+- **"ETCD has no auth/TLS"** — operator-configured store, defaults documented (§3/§10).
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Introduction (or confirmation) of built-in API/UI authentication/authorization — would add §8 properties
+ and shrink §9/§10.
+- A change to the default `addr` / TLS posture.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening (e.g. add CSRF tokens, SSRF allow-list). | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability. | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS default, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+**Wave 1 — the central auth question (§2/§5a/§8/§9):**
+1. Does the controller API have **any built-in authentication/authorization** (token, mTLS, basic-auth), or
+ is it **network-trust only**? If the latter, is exposing it behind an operator's own auth proxy the
+ *supported* posture, so an "unauthenticated API" report is `BY-DESIGN`? *Proposed:* network-trust only
+ today; operator fronts it; unauth-on-trusted-network is by design, unauth-on-untrusted-network is misuse.
+2. Does the **web UI** authenticate, and does it have **CSRF** protection on state-changing calls?
+ *Proposed:* same as the API; CSRF is a hardening item.
+3. Is **TLS** supported/expected for the API and managed-node connections? *Proposed:* operator-configurable;
+ plaintext acceptable only on trusted networks.
+
+**Wave 2 — store, nodes, SSRF (§4/§6/§9):**
+4. How are **managed-node admin credentials** stored and used (in the store? in config?), and what protects
+ them at rest? *Proposed:* operator-supplied; stored in the metadata store; protected at the store layer.
+5. Are **node addresses** registered via the API validated/allow-listed, or will the controller connect to
+ any host:port given (SSRF)? *Proposed:* currently connects as given; allow-listing is a hardening item.
+6. Does the controller **trust the metadata store and peer controllers** as honest (out of §7), or should a
Review Comment:
We expected to trust the metadata store and peer nodes as honest, becuase it's required to be deployed inside the trusted environment.
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,273 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, not yet reviewed by the Kvrocks PMC.** Produced by the ASF Security team via
+ the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / 0 maintainer / ~40 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **The config exposes no built-in
+ authentication knob**, so by default this role is *unauthenticated* and gated only by `addr` /
+ network reachability *(inferred — `config/config.yaml` has no API-auth section; default `addr` is
+ localhost; `server/middleware` present but role unconfirmed)*. This is the load-bearing §14 wave-1 item.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** beyond the TLS the controller supports.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With no built-in auth (pending §14), the boundary is effectively the
+network ACL around `:9379` *(inferred)*.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership. An actor who can write the store can redirect the controller *(inferred)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured *(inferred)*. Node addresses supplied via the API are an **SSRF / connect-to-arbitrary-host**
+ vector if the caller is untrusted (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model if reachable by a client the deployment treats as untrusted
+ (which, absent built-in auth, is "anyone who can reach the port" — see §14 wave-1).
+- A finding in **store handling** is in-model if reachable from API input or from store contents an
+ attacker could influence.
+- A finding in the **node client** (e.g. SSRF, credential mishandling) is in-model if a node address or
+ connection parameter is attacker-influenceable via the API.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them *(inferred)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes *(inferred)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it without a fronting auth proxy is the risk |
+| API authentication | **none present in config** | Control plane appears unauthenticated | **Open (wave-1):** is there *any* API/UI auth, and is "network-trust only" the supported posture? |
+| API/UI TLS | *(unconfirmed)* | Plaintext control-plane traffic | **Open (wave-1)** |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | **yes** (absent auth, any API client) | front with authn/authz; network ACL |
+| API: add node | **node address/host:port** | **yes** | restrict who may register nodes (SSRF surface) |
+| Web UI | form/query fields | **yes** | output encoding; CSRF protection; auth |
+| metadata store reads | topology/leadership records | from a **trusted** store *(inferred)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(inferred)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** an actor who can reach the controller API or web UI but is not the operator —
+ realistically present whenever the API is exposed beyond a trusted network without a fronting auth layer.
+ Capabilities: call any API endpoint (create/delete clusters, add/remove nodes, **force failover**,
+ migrate slots), register node addresses (SSRF), drive the UI.
+- **Goals:** seize administrative control of managed Kvrocks clusters; cause data movement/loss via slot
+ migration or failover; make the controller connect to attacker-chosen hosts; read/modify topology.
+- **Out of model:** the operator, anyone with `config.yaml` / store / managed-node credentials, and
+ (pending §14) a malicious peer controller or a compromised metadata store.
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane assumed to run on a trusted network; all *(inferred)* pending §14.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election safety (single active controller).** HA controllers coordinate via the store so that
+ conflicting administrative actions are serialized *(inferred)*. *Symptom:* two controllers issuing
+ conflicting cluster ops. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — UNRESOLVED.** Whether the API/UI authenticate callers at all is the
+ central open question (§14 wave-1); absent that, the controller claims **no** access-control property and
+ relies entirely on §10 network controls.
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication by default** *(inferred)* — exposing `:9379` (or the UI) to an
+ untrusted network without a fronting auth proxy yields an **unauthenticated administrative control plane**
+ over every managed cluster.
+- **No transport encryption guarantee by default** for the API/UI; store TLS is off unless configured.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store and its peers** — it is not a defence against a tampered store
+ or a Byzantine peer controller (pending §14).
+- **No SSRF protection on registered node addresses** *(inferred)* — the controller connects to host:port
+ values it is given; an untrusted caller who can add nodes can aim those connections.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but (pending §14) may have no authentication at
+ all* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator:** unauthenticated admin-API exposure; CSRF/XSS on the web
+UI; SSRF via node registration; plaintext control traffic; an unsecured ETCD that anyone can rewrite.
+
+## §10 Downstream (operator) responsibilities
+
+- **Do not expose the API/UI to an untrusted network without an authenticating reverse proxy / network ACL**
+ (until/unless built-in auth is confirmed).
+- Enable TLS for the API/UI, for the store connection (`etcd.tls`), and for managed-node connections on
+ untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes.
+- Restrict who may register node addresses (SSRF surface).
+
+## §11 Known misuse patterns
+
+- Binding the controller API to `0.0.0.0` on a shared network without fronting authentication.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it is not.
+
+## §11a Known non-findings (recurring false positives)
+
+*(v0 seed — PMC's real list is the key §14 input.)*
+
+- **"Unauthenticated admin API / no login on the UI"** against the default config — by design *if* the PMC
+ rules network-trust the supported posture (else it is `VALID`); resolved in §14 wave-1.
+- **"ETCD has no auth/TLS"** — operator-configured store, defaults documented (§3/§10).
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Introduction (or confirmation) of built-in API/UI authentication/authorization — would add §8 properties
+ and shrink §9/§10.
+- A change to the default `addr` / TLS posture.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening (e.g. add CSRF tokens, SSRF allow-list). | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability. | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS default, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+**Wave 1 — the central auth question (§2/§5a/§8/§9):**
+1. Does the controller API have **any built-in authentication/authorization** (token, mTLS, basic-auth), or
+ is it **network-trust only**? If the latter, is exposing it behind an operator's own auth proxy the
+ *supported* posture, so an "unauthenticated API" report is `BY-DESIGN`? *Proposed:* network-trust only
+ today; operator fronts it; unauth-on-trusted-network is by design, unauth-on-untrusted-network is misuse.
+2. Does the **web UI** authenticate, and does it have **CSRF** protection on state-changing calls?
+ *Proposed:* same as the API; CSRF is a hardening item.
+3. Is **TLS** supported/expected for the API and managed-node connections? *Proposed:* operator-configurable;
+ plaintext acceptable only on trusted networks.
+
+**Wave 2 — store, nodes, SSRF (§4/§6/§9):**
+4. How are **managed-node admin credentials** stored and used (in the store? in config?), and what protects
+ them at rest? *Proposed:* operator-supplied; stored in the metadata store; protected at the store layer.
+5. Are **node addresses** registered via the API validated/allow-listed, or will the controller connect to
+ any host:port given (SSRF)? *Proposed:* currently connects as given; allow-listing is a hardening item.
+6. Does the controller **trust the metadata store and peer controllers** as honest (out of §7), or should a
+ tampered store / Byzantine peer be modelled? *Proposed:* trusted; out of scope.
+
+**Wave 3 — properties & §11a (§8/§11a):**
+7. What **failover-correctness / split-brain** guarantees does the controller make, and under what store/peer
+ assumptions? *Proposed:* correct given a healthy store and a quorum of honest peers.
+8. What do scanners/researchers most often report here that the PMC considers a **non-finding**? (Seeds §11a.)
+
+**Meta:**
+9. Confirm this model lives as root `THREAT_MODEL.md` referenced from a new `SECURITY.md`, separate from the
Review Comment:
Yes
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@kvrocks.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Add draft threat model + SECURITY.md + AGENTS.md for security-model discoverability [kvrocks-controller]
Posted by "git-hulk (via GitHub)" <gi...@apache.org>.
git-hulk commented on code in PR #397:
URL: https://github.com/apache/kvrocks-controller/pull/397#discussion_r3353138040
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,321 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, maintainer-reviewed (git-hulk), pending PMC sign-off.** Produced by the ASF
+ Security team via the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / ~10 maintainer / ~14 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA. The
+controller is **required to be deployed inside a trusted environment** *(maintainer — git-hulk)*.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **There is no built-in
+ authentication or authorization** *(maintainer — git-hulk)*, so this role is *unauthenticated* and
+ gated only by `addr` / network reachability. Exposing an unauthenticated API is **expected behaviour**
+ today; authentication/authorization is **planned** (tracking issue
+ [apache/kvrocks-controller#390](https://github.com/apache/kvrocks-controller/issues/390)) *(maintainer
+ — git-hulk)*.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it,
+ and is expected to *(maintainer — git-hulk; trusted environment)*.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to;
+ trusted as honest *(maintainer — git-hulk)*.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store;
+ trusted as honest *(maintainer — git-hulk)*.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** — the controller does **not** provide built-in TLS; operators front it
+ with a TLS proxy such as Nginx *(maintainer — git-hulk)*.
+- **A tampered metadata store or a Byzantine peer controller** — the store and peer nodes are trusted as
+ honest because the deployment is required to be in a trusted environment *(maintainer — git-hulk)*.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With **no built-in auth** *(maintainer — git-hulk)*, the boundary is
+effectively the network ACL around `:9379`, and the deployment is required to sit in a trusted
+environment.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership, and is expected to — the store is trusted as honest *(maintainer — git-hulk)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured (expected to be **stored inside the metadata store**) *(maintainer — git-hulk)*. Node
+ addresses supplied via the API are accepted but **validated to be a real Kvrocks node**; no further
+ SSRF hardening is considered necessary *(maintainer — git-hulk)* (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model only when it breaks a §8 property; "the API is
+ unauthenticated" is by-design (§9), since the deployment is a trusted environment.
+- A finding in **store handling** is in-model if reachable from API input; the store contents themselves
+ are trusted (§7).
+- A finding in the **node client** (e.g. credential mishandling) is in-model if a connection parameter is
+ attacker-influenceable via the API; arbitrary node addresses are accepted but Kvrocks-validated
+ *(maintainer — git-hulk)*.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Deployment:** the controller, its store, its peers and its managed nodes are deployed together in a
+ **trusted environment** *(maintainer — git-hulk)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*; trusted
+ as honest *(maintainer — git-hulk)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them, and the nodes are trusted as honest *(maintainer — git-hulk)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes; there is no
+ built-in API auth or TLS, so network controls (and an optional TLS proxy) are the boundary *(maintainer
+ — git-hulk)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it on an untrusted network is operator misuse (§11) |
+| API authentication | **none** *(maintainer — git-hulk)* | Control plane is unauthenticated by design | By-design today; auth/authz planned in #390. Trusted-environment deployment is the supported posture |
+| API/UI TLS | **none built-in** *(maintainer — git-hulk)* | Plaintext control-plane traffic | By-design; operators front with a TLS proxy (e.g. Nginx) |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | only if API reachable; no built-in auth *(maintainer)* | deploy in a trusted environment; network ACL / TLS proxy |
+| API: add node | **node address/host:port** | accepted, but Kvrocks-validated *(maintainer)* | trusted-environment deployment; restrict network access |
+| Web UI | form/query fields | only if reachable; no auth/CSRF *(maintainer)* | front with auth proxy; trusted-environment deployment |
+| metadata store reads | topology/leadership records | from a **trusted** store *(maintainer)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(maintainer)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** because the controller is required to be deployed in a **trusted environment**
+ with no built-in auth *(maintainer — git-hulk)*, the modelled adversary is **not** an arbitrary network
+ client but an actor who can subvert a §8 safety property of the control plane (e.g. crafted API input
+ that crashes or corrupts the controller despite trusted callers).
+- **Goals against a §8 property:** crash/corrupt the controller via malformed input; induce incorrect
+ failover or split-brain through a §8 logic flaw (not through a tampered store).
+- **Out of model:** the operator; anyone with `config.yaml` / store / managed-node credentials; a
+ malicious peer controller or a tampered/Byzantine metadata store (the store and peers are trusted as
+ honest — *(maintainer — git-hulk)*); and an unauthenticated network client reaching `:9379`, since
+ exposing an unauthenticated API in a trusted environment is by-design (§9).
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane required to run in a trusted environment.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election / split-brain safety — store-dependent.** HA controllers coordinate via the store;
+ split-brain resolution **depends on the store engine** and is **majority-win** when using Raft / ETCD /
+ ZooKeeper *(maintainer — git-hulk)*. *Symptom:* two controllers issuing conflicting cluster ops under a
+ non-majority store. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — NOT PROVIDED (by design).** The API/UI have **no built-in
+ authentication or authorization** *(maintainer — git-hulk)*; the controller claims **no** access-control
+ property and relies entirely on §10 network controls and a trusted-environment deployment. Auth/authz is
+ planned in [#390](https://github.com/apache/kvrocks-controller/issues/390).
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication or authorization** *(maintainer — git-hulk)* — exposing
+ `:9379` (or the UI) yields an unauthenticated administrative control plane; this is **expected behaviour**
+ in the required trusted-environment deployment, with auth/authz **planned in #390**.
+- **No transport encryption** for the API/UI *(maintainer — git-hulk)* — operators front the controller
+ with a TLS proxy (e.g. Nginx); store TLS is off unless configured.
+- **No web-UI authentication or CSRF protection** *(maintainer — git-hulk)*.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store, its peers and its managed nodes as honest** *(maintainer —
+ git-hulk)* — it is not a defence against a tampered store, a Byzantine peer, or a hostile node; the
+ trusted-environment requirement covers this.
+- **No SSRF allow-listing of registered node addresses** — any address is accepted, but the controller
+ **validates that it is a real Kvrocks node**, which the PMC considers sufficient *(maintainer —
+ git-hulk)*.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but it has **no authentication and no CSRF**
+ protection* *(maintainer — git-hulk)* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator / the trusted-environment requirement:** unauthenticated
+admin-API exposure; CSRF/XSS on the web UI; plaintext control traffic; an unsecured ETCD that anyone can
+rewrite. These are accepted given the trusted-environment deployment model.
+
+## §10 Downstream (operator) responsibilities
+
+- **Deploy the controller, store, peers and managed nodes in a trusted environment** — the supported
+ posture, since there is no built-in API/UI auth *(maintainer — git-hulk)*.
+- **Do not expose the API/UI to an untrusted network**; front it with an authenticating reverse proxy /
+ network ACL and a TLS proxy (e.g. Nginx) for transport encryption *(maintainer — git-hulk)*.
+- Enable TLS for the store connection (`etcd.tls`) and for managed-node connections on untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes (these are
+ **expected to be stored inside the metadata store** *(maintainer — git-hulk)*).
+
+## §11 Known misuse patterns
+
+- Deploying the controller outside a trusted environment / exposing its API or UI to an untrusted network
+ (there is no built-in auth) *(maintainer — git-hulk)*.
+- Binding the controller API to `0.0.0.0` on a shared network without a fronting auth + TLS proxy.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it has no auth or CSRF protection.
+
+## §11a Known non-findings (recurring false positives)
+
+*(Seed list; the PMC reports **no scanner/researcher findings yet** *(maintainer — git-hulk)*, so this
+list is provisional — §14 Q8.)*
+
+- **"Unauthenticated admin API / no login on the UI / no CSRF"** against any config — **by design**; the
+ controller deliberately ships no auth and is deployed in a trusted environment; auth/authz is planned in
+ #390 *(maintainer — git-hulk)*. Disposition `BY-DESIGN`.
+- **"Controller connects to arbitrary node addresses (SSRF)"** — addresses are accepted but Kvrocks-node
+ validated; the PMC considers this sufficient and not in need of hardening *(maintainer — git-hulk)*.
+- **"Tampered ETCD / Byzantine peer redirects the controller"** — store and peers are trusted as honest in
+ the required trusted environment *(maintainer — git-hulk)*. Disposition `OUT-OF-MODEL`.
+- **"No transport encryption on the API"** — by design; operators front with a TLS proxy *(maintainer —
+ git-hulk)*.
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Landing of built-in API/UI authentication/authorization (tracked in #390) — would add §8 properties and
+ shrink §9/§10, and remove the trusted-environment requirement from several rows.
+- A change to the default `addr` / TLS posture, or built-in TLS support.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening. | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability, or an untrusted-network client (trusted-environment deployment assumed). | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS, no web-UI CSRF, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+*Wave-1 and most of wave-2/3 were answered by git-hulk on PR #397 (folded above as *(maintainer)*); they are
+retained here for traceability with their resolutions. Genuinely open items remain tagged *(inferred)*.*
+
+**Wave 1 — auth, TLS (§2/§5a/§8/§9):**
+1. **[ANSWERED — git-hulk]** Built-in API authentication/authorization? **No** — none today; an
+ unauthenticated API is expected behaviour; auth/authz is planned in
+ [#390](https://github.com/apache/kvrocks-controller/issues/390). Supported posture is a
+ trusted-environment deployment.
+2. **[ANSWERED — git-hulk]** Web-UI authentication / CSRF? **None of them** — no auth, no CSRF.
+3. **[ANSWERED — git-hulk]** TLS for the API / managed-node connections? **Not built-in** — operators use a
+ TLS proxy such as Nginx.
+
+**Wave 2 — store, nodes, SSRF (§4/§6/§9):**
+4. **[ANSWERED — git-hulk]** How are managed-node admin credentials stored? **Expected to be stored inside
+ the (metadata) store.** *(Open *(inferred)* sub-item: what protects them at rest within the store is the
+ store layer's responsibility — confirm if any controller-side protection is intended.)*
+5. **[ANSWERED — git-hulk]** Are node addresses validated/allow-listed? **All addresses are allowed, but the
+ controller validates that the target is a Kvrocks node**; no further hardening considered necessary.
+6. **[ANSWERED — git-hulk]** Trust the metadata store and peers as honest? **Yes** — required to be deployed
+ inside a trusted environment.
+
+**Wave 3 — properties & §11a (§8/§11a):**
+7. **[ANSWERED — git-hulk]** Failover-correctness / split-brain guarantees? **Depends on the store engine** —
+ majority-win with Raft / ETCD / ZooKeeper.
+8. **[ANSWERED — git-hulk]** Most common scanner/researcher non-findings? **No report yet** — §11a stays a
+ provisional seed *(inferred)* until real reports arrive.
+9. **[ANSWERED — git-hulk]** Confirm this model lives as root `THREAT_MODEL.md` referenced from a new
+ `SECURITY.md`, separate from the `apache/kvrocks` model? **Yes.**
+
+**Still open *(inferred)* — for the PMC:**
+10. *(inferred)* Confirm the operator/deployer is the only out-of-scope adversary class, and that no
+ in-process privilege boundary is claimed between API roles (none exist today).
Review Comment:
Yes for now.
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,321 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, maintainer-reviewed (git-hulk), pending PMC sign-off.** Produced by the ASF
+ Security team via the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / ~10 maintainer / ~14 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA. The
+controller is **required to be deployed inside a trusted environment** *(maintainer — git-hulk)*.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **There is no built-in
+ authentication or authorization** *(maintainer — git-hulk)*, so this role is *unauthenticated* and
+ gated only by `addr` / network reachability. Exposing an unauthenticated API is **expected behaviour**
+ today; authentication/authorization is **planned** (tracking issue
+ [apache/kvrocks-controller#390](https://github.com/apache/kvrocks-controller/issues/390)) *(maintainer
+ — git-hulk)*.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it,
+ and is expected to *(maintainer — git-hulk; trusted environment)*.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to;
+ trusted as honest *(maintainer — git-hulk)*.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store;
+ trusted as honest *(maintainer — git-hulk)*.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** — the controller does **not** provide built-in TLS; operators front it
+ with a TLS proxy such as Nginx *(maintainer — git-hulk)*.
+- **A tampered metadata store or a Byzantine peer controller** — the store and peer nodes are trusted as
+ honest because the deployment is required to be in a trusted environment *(maintainer — git-hulk)*.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With **no built-in auth** *(maintainer — git-hulk)*, the boundary is
+effectively the network ACL around `:9379`, and the deployment is required to sit in a trusted
+environment.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership, and is expected to — the store is trusted as honest *(maintainer — git-hulk)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured (expected to be **stored inside the metadata store**) *(maintainer — git-hulk)*. Node
+ addresses supplied via the API are accepted but **validated to be a real Kvrocks node**; no further
+ SSRF hardening is considered necessary *(maintainer — git-hulk)* (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model only when it breaks a §8 property; "the API is
+ unauthenticated" is by-design (§9), since the deployment is a trusted environment.
+- A finding in **store handling** is in-model if reachable from API input; the store contents themselves
+ are trusted (§7).
+- A finding in the **node client** (e.g. credential mishandling) is in-model if a connection parameter is
+ attacker-influenceable via the API; arbitrary node addresses are accepted but Kvrocks-validated
+ *(maintainer — git-hulk)*.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Deployment:** the controller, its store, its peers and its managed nodes are deployed together in a
+ **trusted environment** *(maintainer — git-hulk)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*; trusted
+ as honest *(maintainer — git-hulk)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them, and the nodes are trusted as honest *(maintainer — git-hulk)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes; there is no
+ built-in API auth or TLS, so network controls (and an optional TLS proxy) are the boundary *(maintainer
+ — git-hulk)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it on an untrusted network is operator misuse (§11) |
+| API authentication | **none** *(maintainer — git-hulk)* | Control plane is unauthenticated by design | By-design today; auth/authz planned in #390. Trusted-environment deployment is the supported posture |
+| API/UI TLS | **none built-in** *(maintainer — git-hulk)* | Plaintext control-plane traffic | By-design; operators front with a TLS proxy (e.g. Nginx) |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | only if API reachable; no built-in auth *(maintainer)* | deploy in a trusted environment; network ACL / TLS proxy |
+| API: add node | **node address/host:port** | accepted, but Kvrocks-validated *(maintainer)* | trusted-environment deployment; restrict network access |
+| Web UI | form/query fields | only if reachable; no auth/CSRF *(maintainer)* | front with auth proxy; trusted-environment deployment |
+| metadata store reads | topology/leadership records | from a **trusted** store *(maintainer)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(maintainer)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** because the controller is required to be deployed in a **trusted environment**
+ with no built-in auth *(maintainer — git-hulk)*, the modelled adversary is **not** an arbitrary network
+ client but an actor who can subvert a §8 safety property of the control plane (e.g. crafted API input
+ that crashes or corrupts the controller despite trusted callers).
+- **Goals against a §8 property:** crash/corrupt the controller via malformed input; induce incorrect
+ failover or split-brain through a §8 logic flaw (not through a tampered store).
+- **Out of model:** the operator; anyone with `config.yaml` / store / managed-node credentials; a
+ malicious peer controller or a tampered/Byzantine metadata store (the store and peers are trusted as
+ honest — *(maintainer — git-hulk)*); and an unauthenticated network client reaching `:9379`, since
+ exposing an unauthenticated API in a trusted environment is by-design (§9).
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane required to run in a trusted environment.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election / split-brain safety — store-dependent.** HA controllers coordinate via the store;
+ split-brain resolution **depends on the store engine** and is **majority-win** when using Raft / ETCD /
+ ZooKeeper *(maintainer — git-hulk)*. *Symptom:* two controllers issuing conflicting cluster ops under a
+ non-majority store. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — NOT PROVIDED (by design).** The API/UI have **no built-in
+ authentication or authorization** *(maintainer — git-hulk)*; the controller claims **no** access-control
+ property and relies entirely on §10 network controls and a trusted-environment deployment. Auth/authz is
+ planned in [#390](https://github.com/apache/kvrocks-controller/issues/390).
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication or authorization** *(maintainer — git-hulk)* — exposing
+ `:9379` (or the UI) yields an unauthenticated administrative control plane; this is **expected behaviour**
+ in the required trusted-environment deployment, with auth/authz **planned in #390**.
+- **No transport encryption** for the API/UI *(maintainer — git-hulk)* — operators front the controller
+ with a TLS proxy (e.g. Nginx); store TLS is off unless configured.
+- **No web-UI authentication or CSRF protection** *(maintainer — git-hulk)*.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store, its peers and its managed nodes as honest** *(maintainer —
+ git-hulk)* — it is not a defence against a tampered store, a Byzantine peer, or a hostile node; the
+ trusted-environment requirement covers this.
+- **No SSRF allow-listing of registered node addresses** — any address is accepted, but the controller
+ **validates that it is a real Kvrocks node**, which the PMC considers sufficient *(maintainer —
+ git-hulk)*.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but it has **no authentication and no CSRF**
+ protection* *(maintainer — git-hulk)* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator / the trusted-environment requirement:** unauthenticated
+admin-API exposure; CSRF/XSS on the web UI; plaintext control traffic; an unsecured ETCD that anyone can
+rewrite. These are accepted given the trusted-environment deployment model.
+
+## §10 Downstream (operator) responsibilities
+
+- **Deploy the controller, store, peers and managed nodes in a trusted environment** — the supported
+ posture, since there is no built-in API/UI auth *(maintainer — git-hulk)*.
+- **Do not expose the API/UI to an untrusted network**; front it with an authenticating reverse proxy /
+ network ACL and a TLS proxy (e.g. Nginx) for transport encryption *(maintainer — git-hulk)*.
+- Enable TLS for the store connection (`etcd.tls`) and for managed-node connections on untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes (these are
+ **expected to be stored inside the metadata store** *(maintainer — git-hulk)*).
+
+## §11 Known misuse patterns
+
+- Deploying the controller outside a trusted environment / exposing its API or UI to an untrusted network
+ (there is no built-in auth) *(maintainer — git-hulk)*.
+- Binding the controller API to `0.0.0.0` on a shared network without a fronting auth + TLS proxy.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it has no auth or CSRF protection.
+
+## §11a Known non-findings (recurring false positives)
+
+*(Seed list; the PMC reports **no scanner/researcher findings yet** *(maintainer — git-hulk)*, so this
+list is provisional — §14 Q8.)*
+
+- **"Unauthenticated admin API / no login on the UI / no CSRF"** against any config — **by design**; the
+ controller deliberately ships no auth and is deployed in a trusted environment; auth/authz is planned in
+ #390 *(maintainer — git-hulk)*. Disposition `BY-DESIGN`.
+- **"Controller connects to arbitrary node addresses (SSRF)"** — addresses are accepted but Kvrocks-node
+ validated; the PMC considers this sufficient and not in need of hardening *(maintainer — git-hulk)*.
+- **"Tampered ETCD / Byzantine peer redirects the controller"** — store and peers are trusted as honest in
+ the required trusted environment *(maintainer — git-hulk)*. Disposition `OUT-OF-MODEL`.
+- **"No transport encryption on the API"** — by design; operators front with a TLS proxy *(maintainer —
+ git-hulk)*.
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Landing of built-in API/UI authentication/authorization (tracked in #390) — would add §8 properties and
+ shrink §9/§10, and remove the trusted-environment requirement from several rows.
+- A change to the default `addr` / TLS posture, or built-in TLS support.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening. | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability, or an untrusted-network client (trusted-environment deployment assumed). | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS, no web-UI CSRF, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+*Wave-1 and most of wave-2/3 were answered by git-hulk on PR #397 (folded above as *(maintainer)*); they are
+retained here for traceability with their resolutions. Genuinely open items remain tagged *(inferred)*.*
+
+**Wave 1 — auth, TLS (§2/§5a/§8/§9):**
+1. **[ANSWERED — git-hulk]** Built-in API authentication/authorization? **No** — none today; an
+ unauthenticated API is expected behaviour; auth/authz is planned in
+ [#390](https://github.com/apache/kvrocks-controller/issues/390). Supported posture is a
+ trusted-environment deployment.
+2. **[ANSWERED — git-hulk]** Web-UI authentication / CSRF? **None of them** — no auth, no CSRF.
+3. **[ANSWERED — git-hulk]** TLS for the API / managed-node connections? **Not built-in** — operators use a
+ TLS proxy such as Nginx.
+
+**Wave 2 — store, nodes, SSRF (§4/§6/§9):**
+4. **[ANSWERED — git-hulk]** How are managed-node admin credentials stored? **Expected to be stored inside
+ the (metadata) store.** *(Open *(inferred)* sub-item: what protects them at rest within the store is the
+ store layer's responsibility — confirm if any controller-side protection is intended.)*
+5. **[ANSWERED — git-hulk]** Are node addresses validated/allow-listed? **All addresses are allowed, but the
+ controller validates that the target is a Kvrocks node**; no further hardening considered necessary.
+6. **[ANSWERED — git-hulk]** Trust the metadata store and peers as honest? **Yes** — required to be deployed
+ inside a trusted environment.
+
+**Wave 3 — properties & §11a (§8/§11a):**
+7. **[ANSWERED — git-hulk]** Failover-correctness / split-brain guarantees? **Depends on the store engine** —
+ majority-win with Raft / ETCD / ZooKeeper.
+8. **[ANSWERED — git-hulk]** Most common scanner/researcher non-findings? **No report yet** — §11a stays a
+ provisional seed *(inferred)* until real reports arrive.
+9. **[ANSWERED — git-hulk]** Confirm this model lives as root `THREAT_MODEL.md` referenced from a new
+ `SECURITY.md`, separate from the `apache/kvrocks` model? **Yes.**
+
+**Still open *(inferred)* — for the PMC:**
+10. *(inferred)* Confirm the operator/deployer is the only out-of-scope adversary class, and that no
+ in-process privilege boundary is claimed between API roles (none exist today).
+11. *(inferred)* Memory/handler safety on malformed API/UI input (§8.3): is a panic/crash from crafted
+ input considered `VALID`, given callers are nominally trusted?
+12. *(inferred)* Wave-2 host/network behaviour (§5): confirm the controller never executes arbitrary host
+ commands and only binds the API port + connects out to the store and nodes.
Review Comment:
Yes, it won't execute arbitrary host commands
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,321 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, maintainer-reviewed (git-hulk), pending PMC sign-off.** Produced by the ASF
+ Security team via the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / ~10 maintainer / ~14 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA. The
+controller is **required to be deployed inside a trusted environment** *(maintainer — git-hulk)*.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **There is no built-in
+ authentication or authorization** *(maintainer — git-hulk)*, so this role is *unauthenticated* and
+ gated only by `addr` / network reachability. Exposing an unauthenticated API is **expected behaviour**
+ today; authentication/authorization is **planned** (tracking issue
+ [apache/kvrocks-controller#390](https://github.com/apache/kvrocks-controller/issues/390)) *(maintainer
+ — git-hulk)*.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it,
+ and is expected to *(maintainer — git-hulk; trusted environment)*.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to;
+ trusted as honest *(maintainer — git-hulk)*.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store;
+ trusted as honest *(maintainer — git-hulk)*.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** — the controller does **not** provide built-in TLS; operators front it
+ with a TLS proxy such as Nginx *(maintainer — git-hulk)*.
+- **A tampered metadata store or a Byzantine peer controller** — the store and peer nodes are trusted as
+ honest because the deployment is required to be in a trusted environment *(maintainer — git-hulk)*.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With **no built-in auth** *(maintainer — git-hulk)*, the boundary is
+effectively the network ACL around `:9379`, and the deployment is required to sit in a trusted
+environment.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership, and is expected to — the store is trusted as honest *(maintainer — git-hulk)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured (expected to be **stored inside the metadata store**) *(maintainer — git-hulk)*. Node
+ addresses supplied via the API are accepted but **validated to be a real Kvrocks node**; no further
+ SSRF hardening is considered necessary *(maintainer — git-hulk)* (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model only when it breaks a §8 property; "the API is
+ unauthenticated" is by-design (§9), since the deployment is a trusted environment.
+- A finding in **store handling** is in-model if reachable from API input; the store contents themselves
+ are trusted (§7).
+- A finding in the **node client** (e.g. credential mishandling) is in-model if a connection parameter is
+ attacker-influenceable via the API; arbitrary node addresses are accepted but Kvrocks-validated
+ *(maintainer — git-hulk)*.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Deployment:** the controller, its store, its peers and its managed nodes are deployed together in a
+ **trusted environment** *(maintainer — git-hulk)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*; trusted
+ as honest *(maintainer — git-hulk)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them, and the nodes are trusted as honest *(maintainer — git-hulk)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes; there is no
+ built-in API auth or TLS, so network controls (and an optional TLS proxy) are the boundary *(maintainer
+ — git-hulk)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it on an untrusted network is operator misuse (§11) |
+| API authentication | **none** *(maintainer — git-hulk)* | Control plane is unauthenticated by design | By-design today; auth/authz planned in #390. Trusted-environment deployment is the supported posture |
+| API/UI TLS | **none built-in** *(maintainer — git-hulk)* | Plaintext control-plane traffic | By-design; operators front with a TLS proxy (e.g. Nginx) |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | only if API reachable; no built-in auth *(maintainer)* | deploy in a trusted environment; network ACL / TLS proxy |
+| API: add node | **node address/host:port** | accepted, but Kvrocks-validated *(maintainer)* | trusted-environment deployment; restrict network access |
+| Web UI | form/query fields | only if reachable; no auth/CSRF *(maintainer)* | front with auth proxy; trusted-environment deployment |
+| metadata store reads | topology/leadership records | from a **trusted** store *(maintainer)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(maintainer)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** because the controller is required to be deployed in a **trusted environment**
+ with no built-in auth *(maintainer — git-hulk)*, the modelled adversary is **not** an arbitrary network
+ client but an actor who can subvert a §8 safety property of the control plane (e.g. crafted API input
+ that crashes or corrupts the controller despite trusted callers).
+- **Goals against a §8 property:** crash/corrupt the controller via malformed input; induce incorrect
+ failover or split-brain through a §8 logic flaw (not through a tampered store).
+- **Out of model:** the operator; anyone with `config.yaml` / store / managed-node credentials; a
+ malicious peer controller or a tampered/Byzantine metadata store (the store and peers are trusted as
+ honest — *(maintainer — git-hulk)*); and an unauthenticated network client reaching `:9379`, since
+ exposing an unauthenticated API in a trusted environment is by-design (§9).
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane required to run in a trusted environment.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election / split-brain safety — store-dependent.** HA controllers coordinate via the store;
+ split-brain resolution **depends on the store engine** and is **majority-win** when using Raft / ETCD /
+ ZooKeeper *(maintainer — git-hulk)*. *Symptom:* two controllers issuing conflicting cluster ops under a
+ non-majority store. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — NOT PROVIDED (by design).** The API/UI have **no built-in
+ authentication or authorization** *(maintainer — git-hulk)*; the controller claims **no** access-control
+ property and relies entirely on §10 network controls and a trusted-environment deployment. Auth/authz is
+ planned in [#390](https://github.com/apache/kvrocks-controller/issues/390).
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication or authorization** *(maintainer — git-hulk)* — exposing
+ `:9379` (or the UI) yields an unauthenticated administrative control plane; this is **expected behaviour**
+ in the required trusted-environment deployment, with auth/authz **planned in #390**.
+- **No transport encryption** for the API/UI *(maintainer — git-hulk)* — operators front the controller
+ with a TLS proxy (e.g. Nginx); store TLS is off unless configured.
+- **No web-UI authentication or CSRF protection** *(maintainer — git-hulk)*.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store, its peers and its managed nodes as honest** *(maintainer —
+ git-hulk)* — it is not a defence against a tampered store, a Byzantine peer, or a hostile node; the
+ trusted-environment requirement covers this.
+- **No SSRF allow-listing of registered node addresses** — any address is accepted, but the controller
+ **validates that it is a real Kvrocks node**, which the PMC considers sufficient *(maintainer —
+ git-hulk)*.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but it has **no authentication and no CSRF**
+ protection* *(maintainer — git-hulk)* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator / the trusted-environment requirement:** unauthenticated
+admin-API exposure; CSRF/XSS on the web UI; plaintext control traffic; an unsecured ETCD that anyone can
+rewrite. These are accepted given the trusted-environment deployment model.
+
+## §10 Downstream (operator) responsibilities
+
+- **Deploy the controller, store, peers and managed nodes in a trusted environment** — the supported
+ posture, since there is no built-in API/UI auth *(maintainer — git-hulk)*.
+- **Do not expose the API/UI to an untrusted network**; front it with an authenticating reverse proxy /
+ network ACL and a TLS proxy (e.g. Nginx) for transport encryption *(maintainer — git-hulk)*.
+- Enable TLS for the store connection (`etcd.tls`) and for managed-node connections on untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes (these are
+ **expected to be stored inside the metadata store** *(maintainer — git-hulk)*).
+
+## §11 Known misuse patterns
+
+- Deploying the controller outside a trusted environment / exposing its API or UI to an untrusted network
+ (there is no built-in auth) *(maintainer — git-hulk)*.
+- Binding the controller API to `0.0.0.0` on a shared network without a fronting auth + TLS proxy.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it has no auth or CSRF protection.
+
+## §11a Known non-findings (recurring false positives)
+
+*(Seed list; the PMC reports **no scanner/researcher findings yet** *(maintainer — git-hulk)*, so this
+list is provisional — §14 Q8.)*
+
+- **"Unauthenticated admin API / no login on the UI / no CSRF"** against any config — **by design**; the
+ controller deliberately ships no auth and is deployed in a trusted environment; auth/authz is planned in
+ #390 *(maintainer — git-hulk)*. Disposition `BY-DESIGN`.
+- **"Controller connects to arbitrary node addresses (SSRF)"** — addresses are accepted but Kvrocks-node
+ validated; the PMC considers this sufficient and not in need of hardening *(maintainer — git-hulk)*.
+- **"Tampered ETCD / Byzantine peer redirects the controller"** — store and peers are trusted as honest in
+ the required trusted environment *(maintainer — git-hulk)*. Disposition `OUT-OF-MODEL`.
+- **"No transport encryption on the API"** — by design; operators front with a TLS proxy *(maintainer —
+ git-hulk)*.
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Landing of built-in API/UI authentication/authorization (tracked in #390) — would add §8 properties and
+ shrink §9/§10, and remove the trusted-environment requirement from several rows.
+- A change to the default `addr` / TLS posture, or built-in TLS support.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening. | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability, or an untrusted-network client (trusted-environment deployment assumed). | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS, no web-UI CSRF, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+*Wave-1 and most of wave-2/3 were answered by git-hulk on PR #397 (folded above as *(maintainer)*); they are
+retained here for traceability with their resolutions. Genuinely open items remain tagged *(inferred)*.*
+
+**Wave 1 — auth, TLS (§2/§5a/§8/§9):**
+1. **[ANSWERED — git-hulk]** Built-in API authentication/authorization? **No** — none today; an
+ unauthenticated API is expected behaviour; auth/authz is planned in
+ [#390](https://github.com/apache/kvrocks-controller/issues/390). Supported posture is a
+ trusted-environment deployment.
+2. **[ANSWERED — git-hulk]** Web-UI authentication / CSRF? **None of them** — no auth, no CSRF.
+3. **[ANSWERED — git-hulk]** TLS for the API / managed-node connections? **Not built-in** — operators use a
+ TLS proxy such as Nginx.
+
+**Wave 2 — store, nodes, SSRF (§4/§6/§9):**
+4. **[ANSWERED — git-hulk]** How are managed-node admin credentials stored? **Expected to be stored inside
+ the (metadata) store.** *(Open *(inferred)* sub-item: what protects them at rest within the store is the
+ store layer's responsibility — confirm if any controller-side protection is intended.)*
+5. **[ANSWERED — git-hulk]** Are node addresses validated/allow-listed? **All addresses are allowed, but the
+ controller validates that the target is a Kvrocks node**; no further hardening considered necessary.
+6. **[ANSWERED — git-hulk]** Trust the metadata store and peers as honest? **Yes** — required to be deployed
+ inside a trusted environment.
+
+**Wave 3 — properties & §11a (§8/§11a):**
+7. **[ANSWERED — git-hulk]** Failover-correctness / split-brain guarantees? **Depends on the store engine** —
+ majority-win with Raft / ETCD / ZooKeeper.
+8. **[ANSWERED — git-hulk]** Most common scanner/researcher non-findings? **No report yet** — §11a stays a
+ provisional seed *(inferred)* until real reports arrive.
+9. **[ANSWERED — git-hulk]** Confirm this model lives as root `THREAT_MODEL.md` referenced from a new
+ `SECURITY.md`, separate from the `apache/kvrocks` model? **Yes.**
+
+**Still open *(inferred)* — for the PMC:**
+10. *(inferred)* Confirm the operator/deployer is the only out-of-scope adversary class, and that no
+ in-process privilege boundary is claimed between API roles (none exist today).
+11. *(inferred)* Memory/handler safety on malformed API/UI input (§8.3): is a panic/crash from crafted
+ input considered `VALID`, given callers are nominally trusted?
+12. *(inferred)* Wave-2 host/network behaviour (§5): confirm the controller never executes arbitrary host
+ commands and only binds the API port + connects out to the store and nodes.
+13. *(inferred)* Within-store protection of node credentials at rest (follow-up to Q4): is any
+ controller-side encryption of stored credentials intended, or is it wholly the store's responsibility?
Review Comment:
Yes, we should have a way to encrypt users' credentials. Will create an issue to track this.
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,321 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, maintainer-reviewed (git-hulk), pending PMC sign-off.** Produced by the ASF
+ Security team via the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / ~10 maintainer / ~14 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA. The
+controller is **required to be deployed inside a trusted environment** *(maintainer — git-hulk)*.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **There is no built-in
+ authentication or authorization** *(maintainer — git-hulk)*, so this role is *unauthenticated* and
+ gated only by `addr` / network reachability. Exposing an unauthenticated API is **expected behaviour**
+ today; authentication/authorization is **planned** (tracking issue
+ [apache/kvrocks-controller#390](https://github.com/apache/kvrocks-controller/issues/390)) *(maintainer
+ — git-hulk)*.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it,
+ and is expected to *(maintainer — git-hulk; trusted environment)*.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to;
+ trusted as honest *(maintainer — git-hulk)*.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store;
+ trusted as honest *(maintainer — git-hulk)*.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** — the controller does **not** provide built-in TLS; operators front it
+ with a TLS proxy such as Nginx *(maintainer — git-hulk)*.
+- **A tampered metadata store or a Byzantine peer controller** — the store and peer nodes are trusted as
+ honest because the deployment is required to be in a trusted environment *(maintainer — git-hulk)*.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With **no built-in auth** *(maintainer — git-hulk)*, the boundary is
+effectively the network ACL around `:9379`, and the deployment is required to sit in a trusted
+environment.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership, and is expected to — the store is trusted as honest *(maintainer — git-hulk)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured (expected to be **stored inside the metadata store**) *(maintainer — git-hulk)*. Node
+ addresses supplied via the API are accepted but **validated to be a real Kvrocks node**; no further
+ SSRF hardening is considered necessary *(maintainer — git-hulk)* (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model only when it breaks a §8 property; "the API is
+ unauthenticated" is by-design (§9), since the deployment is a trusted environment.
+- A finding in **store handling** is in-model if reachable from API input; the store contents themselves
+ are trusted (§7).
+- A finding in the **node client** (e.g. credential mishandling) is in-model if a connection parameter is
+ attacker-influenceable via the API; arbitrary node addresses are accepted but Kvrocks-validated
+ *(maintainer — git-hulk)*.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Deployment:** the controller, its store, its peers and its managed nodes are deployed together in a
+ **trusted environment** *(maintainer — git-hulk)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*; trusted
+ as honest *(maintainer — git-hulk)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them, and the nodes are trusted as honest *(maintainer — git-hulk)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes; there is no
+ built-in API auth or TLS, so network controls (and an optional TLS proxy) are the boundary *(maintainer
+ — git-hulk)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it on an untrusted network is operator misuse (§11) |
+| API authentication | **none** *(maintainer — git-hulk)* | Control plane is unauthenticated by design | By-design today; auth/authz planned in #390. Trusted-environment deployment is the supported posture |
+| API/UI TLS | **none built-in** *(maintainer — git-hulk)* | Plaintext control-plane traffic | By-design; operators front with a TLS proxy (e.g. Nginx) |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | only if API reachable; no built-in auth *(maintainer)* | deploy in a trusted environment; network ACL / TLS proxy |
+| API: add node | **node address/host:port** | accepted, but Kvrocks-validated *(maintainer)* | trusted-environment deployment; restrict network access |
+| Web UI | form/query fields | only if reachable; no auth/CSRF *(maintainer)* | front with auth proxy; trusted-environment deployment |
+| metadata store reads | topology/leadership records | from a **trusted** store *(maintainer)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(maintainer)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** because the controller is required to be deployed in a **trusted environment**
+ with no built-in auth *(maintainer — git-hulk)*, the modelled adversary is **not** an arbitrary network
+ client but an actor who can subvert a §8 safety property of the control plane (e.g. crafted API input
+ that crashes or corrupts the controller despite trusted callers).
+- **Goals against a §8 property:** crash/corrupt the controller via malformed input; induce incorrect
+ failover or split-brain through a §8 logic flaw (not through a tampered store).
+- **Out of model:** the operator; anyone with `config.yaml` / store / managed-node credentials; a
+ malicious peer controller or a tampered/Byzantine metadata store (the store and peers are trusted as
+ honest — *(maintainer — git-hulk)*); and an unauthenticated network client reaching `:9379`, since
+ exposing an unauthenticated API in a trusted environment is by-design (§9).
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane required to run in a trusted environment.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election / split-brain safety — store-dependent.** HA controllers coordinate via the store;
+ split-brain resolution **depends on the store engine** and is **majority-win** when using Raft / ETCD /
+ ZooKeeper *(maintainer — git-hulk)*. *Symptom:* two controllers issuing conflicting cluster ops under a
+ non-majority store. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — NOT PROVIDED (by design).** The API/UI have **no built-in
+ authentication or authorization** *(maintainer — git-hulk)*; the controller claims **no** access-control
+ property and relies entirely on §10 network controls and a trusted-environment deployment. Auth/authz is
+ planned in [#390](https://github.com/apache/kvrocks-controller/issues/390).
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication or authorization** *(maintainer — git-hulk)* — exposing
+ `:9379` (or the UI) yields an unauthenticated administrative control plane; this is **expected behaviour**
+ in the required trusted-environment deployment, with auth/authz **planned in #390**.
+- **No transport encryption** for the API/UI *(maintainer — git-hulk)* — operators front the controller
+ with a TLS proxy (e.g. Nginx); store TLS is off unless configured.
+- **No web-UI authentication or CSRF protection** *(maintainer — git-hulk)*.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store, its peers and its managed nodes as honest** *(maintainer —
+ git-hulk)* — it is not a defence against a tampered store, a Byzantine peer, or a hostile node; the
+ trusted-environment requirement covers this.
+- **No SSRF allow-listing of registered node addresses** — any address is accepted, but the controller
+ **validates that it is a real Kvrocks node**, which the PMC considers sufficient *(maintainer —
+ git-hulk)*.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but it has **no authentication and no CSRF**
+ protection* *(maintainer — git-hulk)* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator / the trusted-environment requirement:** unauthenticated
+admin-API exposure; CSRF/XSS on the web UI; plaintext control traffic; an unsecured ETCD that anyone can
+rewrite. These are accepted given the trusted-environment deployment model.
+
+## §10 Downstream (operator) responsibilities
+
+- **Deploy the controller, store, peers and managed nodes in a trusted environment** — the supported
+ posture, since there is no built-in API/UI auth *(maintainer — git-hulk)*.
+- **Do not expose the API/UI to an untrusted network**; front it with an authenticating reverse proxy /
+ network ACL and a TLS proxy (e.g. Nginx) for transport encryption *(maintainer — git-hulk)*.
+- Enable TLS for the store connection (`etcd.tls`) and for managed-node connections on untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes (these are
+ **expected to be stored inside the metadata store** *(maintainer — git-hulk)*).
+
+## §11 Known misuse patterns
+
+- Deploying the controller outside a trusted environment / exposing its API or UI to an untrusted network
+ (there is no built-in auth) *(maintainer — git-hulk)*.
+- Binding the controller API to `0.0.0.0` on a shared network without a fronting auth + TLS proxy.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it has no auth or CSRF protection.
+
+## §11a Known non-findings (recurring false positives)
+
+*(Seed list; the PMC reports **no scanner/researcher findings yet** *(maintainer — git-hulk)*, so this
+list is provisional — §14 Q8.)*
+
+- **"Unauthenticated admin API / no login on the UI / no CSRF"** against any config — **by design**; the
+ controller deliberately ships no auth and is deployed in a trusted environment; auth/authz is planned in
+ #390 *(maintainer — git-hulk)*. Disposition `BY-DESIGN`.
+- **"Controller connects to arbitrary node addresses (SSRF)"** — addresses are accepted but Kvrocks-node
+ validated; the PMC considers this sufficient and not in need of hardening *(maintainer — git-hulk)*.
+- **"Tampered ETCD / Byzantine peer redirects the controller"** — store and peers are trusted as honest in
+ the required trusted environment *(maintainer — git-hulk)*. Disposition `OUT-OF-MODEL`.
+- **"No transport encryption on the API"** — by design; operators front with a TLS proxy *(maintainer —
+ git-hulk)*.
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Landing of built-in API/UI authentication/authorization (tracked in #390) — would add §8 properties and
+ shrink §9/§10, and remove the trusted-environment requirement from several rows.
+- A change to the default `addr` / TLS posture, or built-in TLS support.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening. | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability, or an untrusted-network client (trusted-environment deployment assumed). | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS, no web-UI CSRF, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+*Wave-1 and most of wave-2/3 were answered by git-hulk on PR #397 (folded above as *(maintainer)*); they are
+retained here for traceability with their resolutions. Genuinely open items remain tagged *(inferred)*.*
+
+**Wave 1 — auth, TLS (§2/§5a/§8/§9):**
+1. **[ANSWERED — git-hulk]** Built-in API authentication/authorization? **No** — none today; an
+ unauthenticated API is expected behaviour; auth/authz is planned in
+ [#390](https://github.com/apache/kvrocks-controller/issues/390). Supported posture is a
+ trusted-environment deployment.
+2. **[ANSWERED — git-hulk]** Web-UI authentication / CSRF? **None of them** — no auth, no CSRF.
+3. **[ANSWERED — git-hulk]** TLS for the API / managed-node connections? **Not built-in** — operators use a
+ TLS proxy such as Nginx.
+
+**Wave 2 — store, nodes, SSRF (§4/§6/§9):**
+4. **[ANSWERED — git-hulk]** How are managed-node admin credentials stored? **Expected to be stored inside
+ the (metadata) store.** *(Open *(inferred)* sub-item: what protects them at rest within the store is the
+ store layer's responsibility — confirm if any controller-side protection is intended.)*
+5. **[ANSWERED — git-hulk]** Are node addresses validated/allow-listed? **All addresses are allowed, but the
+ controller validates that the target is a Kvrocks node**; no further hardening considered necessary.
+6. **[ANSWERED — git-hulk]** Trust the metadata store and peers as honest? **Yes** — required to be deployed
+ inside a trusted environment.
+
+**Wave 3 — properties & §11a (§8/§11a):**
+7. **[ANSWERED — git-hulk]** Failover-correctness / split-brain guarantees? **Depends on the store engine** —
+ majority-win with Raft / ETCD / ZooKeeper.
+8. **[ANSWERED — git-hulk]** Most common scanner/researcher non-findings? **No report yet** — §11a stays a
+ provisional seed *(inferred)* until real reports arrive.
+9. **[ANSWERED — git-hulk]** Confirm this model lives as root `THREAT_MODEL.md` referenced from a new
+ `SECURITY.md`, separate from the `apache/kvrocks` model? **Yes.**
+
+**Still open *(inferred)* — for the PMC:**
+10. *(inferred)* Confirm the operator/deployer is the only out-of-scope adversary class, and that no
+ in-process privilege boundary is claimed between API roles (none exist today).
+11. *(inferred)* Memory/handler safety on malformed API/UI input (§8.3): is a panic/crash from crafted
+ input considered `VALID`, given callers are nominally trusted?
Review Comment:
It should be considered as a valid issue.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@kvrocks.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Add draft threat model + SECURITY.md + AGENTS.md for security-model discoverability [kvrocks-controller]
Posted by "potiuk (via GitHub)" <gi...@apache.org>.
potiuk commented on code in PR #397:
URL: https://github.com/apache/kvrocks-controller/pull/397#discussion_r3359700733
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,321 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, maintainer-reviewed (git-hulk), pending PMC sign-off.** Produced by the ASF
+ Security team via the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / ~10 maintainer / ~14 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA. The
+controller is **required to be deployed inside a trusted environment** *(maintainer — git-hulk)*.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **There is no built-in
+ authentication or authorization** *(maintainer — git-hulk)*, so this role is *unauthenticated* and
+ gated only by `addr` / network reachability. Exposing an unauthenticated API is **expected behaviour**
+ today; authentication/authorization is **planned** (tracking issue
+ [apache/kvrocks-controller#390](https://github.com/apache/kvrocks-controller/issues/390)) *(maintainer
+ — git-hulk)*.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it,
+ and is expected to *(maintainer — git-hulk; trusted environment)*.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to;
+ trusted as honest *(maintainer — git-hulk)*.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store;
+ trusted as honest *(maintainer — git-hulk)*.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** — the controller does **not** provide built-in TLS; operators front it
+ with a TLS proxy such as Nginx *(maintainer — git-hulk)*.
+- **A tampered metadata store or a Byzantine peer controller** — the store and peer nodes are trusted as
+ honest because the deployment is required to be in a trusted environment *(maintainer — git-hulk)*.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With **no built-in auth** *(maintainer — git-hulk)*, the boundary is
+effectively the network ACL around `:9379`, and the deployment is required to sit in a trusted
+environment.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership, and is expected to — the store is trusted as honest *(maintainer — git-hulk)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured (expected to be **stored inside the metadata store**) *(maintainer — git-hulk)*. Node
+ addresses supplied via the API are accepted but **validated to be a real Kvrocks node**; no further
+ SSRF hardening is considered necessary *(maintainer — git-hulk)* (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model only when it breaks a §8 property; "the API is
+ unauthenticated" is by-design (§9), since the deployment is a trusted environment.
+- A finding in **store handling** is in-model if reachable from API input; the store contents themselves
+ are trusted (§7).
+- A finding in the **node client** (e.g. credential mishandling) is in-model if a connection parameter is
+ attacker-influenceable via the API; arbitrary node addresses are accepted but Kvrocks-validated
+ *(maintainer — git-hulk)*.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Deployment:** the controller, its store, its peers and its managed nodes are deployed together in a
+ **trusted environment** *(maintainer — git-hulk)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*; trusted
+ as honest *(maintainer — git-hulk)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them, and the nodes are trusted as honest *(maintainer — git-hulk)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes; there is no
+ built-in API auth or TLS, so network controls (and an optional TLS proxy) are the boundary *(maintainer
+ — git-hulk)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it on an untrusted network is operator misuse (§11) |
+| API authentication | **none** *(maintainer — git-hulk)* | Control plane is unauthenticated by design | By-design today; auth/authz planned in #390. Trusted-environment deployment is the supported posture |
+| API/UI TLS | **none built-in** *(maintainer — git-hulk)* | Plaintext control-plane traffic | By-design; operators front with a TLS proxy (e.g. Nginx) |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | only if API reachable; no built-in auth *(maintainer)* | deploy in a trusted environment; network ACL / TLS proxy |
+| API: add node | **node address/host:port** | accepted, but Kvrocks-validated *(maintainer)* | trusted-environment deployment; restrict network access |
+| Web UI | form/query fields | only if reachable; no auth/CSRF *(maintainer)* | front with auth proxy; trusted-environment deployment |
+| metadata store reads | topology/leadership records | from a **trusted** store *(maintainer)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(maintainer)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** because the controller is required to be deployed in a **trusted environment**
+ with no built-in auth *(maintainer — git-hulk)*, the modelled adversary is **not** an arbitrary network
+ client but an actor who can subvert a §8 safety property of the control plane (e.g. crafted API input
+ that crashes or corrupts the controller despite trusted callers).
+- **Goals against a §8 property:** crash/corrupt the controller via malformed input; induce incorrect
+ failover or split-brain through a §8 logic flaw (not through a tampered store).
+- **Out of model:** the operator; anyone with `config.yaml` / store / managed-node credentials; a
+ malicious peer controller or a tampered/Byzantine metadata store (the store and peers are trusted as
+ honest — *(maintainer — git-hulk)*); and an unauthenticated network client reaching `:9379`, since
+ exposing an unauthenticated API in a trusted environment is by-design (§9).
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane required to run in a trusted environment.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election / split-brain safety — store-dependent.** HA controllers coordinate via the store;
+ split-brain resolution **depends on the store engine** and is **majority-win** when using Raft / ETCD /
+ ZooKeeper *(maintainer — git-hulk)*. *Symptom:* two controllers issuing conflicting cluster ops under a
+ non-majority store. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — NOT PROVIDED (by design).** The API/UI have **no built-in
+ authentication or authorization** *(maintainer — git-hulk)*; the controller claims **no** access-control
+ property and relies entirely on §10 network controls and a trusted-environment deployment. Auth/authz is
+ planned in [#390](https://github.com/apache/kvrocks-controller/issues/390).
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication or authorization** *(maintainer — git-hulk)* — exposing
+ `:9379` (or the UI) yields an unauthenticated administrative control plane; this is **expected behaviour**
+ in the required trusted-environment deployment, with auth/authz **planned in #390**.
+- **No transport encryption** for the API/UI *(maintainer — git-hulk)* — operators front the controller
+ with a TLS proxy (e.g. Nginx); store TLS is off unless configured.
+- **No web-UI authentication or CSRF protection** *(maintainer — git-hulk)*.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store, its peers and its managed nodes as honest** *(maintainer —
+ git-hulk)* — it is not a defence against a tampered store, a Byzantine peer, or a hostile node; the
+ trusted-environment requirement covers this.
+- **No SSRF allow-listing of registered node addresses** — any address is accepted, but the controller
+ **validates that it is a real Kvrocks node**, which the PMC considers sufficient *(maintainer —
+ git-hulk)*.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but it has **no authentication and no CSRF**
+ protection* *(maintainer — git-hulk)* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator / the trusted-environment requirement:** unauthenticated
+admin-API exposure; CSRF/XSS on the web UI; plaintext control traffic; an unsecured ETCD that anyone can
+rewrite. These are accepted given the trusted-environment deployment model.
+
+## §10 Downstream (operator) responsibilities
+
+- **Deploy the controller, store, peers and managed nodes in a trusted environment** — the supported
+ posture, since there is no built-in API/UI auth *(maintainer — git-hulk)*.
+- **Do not expose the API/UI to an untrusted network**; front it with an authenticating reverse proxy /
+ network ACL and a TLS proxy (e.g. Nginx) for transport encryption *(maintainer — git-hulk)*.
+- Enable TLS for the store connection (`etcd.tls`) and for managed-node connections on untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes (these are
+ **expected to be stored inside the metadata store** *(maintainer — git-hulk)*).
+
+## §11 Known misuse patterns
+
+- Deploying the controller outside a trusted environment / exposing its API or UI to an untrusted network
+ (there is no built-in auth) *(maintainer — git-hulk)*.
+- Binding the controller API to `0.0.0.0` on a shared network without a fronting auth + TLS proxy.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it has no auth or CSRF protection.
+
+## §11a Known non-findings (recurring false positives)
+
+*(Seed list; the PMC reports **no scanner/researcher findings yet** *(maintainer — git-hulk)*, so this
+list is provisional — §14 Q8.)*
+
+- **"Unauthenticated admin API / no login on the UI / no CSRF"** against any config — **by design**; the
+ controller deliberately ships no auth and is deployed in a trusted environment; auth/authz is planned in
+ #390 *(maintainer — git-hulk)*. Disposition `BY-DESIGN`.
+- **"Controller connects to arbitrary node addresses (SSRF)"** — addresses are accepted but Kvrocks-node
+ validated; the PMC considers this sufficient and not in need of hardening *(maintainer — git-hulk)*.
+- **"Tampered ETCD / Byzantine peer redirects the controller"** — store and peers are trusted as honest in
+ the required trusted environment *(maintainer — git-hulk)*. Disposition `OUT-OF-MODEL`.
+- **"No transport encryption on the API"** — by design; operators front with a TLS proxy *(maintainer —
+ git-hulk)*.
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Landing of built-in API/UI authentication/authorization (tracked in #390) — would add §8 properties and
+ shrink §9/§10, and remove the trusted-environment requirement from several rows.
+- A change to the default `addr` / TLS posture, or built-in TLS support.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening. | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability, or an untrusted-network client (trusted-environment deployment assumed). | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS, no web-UI CSRF, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+*Wave-1 and most of wave-2/3 were answered by git-hulk on PR #397 (folded above as *(maintainer)*); they are
+retained here for traceability with their resolutions. Genuinely open items remain tagged *(inferred)*.*
+
+**Wave 1 — auth, TLS (§2/§5a/§8/§9):**
+1. **[ANSWERED — git-hulk]** Built-in API authentication/authorization? **No** — none today; an
+ unauthenticated API is expected behaviour; auth/authz is planned in
+ [#390](https://github.com/apache/kvrocks-controller/issues/390). Supported posture is a
+ trusted-environment deployment.
+2. **[ANSWERED — git-hulk]** Web-UI authentication / CSRF? **None of them** — no auth, no CSRF.
+3. **[ANSWERED — git-hulk]** TLS for the API / managed-node connections? **Not built-in** — operators use a
+ TLS proxy such as Nginx.
+
+**Wave 2 — store, nodes, SSRF (§4/§6/§9):**
+4. **[ANSWERED — git-hulk]** How are managed-node admin credentials stored? **Expected to be stored inside
+ the (metadata) store.** *(Open *(inferred)* sub-item: what protects them at rest within the store is the
+ store layer's responsibility — confirm if any controller-side protection is intended.)*
+5. **[ANSWERED — git-hulk]** Are node addresses validated/allow-listed? **All addresses are allowed, but the
+ controller validates that the target is a Kvrocks node**; no further hardening considered necessary.
+6. **[ANSWERED — git-hulk]** Trust the metadata store and peers as honest? **Yes** — required to be deployed
+ inside a trusted environment.
+
+**Wave 3 — properties & §11a (§8/§11a):**
+7. **[ANSWERED — git-hulk]** Failover-correctness / split-brain guarantees? **Depends on the store engine** —
+ majority-win with Raft / ETCD / ZooKeeper.
+8. **[ANSWERED — git-hulk]** Most common scanner/researcher non-findings? **No report yet** — §11a stays a
+ provisional seed *(inferred)* until real reports arrive.
+9. **[ANSWERED — git-hulk]** Confirm this model lives as root `THREAT_MODEL.md` referenced from a new
+ `SECURITY.md`, separate from the `apache/kvrocks` model? **Yes.**
+
+**Still open *(inferred)* — for the PMC:**
+10. *(inferred)* Confirm the operator/deployer is the only out-of-scope adversary class, and that no
+ in-process privilege boundary is claimed between API roles (none exist today).
Review Comment:
Folded — §14 Q10 now records the operator/deployer as the only out-of-scope adversary class, no in-process role boundary. Thanks!
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,321 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, maintainer-reviewed (git-hulk), pending PMC sign-off.** Produced by the ASF
+ Security team via the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / ~10 maintainer / ~14 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA. The
+controller is **required to be deployed inside a trusted environment** *(maintainer — git-hulk)*.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **There is no built-in
+ authentication or authorization** *(maintainer — git-hulk)*, so this role is *unauthenticated* and
+ gated only by `addr` / network reachability. Exposing an unauthenticated API is **expected behaviour**
+ today; authentication/authorization is **planned** (tracking issue
+ [apache/kvrocks-controller#390](https://github.com/apache/kvrocks-controller/issues/390)) *(maintainer
+ — git-hulk)*.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it,
+ and is expected to *(maintainer — git-hulk; trusted environment)*.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to;
+ trusted as honest *(maintainer — git-hulk)*.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store;
+ trusted as honest *(maintainer — git-hulk)*.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** — the controller does **not** provide built-in TLS; operators front it
+ with a TLS proxy such as Nginx *(maintainer — git-hulk)*.
+- **A tampered metadata store or a Byzantine peer controller** — the store and peer nodes are trusted as
+ honest because the deployment is required to be in a trusted environment *(maintainer — git-hulk)*.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With **no built-in auth** *(maintainer — git-hulk)*, the boundary is
+effectively the network ACL around `:9379`, and the deployment is required to sit in a trusted
+environment.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership, and is expected to — the store is trusted as honest *(maintainer — git-hulk)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured (expected to be **stored inside the metadata store**) *(maintainer — git-hulk)*. Node
+ addresses supplied via the API are accepted but **validated to be a real Kvrocks node**; no further
+ SSRF hardening is considered necessary *(maintainer — git-hulk)* (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model only when it breaks a §8 property; "the API is
+ unauthenticated" is by-design (§9), since the deployment is a trusted environment.
+- A finding in **store handling** is in-model if reachable from API input; the store contents themselves
+ are trusted (§7).
+- A finding in the **node client** (e.g. credential mishandling) is in-model if a connection parameter is
+ attacker-influenceable via the API; arbitrary node addresses are accepted but Kvrocks-validated
+ *(maintainer — git-hulk)*.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Deployment:** the controller, its store, its peers and its managed nodes are deployed together in a
+ **trusted environment** *(maintainer — git-hulk)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*; trusted
+ as honest *(maintainer — git-hulk)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them, and the nodes are trusted as honest *(maintainer — git-hulk)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes; there is no
+ built-in API auth or TLS, so network controls (and an optional TLS proxy) are the boundary *(maintainer
+ — git-hulk)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it on an untrusted network is operator misuse (§11) |
+| API authentication | **none** *(maintainer — git-hulk)* | Control plane is unauthenticated by design | By-design today; auth/authz planned in #390. Trusted-environment deployment is the supported posture |
+| API/UI TLS | **none built-in** *(maintainer — git-hulk)* | Plaintext control-plane traffic | By-design; operators front with a TLS proxy (e.g. Nginx) |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | only if API reachable; no built-in auth *(maintainer)* | deploy in a trusted environment; network ACL / TLS proxy |
+| API: add node | **node address/host:port** | accepted, but Kvrocks-validated *(maintainer)* | trusted-environment deployment; restrict network access |
+| Web UI | form/query fields | only if reachable; no auth/CSRF *(maintainer)* | front with auth proxy; trusted-environment deployment |
+| metadata store reads | topology/leadership records | from a **trusted** store *(maintainer)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(maintainer)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** because the controller is required to be deployed in a **trusted environment**
+ with no built-in auth *(maintainer — git-hulk)*, the modelled adversary is **not** an arbitrary network
+ client but an actor who can subvert a §8 safety property of the control plane (e.g. crafted API input
+ that crashes or corrupts the controller despite trusted callers).
+- **Goals against a §8 property:** crash/corrupt the controller via malformed input; induce incorrect
+ failover or split-brain through a §8 logic flaw (not through a tampered store).
+- **Out of model:** the operator; anyone with `config.yaml` / store / managed-node credentials; a
+ malicious peer controller or a tampered/Byzantine metadata store (the store and peers are trusted as
+ honest — *(maintainer — git-hulk)*); and an unauthenticated network client reaching `:9379`, since
+ exposing an unauthenticated API in a trusted environment is by-design (§9).
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane required to run in a trusted environment.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election / split-brain safety — store-dependent.** HA controllers coordinate via the store;
+ split-brain resolution **depends on the store engine** and is **majority-win** when using Raft / ETCD /
+ ZooKeeper *(maintainer — git-hulk)*. *Symptom:* two controllers issuing conflicting cluster ops under a
+ non-majority store. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — NOT PROVIDED (by design).** The API/UI have **no built-in
+ authentication or authorization** *(maintainer — git-hulk)*; the controller claims **no** access-control
+ property and relies entirely on §10 network controls and a trusted-environment deployment. Auth/authz is
+ planned in [#390](https://github.com/apache/kvrocks-controller/issues/390).
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication or authorization** *(maintainer — git-hulk)* — exposing
+ `:9379` (or the UI) yields an unauthenticated administrative control plane; this is **expected behaviour**
+ in the required trusted-environment deployment, with auth/authz **planned in #390**.
+- **No transport encryption** for the API/UI *(maintainer — git-hulk)* — operators front the controller
+ with a TLS proxy (e.g. Nginx); store TLS is off unless configured.
+- **No web-UI authentication or CSRF protection** *(maintainer — git-hulk)*.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store, its peers and its managed nodes as honest** *(maintainer —
+ git-hulk)* — it is not a defence against a tampered store, a Byzantine peer, or a hostile node; the
+ trusted-environment requirement covers this.
+- **No SSRF allow-listing of registered node addresses** — any address is accepted, but the controller
+ **validates that it is a real Kvrocks node**, which the PMC considers sufficient *(maintainer —
+ git-hulk)*.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but it has **no authentication and no CSRF**
+ protection* *(maintainer — git-hulk)* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator / the trusted-environment requirement:** unauthenticated
+admin-API exposure; CSRF/XSS on the web UI; plaintext control traffic; an unsecured ETCD that anyone can
+rewrite. These are accepted given the trusted-environment deployment model.
+
+## §10 Downstream (operator) responsibilities
+
+- **Deploy the controller, store, peers and managed nodes in a trusted environment** — the supported
+ posture, since there is no built-in API/UI auth *(maintainer — git-hulk)*.
+- **Do not expose the API/UI to an untrusted network**; front it with an authenticating reverse proxy /
+ network ACL and a TLS proxy (e.g. Nginx) for transport encryption *(maintainer — git-hulk)*.
+- Enable TLS for the store connection (`etcd.tls`) and for managed-node connections on untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes (these are
+ **expected to be stored inside the metadata store** *(maintainer — git-hulk)*).
+
+## §11 Known misuse patterns
+
+- Deploying the controller outside a trusted environment / exposing its API or UI to an untrusted network
+ (there is no built-in auth) *(maintainer — git-hulk)*.
+- Binding the controller API to `0.0.0.0` on a shared network without a fronting auth + TLS proxy.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it has no auth or CSRF protection.
+
+## §11a Known non-findings (recurring false positives)
+
+*(Seed list; the PMC reports **no scanner/researcher findings yet** *(maintainer — git-hulk)*, so this
+list is provisional — §14 Q8.)*
+
+- **"Unauthenticated admin API / no login on the UI / no CSRF"** against any config — **by design**; the
+ controller deliberately ships no auth and is deployed in a trusted environment; auth/authz is planned in
+ #390 *(maintainer — git-hulk)*. Disposition `BY-DESIGN`.
+- **"Controller connects to arbitrary node addresses (SSRF)"** — addresses are accepted but Kvrocks-node
+ validated; the PMC considers this sufficient and not in need of hardening *(maintainer — git-hulk)*.
+- **"Tampered ETCD / Byzantine peer redirects the controller"** — store and peers are trusted as honest in
+ the required trusted environment *(maintainer — git-hulk)*. Disposition `OUT-OF-MODEL`.
+- **"No transport encryption on the API"** — by design; operators front with a TLS proxy *(maintainer —
+ git-hulk)*.
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Landing of built-in API/UI authentication/authorization (tracked in #390) — would add §8 properties and
+ shrink §9/§10, and remove the trusted-environment requirement from several rows.
+- A change to the default `addr` / TLS posture, or built-in TLS support.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening. | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability, or an untrusted-network client (trusted-environment deployment assumed). | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS, no web-UI CSRF, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+*Wave-1 and most of wave-2/3 were answered by git-hulk on PR #397 (folded above as *(maintainer)*); they are
+retained here for traceability with their resolutions. Genuinely open items remain tagged *(inferred)*.*
+
+**Wave 1 — auth, TLS (§2/§5a/§8/§9):**
+1. **[ANSWERED — git-hulk]** Built-in API authentication/authorization? **No** — none today; an
+ unauthenticated API is expected behaviour; auth/authz is planned in
+ [#390](https://github.com/apache/kvrocks-controller/issues/390). Supported posture is a
+ trusted-environment deployment.
+2. **[ANSWERED — git-hulk]** Web-UI authentication / CSRF? **None of them** — no auth, no CSRF.
+3. **[ANSWERED — git-hulk]** TLS for the API / managed-node connections? **Not built-in** — operators use a
+ TLS proxy such as Nginx.
+
+**Wave 2 — store, nodes, SSRF (§4/§6/§9):**
+4. **[ANSWERED — git-hulk]** How are managed-node admin credentials stored? **Expected to be stored inside
+ the (metadata) store.** *(Open *(inferred)* sub-item: what protects them at rest within the store is the
+ store layer's responsibility — confirm if any controller-side protection is intended.)*
+5. **[ANSWERED — git-hulk]** Are node addresses validated/allow-listed? **All addresses are allowed, but the
+ controller validates that the target is a Kvrocks node**; no further hardening considered necessary.
+6. **[ANSWERED — git-hulk]** Trust the metadata store and peers as honest? **Yes** — required to be deployed
+ inside a trusted environment.
+
+**Wave 3 — properties & §11a (§8/§11a):**
+7. **[ANSWERED — git-hulk]** Failover-correctness / split-brain guarantees? **Depends on the store engine** —
+ majority-win with Raft / ETCD / ZooKeeper.
+8. **[ANSWERED — git-hulk]** Most common scanner/researcher non-findings? **No report yet** — §11a stays a
+ provisional seed *(inferred)* until real reports arrive.
+9. **[ANSWERED — git-hulk]** Confirm this model lives as root `THREAT_MODEL.md` referenced from a new
+ `SECURITY.md`, separate from the `apache/kvrocks` model? **Yes.**
+
+**Still open *(inferred)* — for the PMC:**
+10. *(inferred)* Confirm the operator/deployer is the only out-of-scope adversary class, and that no
+ in-process privilege boundary is claimed between API roles (none exist today).
+11. *(inferred)* Memory/handler safety on malformed API/UI input (§8.3): is a panic/crash from crafted
+ input considered `VALID`, given callers are nominally trusted?
Review Comment:
Folded — §14 Q11 + §8.3 now state a crash from crafted input is `VALID`. Thanks!
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,321 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, maintainer-reviewed (git-hulk), pending PMC sign-off.** Produced by the ASF
+ Security team via the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / ~10 maintainer / ~14 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA. The
+controller is **required to be deployed inside a trusted environment** *(maintainer — git-hulk)*.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **There is no built-in
+ authentication or authorization** *(maintainer — git-hulk)*, so this role is *unauthenticated* and
+ gated only by `addr` / network reachability. Exposing an unauthenticated API is **expected behaviour**
+ today; authentication/authorization is **planned** (tracking issue
+ [apache/kvrocks-controller#390](https://github.com/apache/kvrocks-controller/issues/390)) *(maintainer
+ — git-hulk)*.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it,
+ and is expected to *(maintainer — git-hulk; trusted environment)*.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to;
+ trusted as honest *(maintainer — git-hulk)*.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store;
+ trusted as honest *(maintainer — git-hulk)*.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** — the controller does **not** provide built-in TLS; operators front it
+ with a TLS proxy such as Nginx *(maintainer — git-hulk)*.
+- **A tampered metadata store or a Byzantine peer controller** — the store and peer nodes are trusted as
+ honest because the deployment is required to be in a trusted environment *(maintainer — git-hulk)*.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With **no built-in auth** *(maintainer — git-hulk)*, the boundary is
+effectively the network ACL around `:9379`, and the deployment is required to sit in a trusted
+environment.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership, and is expected to — the store is trusted as honest *(maintainer — git-hulk)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured (expected to be **stored inside the metadata store**) *(maintainer — git-hulk)*. Node
+ addresses supplied via the API are accepted but **validated to be a real Kvrocks node**; no further
+ SSRF hardening is considered necessary *(maintainer — git-hulk)* (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model only when it breaks a §8 property; "the API is
+ unauthenticated" is by-design (§9), since the deployment is a trusted environment.
+- A finding in **store handling** is in-model if reachable from API input; the store contents themselves
+ are trusted (§7).
+- A finding in the **node client** (e.g. credential mishandling) is in-model if a connection parameter is
+ attacker-influenceable via the API; arbitrary node addresses are accepted but Kvrocks-validated
+ *(maintainer — git-hulk)*.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Deployment:** the controller, its store, its peers and its managed nodes are deployed together in a
+ **trusted environment** *(maintainer — git-hulk)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*; trusted
+ as honest *(maintainer — git-hulk)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them, and the nodes are trusted as honest *(maintainer — git-hulk)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes; there is no
+ built-in API auth or TLS, so network controls (and an optional TLS proxy) are the boundary *(maintainer
+ — git-hulk)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it on an untrusted network is operator misuse (§11) |
+| API authentication | **none** *(maintainer — git-hulk)* | Control plane is unauthenticated by design | By-design today; auth/authz planned in #390. Trusted-environment deployment is the supported posture |
+| API/UI TLS | **none built-in** *(maintainer — git-hulk)* | Plaintext control-plane traffic | By-design; operators front with a TLS proxy (e.g. Nginx) |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | only if API reachable; no built-in auth *(maintainer)* | deploy in a trusted environment; network ACL / TLS proxy |
+| API: add node | **node address/host:port** | accepted, but Kvrocks-validated *(maintainer)* | trusted-environment deployment; restrict network access |
+| Web UI | form/query fields | only if reachable; no auth/CSRF *(maintainer)* | front with auth proxy; trusted-environment deployment |
+| metadata store reads | topology/leadership records | from a **trusted** store *(maintainer)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(maintainer)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** because the controller is required to be deployed in a **trusted environment**
+ with no built-in auth *(maintainer — git-hulk)*, the modelled adversary is **not** an arbitrary network
+ client but an actor who can subvert a §8 safety property of the control plane (e.g. crafted API input
+ that crashes or corrupts the controller despite trusted callers).
+- **Goals against a §8 property:** crash/corrupt the controller via malformed input; induce incorrect
+ failover or split-brain through a §8 logic flaw (not through a tampered store).
+- **Out of model:** the operator; anyone with `config.yaml` / store / managed-node credentials; a
+ malicious peer controller or a tampered/Byzantine metadata store (the store and peers are trusted as
+ honest — *(maintainer — git-hulk)*); and an unauthenticated network client reaching `:9379`, since
+ exposing an unauthenticated API in a trusted environment is by-design (§9).
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane required to run in a trusted environment.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election / split-brain safety — store-dependent.** HA controllers coordinate via the store;
+ split-brain resolution **depends on the store engine** and is **majority-win** when using Raft / ETCD /
+ ZooKeeper *(maintainer — git-hulk)*. *Symptom:* two controllers issuing conflicting cluster ops under a
+ non-majority store. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — NOT PROVIDED (by design).** The API/UI have **no built-in
+ authentication or authorization** *(maintainer — git-hulk)*; the controller claims **no** access-control
+ property and relies entirely on §10 network controls and a trusted-environment deployment. Auth/authz is
+ planned in [#390](https://github.com/apache/kvrocks-controller/issues/390).
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication or authorization** *(maintainer — git-hulk)* — exposing
+ `:9379` (or the UI) yields an unauthenticated administrative control plane; this is **expected behaviour**
+ in the required trusted-environment deployment, with auth/authz **planned in #390**.
+- **No transport encryption** for the API/UI *(maintainer — git-hulk)* — operators front the controller
+ with a TLS proxy (e.g. Nginx); store TLS is off unless configured.
+- **No web-UI authentication or CSRF protection** *(maintainer — git-hulk)*.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store, its peers and its managed nodes as honest** *(maintainer —
+ git-hulk)* — it is not a defence against a tampered store, a Byzantine peer, or a hostile node; the
+ trusted-environment requirement covers this.
+- **No SSRF allow-listing of registered node addresses** — any address is accepted, but the controller
+ **validates that it is a real Kvrocks node**, which the PMC considers sufficient *(maintainer —
+ git-hulk)*.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but it has **no authentication and no CSRF**
+ protection* *(maintainer — git-hulk)* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator / the trusted-environment requirement:** unauthenticated
+admin-API exposure; CSRF/XSS on the web UI; plaintext control traffic; an unsecured ETCD that anyone can
+rewrite. These are accepted given the trusted-environment deployment model.
+
+## §10 Downstream (operator) responsibilities
+
+- **Deploy the controller, store, peers and managed nodes in a trusted environment** — the supported
+ posture, since there is no built-in API/UI auth *(maintainer — git-hulk)*.
+- **Do not expose the API/UI to an untrusted network**; front it with an authenticating reverse proxy /
+ network ACL and a TLS proxy (e.g. Nginx) for transport encryption *(maintainer — git-hulk)*.
+- Enable TLS for the store connection (`etcd.tls`) and for managed-node connections on untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes (these are
+ **expected to be stored inside the metadata store** *(maintainer — git-hulk)*).
+
+## §11 Known misuse patterns
+
+- Deploying the controller outside a trusted environment / exposing its API or UI to an untrusted network
+ (there is no built-in auth) *(maintainer — git-hulk)*.
+- Binding the controller API to `0.0.0.0` on a shared network without a fronting auth + TLS proxy.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it has no auth or CSRF protection.
+
+## §11a Known non-findings (recurring false positives)
+
+*(Seed list; the PMC reports **no scanner/researcher findings yet** *(maintainer — git-hulk)*, so this
+list is provisional — §14 Q8.)*
+
+- **"Unauthenticated admin API / no login on the UI / no CSRF"** against any config — **by design**; the
+ controller deliberately ships no auth and is deployed in a trusted environment; auth/authz is planned in
+ #390 *(maintainer — git-hulk)*. Disposition `BY-DESIGN`.
+- **"Controller connects to arbitrary node addresses (SSRF)"** — addresses are accepted but Kvrocks-node
+ validated; the PMC considers this sufficient and not in need of hardening *(maintainer — git-hulk)*.
+- **"Tampered ETCD / Byzantine peer redirects the controller"** — store and peers are trusted as honest in
+ the required trusted environment *(maintainer — git-hulk)*. Disposition `OUT-OF-MODEL`.
+- **"No transport encryption on the API"** — by design; operators front with a TLS proxy *(maintainer —
+ git-hulk)*.
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Landing of built-in API/UI authentication/authorization (tracked in #390) — would add §8 properties and
+ shrink §9/§10, and remove the trusted-environment requirement from several rows.
+- A change to the default `addr` / TLS posture, or built-in TLS support.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening. | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability, or an untrusted-network client (trusted-environment deployment assumed). | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS, no web-UI CSRF, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+*Wave-1 and most of wave-2/3 were answered by git-hulk on PR #397 (folded above as *(maintainer)*); they are
+retained here for traceability with their resolutions. Genuinely open items remain tagged *(inferred)*.*
+
+**Wave 1 — auth, TLS (§2/§5a/§8/§9):**
+1. **[ANSWERED — git-hulk]** Built-in API authentication/authorization? **No** — none today; an
+ unauthenticated API is expected behaviour; auth/authz is planned in
+ [#390](https://github.com/apache/kvrocks-controller/issues/390). Supported posture is a
+ trusted-environment deployment.
+2. **[ANSWERED — git-hulk]** Web-UI authentication / CSRF? **None of them** — no auth, no CSRF.
+3. **[ANSWERED — git-hulk]** TLS for the API / managed-node connections? **Not built-in** — operators use a
+ TLS proxy such as Nginx.
+
+**Wave 2 — store, nodes, SSRF (§4/§6/§9):**
+4. **[ANSWERED — git-hulk]** How are managed-node admin credentials stored? **Expected to be stored inside
+ the (metadata) store.** *(Open *(inferred)* sub-item: what protects them at rest within the store is the
+ store layer's responsibility — confirm if any controller-side protection is intended.)*
+5. **[ANSWERED — git-hulk]** Are node addresses validated/allow-listed? **All addresses are allowed, but the
+ controller validates that the target is a Kvrocks node**; no further hardening considered necessary.
+6. **[ANSWERED — git-hulk]** Trust the metadata store and peers as honest? **Yes** — required to be deployed
+ inside a trusted environment.
+
+**Wave 3 — properties & §11a (§8/§11a):**
+7. **[ANSWERED — git-hulk]** Failover-correctness / split-brain guarantees? **Depends on the store engine** —
+ majority-win with Raft / ETCD / ZooKeeper.
+8. **[ANSWERED — git-hulk]** Most common scanner/researcher non-findings? **No report yet** — §11a stays a
+ provisional seed *(inferred)* until real reports arrive.
+9. **[ANSWERED — git-hulk]** Confirm this model lives as root `THREAT_MODEL.md` referenced from a new
+ `SECURITY.md`, separate from the `apache/kvrocks` model? **Yes.**
+
+**Still open *(inferred)* — for the PMC:**
+10. *(inferred)* Confirm the operator/deployer is the only out-of-scope adversary class, and that no
+ in-process privilege boundary is claimed between API roles (none exist today).
+11. *(inferred)* Memory/handler safety on malformed API/UI input (§8.3): is a panic/crash from crafted
+ input considered `VALID`, given callers are nominally trusted?
+12. *(inferred)* Wave-2 host/network behaviour (§5): confirm the controller never executes arbitrary host
+ commands and only binds the API port + connects out to the store and nodes.
Review Comment:
Folded — §14 Q12 records the controller does not execute arbitrary host commands. Thanks!
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,321 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, maintainer-reviewed (git-hulk), pending PMC sign-off.** Produced by the ASF
+ Security team via the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / ~10 maintainer / ~14 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA. The
+controller is **required to be deployed inside a trusted environment** *(maintainer — git-hulk)*.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **There is no built-in
+ authentication or authorization** *(maintainer — git-hulk)*, so this role is *unauthenticated* and
+ gated only by `addr` / network reachability. Exposing an unauthenticated API is **expected behaviour**
+ today; authentication/authorization is **planned** (tracking issue
+ [apache/kvrocks-controller#390](https://github.com/apache/kvrocks-controller/issues/390)) *(maintainer
+ — git-hulk)*.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it,
+ and is expected to *(maintainer — git-hulk; trusted environment)*.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to;
+ trusted as honest *(maintainer — git-hulk)*.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store;
+ trusted as honest *(maintainer — git-hulk)*.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** — the controller does **not** provide built-in TLS; operators front it
+ with a TLS proxy such as Nginx *(maintainer — git-hulk)*.
+- **A tampered metadata store or a Byzantine peer controller** — the store and peer nodes are trusted as
+ honest because the deployment is required to be in a trusted environment *(maintainer — git-hulk)*.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With **no built-in auth** *(maintainer — git-hulk)*, the boundary is
+effectively the network ACL around `:9379`, and the deployment is required to sit in a trusted
+environment.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership, and is expected to — the store is trusted as honest *(maintainer — git-hulk)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured (expected to be **stored inside the metadata store**) *(maintainer — git-hulk)*. Node
+ addresses supplied via the API are accepted but **validated to be a real Kvrocks node**; no further
+ SSRF hardening is considered necessary *(maintainer — git-hulk)* (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model only when it breaks a §8 property; "the API is
+ unauthenticated" is by-design (§9), since the deployment is a trusted environment.
+- A finding in **store handling** is in-model if reachable from API input; the store contents themselves
+ are trusted (§7).
+- A finding in the **node client** (e.g. credential mishandling) is in-model if a connection parameter is
+ attacker-influenceable via the API; arbitrary node addresses are accepted but Kvrocks-validated
+ *(maintainer — git-hulk)*.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Deployment:** the controller, its store, its peers and its managed nodes are deployed together in a
+ **trusted environment** *(maintainer — git-hulk)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*; trusted
+ as honest *(maintainer — git-hulk)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them, and the nodes are trusted as honest *(maintainer — git-hulk)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes; there is no
+ built-in API auth or TLS, so network controls (and an optional TLS proxy) are the boundary *(maintainer
+ — git-hulk)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it on an untrusted network is operator misuse (§11) |
+| API authentication | **none** *(maintainer — git-hulk)* | Control plane is unauthenticated by design | By-design today; auth/authz planned in #390. Trusted-environment deployment is the supported posture |
+| API/UI TLS | **none built-in** *(maintainer — git-hulk)* | Plaintext control-plane traffic | By-design; operators front with a TLS proxy (e.g. Nginx) |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | only if API reachable; no built-in auth *(maintainer)* | deploy in a trusted environment; network ACL / TLS proxy |
+| API: add node | **node address/host:port** | accepted, but Kvrocks-validated *(maintainer)* | trusted-environment deployment; restrict network access |
+| Web UI | form/query fields | only if reachable; no auth/CSRF *(maintainer)* | front with auth proxy; trusted-environment deployment |
+| metadata store reads | topology/leadership records | from a **trusted** store *(maintainer)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(maintainer)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** because the controller is required to be deployed in a **trusted environment**
+ with no built-in auth *(maintainer — git-hulk)*, the modelled adversary is **not** an arbitrary network
+ client but an actor who can subvert a §8 safety property of the control plane (e.g. crafted API input
+ that crashes or corrupts the controller despite trusted callers).
+- **Goals against a §8 property:** crash/corrupt the controller via malformed input; induce incorrect
+ failover or split-brain through a §8 logic flaw (not through a tampered store).
+- **Out of model:** the operator; anyone with `config.yaml` / store / managed-node credentials; a
+ malicious peer controller or a tampered/Byzantine metadata store (the store and peers are trusted as
+ honest — *(maintainer — git-hulk)*); and an unauthenticated network client reaching `:9379`, since
+ exposing an unauthenticated API in a trusted environment is by-design (§9).
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane required to run in a trusted environment.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election / split-brain safety — store-dependent.** HA controllers coordinate via the store;
+ split-brain resolution **depends on the store engine** and is **majority-win** when using Raft / ETCD /
+ ZooKeeper *(maintainer — git-hulk)*. *Symptom:* two controllers issuing conflicting cluster ops under a
+ non-majority store. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — NOT PROVIDED (by design).** The API/UI have **no built-in
+ authentication or authorization** *(maintainer — git-hulk)*; the controller claims **no** access-control
+ property and relies entirely on §10 network controls and a trusted-environment deployment. Auth/authz is
+ planned in [#390](https://github.com/apache/kvrocks-controller/issues/390).
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication or authorization** *(maintainer — git-hulk)* — exposing
+ `:9379` (or the UI) yields an unauthenticated administrative control plane; this is **expected behaviour**
+ in the required trusted-environment deployment, with auth/authz **planned in #390**.
+- **No transport encryption** for the API/UI *(maintainer — git-hulk)* — operators front the controller
+ with a TLS proxy (e.g. Nginx); store TLS is off unless configured.
+- **No web-UI authentication or CSRF protection** *(maintainer — git-hulk)*.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store, its peers and its managed nodes as honest** *(maintainer —
+ git-hulk)* — it is not a defence against a tampered store, a Byzantine peer, or a hostile node; the
+ trusted-environment requirement covers this.
+- **No SSRF allow-listing of registered node addresses** — any address is accepted, but the controller
+ **validates that it is a real Kvrocks node**, which the PMC considers sufficient *(maintainer —
+ git-hulk)*.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but it has **no authentication and no CSRF**
+ protection* *(maintainer — git-hulk)* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator / the trusted-environment requirement:** unauthenticated
+admin-API exposure; CSRF/XSS on the web UI; plaintext control traffic; an unsecured ETCD that anyone can
+rewrite. These are accepted given the trusted-environment deployment model.
+
+## §10 Downstream (operator) responsibilities
+
+- **Deploy the controller, store, peers and managed nodes in a trusted environment** — the supported
+ posture, since there is no built-in API/UI auth *(maintainer — git-hulk)*.
+- **Do not expose the API/UI to an untrusted network**; front it with an authenticating reverse proxy /
+ network ACL and a TLS proxy (e.g. Nginx) for transport encryption *(maintainer — git-hulk)*.
+- Enable TLS for the store connection (`etcd.tls`) and for managed-node connections on untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes (these are
+ **expected to be stored inside the metadata store** *(maintainer — git-hulk)*).
+
+## §11 Known misuse patterns
+
+- Deploying the controller outside a trusted environment / exposing its API or UI to an untrusted network
+ (there is no built-in auth) *(maintainer — git-hulk)*.
+- Binding the controller API to `0.0.0.0` on a shared network without a fronting auth + TLS proxy.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it has no auth or CSRF protection.
+
+## §11a Known non-findings (recurring false positives)
+
+*(Seed list; the PMC reports **no scanner/researcher findings yet** *(maintainer — git-hulk)*, so this
+list is provisional — §14 Q8.)*
+
+- **"Unauthenticated admin API / no login on the UI / no CSRF"** against any config — **by design**; the
+ controller deliberately ships no auth and is deployed in a trusted environment; auth/authz is planned in
+ #390 *(maintainer — git-hulk)*. Disposition `BY-DESIGN`.
+- **"Controller connects to arbitrary node addresses (SSRF)"** — addresses are accepted but Kvrocks-node
+ validated; the PMC considers this sufficient and not in need of hardening *(maintainer — git-hulk)*.
+- **"Tampered ETCD / Byzantine peer redirects the controller"** — store and peers are trusted as honest in
+ the required trusted environment *(maintainer — git-hulk)*. Disposition `OUT-OF-MODEL`.
+- **"No transport encryption on the API"** — by design; operators front with a TLS proxy *(maintainer —
+ git-hulk)*.
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Landing of built-in API/UI authentication/authorization (tracked in #390) — would add §8 properties and
+ shrink §9/§10, and remove the trusted-environment requirement from several rows.
+- A change to the default `addr` / TLS posture, or built-in TLS support.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening. | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability, or an untrusted-network client (trusted-environment deployment assumed). | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS, no web-UI CSRF, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+*Wave-1 and most of wave-2/3 were answered by git-hulk on PR #397 (folded above as *(maintainer)*); they are
+retained here for traceability with their resolutions. Genuinely open items remain tagged *(inferred)*.*
+
+**Wave 1 — auth, TLS (§2/§5a/§8/§9):**
+1. **[ANSWERED — git-hulk]** Built-in API authentication/authorization? **No** — none today; an
+ unauthenticated API is expected behaviour; auth/authz is planned in
+ [#390](https://github.com/apache/kvrocks-controller/issues/390). Supported posture is a
+ trusted-environment deployment.
+2. **[ANSWERED — git-hulk]** Web-UI authentication / CSRF? **None of them** — no auth, no CSRF.
+3. **[ANSWERED — git-hulk]** TLS for the API / managed-node connections? **Not built-in** — operators use a
+ TLS proxy such as Nginx.
+
+**Wave 2 — store, nodes, SSRF (§4/§6/§9):**
+4. **[ANSWERED — git-hulk]** How are managed-node admin credentials stored? **Expected to be stored inside
+ the (metadata) store.** *(Open *(inferred)* sub-item: what protects them at rest within the store is the
+ store layer's responsibility — confirm if any controller-side protection is intended.)*
+5. **[ANSWERED — git-hulk]** Are node addresses validated/allow-listed? **All addresses are allowed, but the
+ controller validates that the target is a Kvrocks node**; no further hardening considered necessary.
+6. **[ANSWERED — git-hulk]** Trust the metadata store and peers as honest? **Yes** — required to be deployed
+ inside a trusted environment.
+
+**Wave 3 — properties & §11a (§8/§11a):**
+7. **[ANSWERED — git-hulk]** Failover-correctness / split-brain guarantees? **Depends on the store engine** —
+ majority-win with Raft / ETCD / ZooKeeper.
+8. **[ANSWERED — git-hulk]** Most common scanner/researcher non-findings? **No report yet** — §11a stays a
+ provisional seed *(inferred)* until real reports arrive.
+9. **[ANSWERED — git-hulk]** Confirm this model lives as root `THREAT_MODEL.md` referenced from a new
+ `SECURITY.md`, separate from the `apache/kvrocks` model? **Yes.**
+
+**Still open *(inferred)* — for the PMC:**
+10. *(inferred)* Confirm the operator/deployer is the only out-of-scope adversary class, and that no
+ in-process privilege boundary is claimed between API roles (none exist today).
+11. *(inferred)* Memory/handler safety on malformed API/UI input (§8.3): is a panic/crash from crafted
+ input considered `VALID`, given callers are nominally trusted?
+12. *(inferred)* Wave-2 host/network behaviour (§5): confirm the controller never executes arbitrary host
+ commands and only binds the API port + connects out to the store and nodes.
+13. *(inferred)* Within-store protection of node credentials at rest (follow-up to Q4): is any
+ controller-side encryption of stored credentials intended, or is it wholly the store's responsibility?
Review Comment:
Folded — §14 Q13 + the Q4 sub-item record that controller-side credential-at-rest encryption is intended (tracked issue), so plaintext-at-rest is `VALID`. Thanks!
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@kvrocks.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Add draft threat model + SECURITY.md + AGENTS.md for security-model discoverability [kvrocks-controller]
Posted by "git-hulk (via GitHub)" <gi...@apache.org>.
git-hulk commented on PR #397:
URL: https://github.com/apache/kvrocks-controller/pull/397#issuecomment-4627519708
@potiuk Great thanks for your revise and help.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@kvrocks.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Add draft threat model + SECURITY.md + AGENTS.md for security-model discoverability [kvrocks-controller]
Posted by "PragmaTwice (via GitHub)" <gi...@apache.org>.
PragmaTwice merged PR #397:
URL: https://github.com/apache/kvrocks-controller/pull/397
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@kvrocks.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Add draft threat model + SECURITY.md + AGENTS.md for security-model discoverability [kvrocks-controller]
Posted by "potiuk (via GitHub)" <gi...@apache.org>.
potiuk commented on PR #397:
URL: https://github.com/apache/kvrocks-controller/pull/397#issuecomment-4627190197
Thanks @git-hulk — your remaining answers are folded in, and §14 is now fully resolved:
- **Q10** — operator/deployer is the only out-of-scope adversary class; no in-process role privilege boundary (none today).
- **Q11** — a crash/panic from crafted API/UI input **is `VALID`** (folded into §8.3), even though callers are nominally trusted.
- **Q12** — confirmed: the controller does not execute arbitrary host commands (§5).
- **Q13** — controller-side credential-at-rest encryption **is intended** (a gap you'll track via a follow-up issue), so a plaintext-at-rest finding is `VALID`.
Replied on and resolved the threads. The model is the PMC's to merge whenever — thanks for the thorough review.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@kvrocks.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Add draft threat model + SECURITY.md + AGENTS.md for security-model discoverability [kvrocks-controller]
Posted by "PragmaTwice (via GitHub)" <gi...@apache.org>.
PragmaTwice commented on code in PR #397:
URL: https://github.com/apache/kvrocks-controller/pull/397#discussion_r3329672359
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,273 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, not yet reviewed by the Kvrocks PMC.** Produced by the ASF Security team via
+ the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / 0 maintainer / ~40 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **The config exposes no built-in
+ authentication knob**, so by default this role is *unauthenticated* and gated only by `addr` /
+ network reachability *(inferred — `config/config.yaml` has no API-auth section; default `addr` is
+ localhost; `server/middleware` present but role unconfirmed)*. This is the load-bearing §14 wave-1 item.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** beyond the TLS the controller supports.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With no built-in auth (pending §14), the boundary is effectively the
+network ACL around `:9379` *(inferred)*.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership. An actor who can write the store can redirect the controller *(inferred)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured *(inferred)*. Node addresses supplied via the API are an **SSRF / connect-to-arbitrary-host**
+ vector if the caller is untrusted (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model if reachable by a client the deployment treats as untrusted
+ (which, absent built-in auth, is "anyone who can reach the port" — see §14 wave-1).
+- A finding in **store handling** is in-model if reachable from API input or from store contents an
+ attacker could influence.
+- A finding in the **node client** (e.g. SSRF, credential mishandling) is in-model if a node address or
+ connection parameter is attacker-influenceable via the API.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them *(inferred)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes *(inferred)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it without a fronting auth proxy is the risk |
+| API authentication | **none present in config** | Control plane appears unauthenticated | **Open (wave-1):** is there *any* API/UI auth, and is "network-trust only" the supported posture? |
+| API/UI TLS | *(unconfirmed)* | Plaintext control-plane traffic | **Open (wave-1)** |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | **yes** (absent auth, any API client) | front with authn/authz; network ACL |
+| API: add node | **node address/host:port** | **yes** | restrict who may register nodes (SSRF surface) |
+| Web UI | form/query fields | **yes** | output encoding; CSRF protection; auth |
+| metadata store reads | topology/leadership records | from a **trusted** store *(inferred)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(inferred)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** an actor who can reach the controller API or web UI but is not the operator —
+ realistically present whenever the API is exposed beyond a trusted network without a fronting auth layer.
+ Capabilities: call any API endpoint (create/delete clusters, add/remove nodes, **force failover**,
+ migrate slots), register node addresses (SSRF), drive the UI.
+- **Goals:** seize administrative control of managed Kvrocks clusters; cause data movement/loss via slot
+ migration or failover; make the controller connect to attacker-chosen hosts; read/modify topology.
+- **Out of model:** the operator, anyone with `config.yaml` / store / managed-node credentials, and
+ (pending §14) a malicious peer controller or a compromised metadata store.
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane assumed to run on a trusted network; all *(inferred)* pending §14.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election safety (single active controller).** HA controllers coordinate via the store so that
+ conflicting administrative actions are serialized *(inferred)*. *Symptom:* two controllers issuing
+ conflicting cluster ops. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — UNRESOLVED.** Whether the API/UI authenticate callers at all is the
+ central open question (§14 wave-1); absent that, the controller claims **no** access-control property and
+ relies entirely on §10 network controls.
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication by default** *(inferred)* — exposing `:9379` (or the UI) to an
+ untrusted network without a fronting auth proxy yields an **unauthenticated administrative control plane**
+ over every managed cluster.
+- **No transport encryption guarantee by default** for the API/UI; store TLS is off unless configured.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store and its peers** — it is not a defence against a tampered store
+ or a Byzantine peer controller (pending §14).
+- **No SSRF protection on registered node addresses** *(inferred)* — the controller connects to host:port
+ values it is given; an untrusted caller who can add nodes can aim those connections.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but (pending §14) may have no authentication at
+ all* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator:** unauthenticated admin-API exposure; CSRF/XSS on the web
+UI; SSRF via node registration; plaintext control traffic; an unsecured ETCD that anyone can rewrite.
+
+## §10 Downstream (operator) responsibilities
+
+- **Do not expose the API/UI to an untrusted network without an authenticating reverse proxy / network ACL**
+ (until/unless built-in auth is confirmed).
+- Enable TLS for the API/UI, for the store connection (`etcd.tls`), and for managed-node connections on
+ untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes.
+- Restrict who may register node addresses (SSRF surface).
+
+## §11 Known misuse patterns
+
+- Binding the controller API to `0.0.0.0` on a shared network without fronting authentication.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it is not.
+
+## §11a Known non-findings (recurring false positives)
+
+*(v0 seed — PMC's real list is the key §14 input.)*
+
+- **"Unauthenticated admin API / no login on the UI"** against the default config — by design *if* the PMC
+ rules network-trust the supported posture (else it is `VALID`); resolved in §14 wave-1.
+- **"ETCD has no auth/TLS"** — operator-configured store, defaults documented (§3/§10).
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Introduction (or confirmation) of built-in API/UI authentication/authorization — would add §8 properties
+ and shrink §9/§10.
+- A change to the default `addr` / TLS posture.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening (e.g. add CSRF tokens, SSRF allow-list). | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability. | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS default, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+**Wave 1 — the central auth question (§2/§5a/§8/§9):**
+1. Does the controller API have **any built-in authentication/authorization** (token, mTLS, basic-auth), or
+ is it **network-trust only**? If the latter, is exposing it behind an operator's own auth proxy the
+ *supported* posture, so an "unauthenticated API" report is `BY-DESIGN`? *Proposed:* network-trust only
+ today; operator fronts it; unauth-on-trusted-network is by design, unauth-on-untrusted-network is misuse.
+2. Does the **web UI** authenticate, and does it have **CSRF** protection on state-changing calls?
+ *Proposed:* same as the API; CSRF is a hardening item.
+3. Is **TLS** supported/expected for the API and managed-node connections? *Proposed:* operator-configurable;
+ plaintext acceptable only on trusted networks.
+
+**Wave 2 — store, nodes, SSRF (§4/§6/§9):**
+4. How are **managed-node admin credentials** stored and used (in the store? in config?), and what protects
+ them at rest? *Proposed:* operator-supplied; stored in the metadata store; protected at the store layer.
+5. Are **node addresses** registered via the API validated/allow-listed, or will the controller connect to
+ any host:port given (SSRF)? *Proposed:* currently connects as given; allow-listing is a hardening item.
+6. Does the controller **trust the metadata store and peer controllers** as honest (out of §7), or should a
+ tampered store / Byzantine peer be modelled? *Proposed:* trusted; out of scope.
+
+**Wave 3 — properties & §11a (§8/§11a):**
+7. What **failover-correctness / split-brain** guarantees does the controller make, and under what store/peer
+ assumptions? *Proposed:* correct given a healthy store and a quorum of honest peers.
+8. What do scanners/researchers most often report here that the PMC considers a **non-finding**? (Seeds §11a.)
+
+**Meta:**
+9. Confirm this model lives as root `THREAT_MODEL.md` referenced from a new `SECURITY.md`, separate from the
+ `apache/kvrocks` model. *Proposed:* yes.
Review Comment:
cc @git-hulk Could you confirm and answer these questions when you have time?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@kvrocks.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Add draft threat model + SECURITY.md + AGENTS.md for security-model discoverability [kvrocks-controller]
Posted by "git-hulk (via GitHub)" <gi...@apache.org>.
git-hulk commented on code in PR #397:
URL: https://github.com/apache/kvrocks-controller/pull/397#discussion_r3334344926
##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,273 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Threat Model — Apache Kvrocks Controller
+
+## §1 Header
+
+- **Project:** Apache Kvrocks Controller — a Go cluster-management control plane for Apache Kvrocks.
+ It probes managed Kvrocks nodes and performs **failover**, scales clusters out/in, manages many
+ clusters from one (itself-clustered) controller, and stores cluster metadata in a pluggable backend
+ (ETCD by default; ZooKeeper / Consul / Raft optional) *(documented — README, `config/config.yaml`)*.
+- **Modelled against:** `apache/kvrocks-controller` `unstable`/HEAD (2026-05-31).
+- **Status:** **DRAFT — v0, not yet reviewed by the Kvrocks PMC.** Produced by the ASF Security team via
+ the `threat-model-producer` rubric
+ (<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>). Companion to the
+ `apache/kvrocks` model; this one covers the **control plane**, whose trust surface differs.
+- **Version binding:** versioned with the project.
+- **Reporting cross-reference:** §8-property violations → report privately per `SECURITY.md` /
+ <https://www.apache.org/security/>; §3 / §9 findings closed citing this document.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* as in the sibling model; each
+ *(inferred)* routes to a §14 question.
+- **Draft confidence:** ~12 documented / 0 maintainer / ~40 inferred.
+
+The controller exposes an **HTTP API** (default `addr: 127.0.0.1:9379`) and a bundled **web UI**, through
+which operators create clusters, add/remove nodes, migrate slots, and trigger or automate failover
+*(documented — README, config)*. It is, in effect, the **administrative authority** over every Kvrocks
+cluster it manages: whoever controls the controller controls those clusters' topology and data placement.
+
+## §2 Scope and intended use
+
+Primary intended use *(documented)*: an operations control plane that a cluster administrator runs to
+manage one or more Kvrocks clusters, backed by a consensus/metadata store for its own state and HA.
+
+Caller roles:
+
+- **API / UI client** — whoever can reach `:9379` or the web UI. **The config exposes no built-in
+ authentication knob**, so by default this role is *unauthenticated* and gated only by `addr` /
+ network reachability *(inferred — `config/config.yaml` has no API-auth section; default `addr` is
+ localhost; `server/middleware` present but role unconfirmed)*. This is the load-bearing §14 wave-1 item.
+- **Metadata store (ETCD/…)** — trusted source of truth for cluster topology; the controller believes it.
+- **Managed Kvrocks node** — a data node the controller connects to and issues admin/cluster commands to.
+- **Peer controller** — another controller instance in the same HA group, coordinating via the store.
+- **Operator / deployer** — controls `config.yaml`, the store, TLS material, network exposure, and the
+ managed-node credentials. Fully trusted; **out of model** as adversary (§3).
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| HTTP control-plane API | `:9379`, `server/` | network; store; managed nodes | **Yes** |
+| Web UI / dashboard | `webui/` | browser; the API | **Yes** |
+| Metadata store engine | `store/engine` (etcd/zk/consul/raft) | network (the store) | **Yes** |
+| Controller → Kvrocks-node client | probing, cluster ops, failover | network (managed nodes) | **Yes** |
+| Controller HA / leader election | via the store | network | **Yes** |
+| Build / tooling | `cmd`, `scripts`, `x.py`, `Makefile` | — | No → §3 |
+
+## §3 Out of scope (explicit non-goals)
+
+- **The operator / deployer as adversary** — controls `config.yaml`, the metadata store, and the
+ deployment (§9) *(inferred)*.
+- **Hardening of the metadata store itself** (ETCD/ZK/Consul auth, ACLs, TLS) — the controller consumes
+ it; securing it is the operator's job, though the controller must use the credentials/TLS the operator
+ supplies *(documented — etcd `username`/`password`/`tls` fields exist, default empty/off)*.
+- **The managed Kvrocks nodes' own threat model** — covered by the `apache/kvrocks` model; this document
+ covers the controller's *use* of them.
+- **Network/transport hardening** beyond the TLS the controller supports.
+- **Build tooling and tests.**
+
+## §4 Trust boundaries and data flow
+
+The primary trust boundary is the **HTTP API / web-UI surface**. A request that reaches it can read or
+mutate cluster topology — create/delete clusters, add/remove nodes, migrate slots, force failover
+*(documented — feature list)*. With no built-in auth (pending §14), the boundary is effectively the
+network ACL around `:9379` *(inferred)*.
+
+Secondary boundaries:
+
+- **Controller ↔ metadata store:** the controller trusts store contents as ground truth for topology and
+ leadership. An actor who can write the store can redirect the controller *(inferred)*.
+- **Controller → managed node:** the controller connects out to node addresses taken from its
+ metadata/API input and issues admin/cluster commands, holding whatever node credentials the operator
+ configured *(inferred)*. Node addresses supplied via the API are an **SSRF / connect-to-arbitrary-host**
+ vector if the caller is untrusted (§9).
+
+**Reachability preconditions:**
+
+- A finding in the **API/UI** path is in-model if reachable by a client the deployment treats as untrusted
+ (which, absent built-in auth, is "anyone who can reach the port" — see §14 wave-1).
+- A finding in **store handling** is in-model if reachable from API input or from store contents an
+ attacker could influence.
+- A finding in the **node client** (e.g. SSRF, credential mishandling) is in-model if a node address or
+ connection parameter is attacker-influenceable via the API.
+- A finding reachable only from `config.yaml` or operator-held credentials is out of model (§3).
+
+## §5 Assumptions about the environment
+
+- **Runtime:** a Go binary on a POSIX host; default API bind `127.0.0.1:9379` *(documented)*.
+- **Metadata store:** an operator-run ETCD (default) or alternative, reachable at the configured addr,
+ with operator-chosen auth/TLS (defaults: no auth, `tls.enable: false`) *(documented — config)*.
+- **Managed nodes:** reachable Kvrocks instances the operator has provisioned; the controller is assumed
+ to be authorized to administer them *(inferred)*.
+- **Network:** the operator controls who can reach the API, the store, and the nodes *(inferred)*.
+- **What the controller does to its host/network (*(inferred)* — wave-2):** binds the API port; connects
+ out to the store and to managed nodes; reads `config.yaml`; may write logs/metrics. Not assumed to
+ execute arbitrary host commands.
+
+## §5a Build-time and configuration variants
+
+| Knob | Default *(documented — config)* | Effect | Insecure-default ruling |
+| --- | --- | --- | --- |
+| API `addr` | `127.0.0.1:9379` | Localhost-only by default | Safe default; exposing it without a fronting auth proxy is the risk |
+| API authentication | **none present in config** | Control plane appears unauthenticated | **Open (wave-1):** is there *any* API/UI auth, and is "network-trust only" the supported posture? |
+| API/UI TLS | *(unconfirmed)* | Plaintext control-plane traffic | **Open (wave-1)** |
+| `storage_type` | `etcd` | Choice of metadata backend (etcd/zk/consul/raft; raft = experimental, "not recommended for production") | raft-in-prod is an operator misuse (§11) |
+| etcd `username`/`password`/`tls.enable` | empty / `false` | Store auth + encryption off unless set | Operator responsibility (§10) |
+
+## §6 Assumptions about inputs
+
+| Entry point | Parameter | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| API: create/scale/failover/migrate | cluster/node/slot args | **yes** (absent auth, any API client) | front with authn/authz; network ACL |
+| API: add node | **node address/host:port** | **yes** | restrict who may register nodes (SSRF surface) |
+| Web UI | form/query fields | **yes** | output encoding; CSRF protection; auth |
+| metadata store reads | topology/leadership records | from a **trusted** store *(inferred)* | store auth/TLS (operator) |
+| node responses | probe/command replies | from a **trusted** node *(inferred)* | node authenticity (TLS/credentials) |
+| `config.yaml` | all keys | **no — operator-trusted** | never sourced from a request |
+
+## §7 Adversary model
+
+- **Primary adversary:** an actor who can reach the controller API or web UI but is not the operator —
+ realistically present whenever the API is exposed beyond a trusted network without a fronting auth layer.
+ Capabilities: call any API endpoint (create/delete clusters, add/remove nodes, **force failover**,
+ migrate slots), register node addresses (SSRF), drive the UI.
+- **Goals:** seize administrative control of managed Kvrocks clusters; cause data movement/loss via slot
+ migration or failover; make the controller connect to attacker-chosen hosts; read/modify topology.
+- **Out of model:** the operator, anyone with `config.yaml` / store / managed-node credentials, and
+ (pending §14) a malicious peer controller or a compromised metadata store.
+
+## §8 Security properties the project provides
+
+*(Thin by design for a control plane assumed to run on a trusted network; all *(inferred)* pending §14.)*
+
+1. **Failover correctness under trusted operation.** Given a healthy store and honest peers, failover
+ promotes a valid replica rather than corrupting topology *(inferred — core function)*. *Symptom:* split
+ brain / promotion of a stale or wrong node / topology corruption. *Severity:* high (availability/integrity).
+2. **Leader-election safety (single active controller).** HA controllers coordinate via the store so that
+ conflicting administrative actions are serialized *(inferred)*. *Symptom:* two controllers issuing
+ conflicting cluster ops. *Severity:* high.
+3. **Memory/handler safety on API input.** Malformed API/UI requests do not crash or corrupt the controller
+ *(inferred)*. *Symptom:* panic/crash/OOB from crafted input. *Severity:* medium–high.
+4. **Authentication / authorization — UNRESOLVED.** Whether the API/UI authenticate callers at all is the
+ central open question (§14 wave-1); absent that, the controller claims **no** access-control property and
+ relies entirely on §10 network controls.
+
+## §9 Security properties the project does NOT provide
+
+- **No built-in control-plane authentication by default** *(inferred)* — exposing `:9379` (or the UI) to an
+ untrusted network without a fronting auth proxy yields an **unauthenticated administrative control plane**
+ over every managed cluster.
+- **No transport encryption guarantee by default** for the API/UI; store TLS is off unless configured.
+- **No defence against a malicious operator** or anyone holding store/managed-node credentials (§3).
+- **The controller trusts its metadata store and its peers** — it is not a defence against a tampered store
+ or a Byzantine peer controller (pending §14).
+- **No SSRF protection on registered node addresses** *(inferred)* — the controller connects to host:port
+ values it is given; an untrusted caller who can add nodes can aim those connections.
+
+**False friends:**
+
+- *A bundled web UI looks like an admin console with a login, but (pending §14) may have no authentication at
+ all* — its presence does not imply an access-control boundary.
+- *Managing "clusters" implies isolation, but the controller is a single authority across all managed
+ clusters* — compromising it is not contained to one cluster.
+
+**Well-known attack classes left to the operator:** unauthenticated admin-API exposure; CSRF/XSS on the web
+UI; SSRF via node registration; plaintext control traffic; an unsecured ETCD that anyone can rewrite.
+
+## §10 Downstream (operator) responsibilities
+
+- **Do not expose the API/UI to an untrusted network without an authenticating reverse proxy / network ACL**
+ (until/unless built-in auth is confirmed).
+- Enable TLS for the API/UI, for the store connection (`etcd.tls`), and for managed-node connections on
+ untrusted networks.
+- Secure the metadata store (ETCD/ZK/Consul) with its own auth + ACLs; supply those credentials to the
+ controller; do not run the experimental `raft` engine in production.
+- Restrict and protect the credentials the controller uses to administer managed nodes.
+- Restrict who may register node addresses (SSRF surface).
+
+## §11 Known misuse patterns
+
+- Binding the controller API to `0.0.0.0` on a shared network without fronting authentication.
+- Running the experimental `raft` store engine in production (the README warns against it).
+- Pointing the controller at an ETCD with no auth/TLS on a reachable network.
+- Treating the web UI as an authenticated admin console when it is not.
+
+## §11a Known non-findings (recurring false positives)
+
+*(v0 seed — PMC's real list is the key §14 input.)*
+
+- **"Unauthenticated admin API / no login on the UI"** against the default config — by design *if* the PMC
+ rules network-trust the supported posture (else it is `VALID`); resolved in §14 wave-1.
+- **"ETCD has no auth/TLS"** — operator-configured store, defaults documented (§3/§10).
+- **Findings in `cmd/`, `scripts/`, `x.py`, build tooling, tests** — out of scope (§3).
+- **Controller can delete/failover clusters** — that is its purpose; an authorized call is not a finding (§7).
+
+## §12 Conditions that would change this model
+
+- Introduction (or confirmation) of built-in API/UI authentication/authorization — would add §8 properties
+ and shrink §9/§10.
+- A change to the default `addr` / TLS posture.
+- A new API surface or store engine, or promotion of the `raft` engine to supported.
+- Treating peer controllers or the metadata store as untrusted (pulls them into §7).
+- Any report not cleanly routable to a §13 disposition.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via an in-scope adversary/input. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse warrants hardening (e.g. add CSRF tokens, SSRF allow-list). | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of config / store / node credentials. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator / store / peer capability. | §7, §3 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in tooling/tests, or the experimental `raft` engine. | §3, §5a |
+| `OUT-OF-MODEL: non-default-build` | Only under a discouraged/non-default config. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no built-in auth/TLS default, single cross-cluster authority). | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |
+
+## §14 Open questions for the maintainers
+
+**Wave 1 — the central auth question (§2/§5a/§8/§9):**
+1. Does the controller API have **any built-in authentication/authorization** (token, mTLS, basic-auth), or
+ is it **network-trust only**? If the latter, is exposing it behind an operator's own auth proxy the
+ *supported* posture, so an "unauthenticated API" report is `BY-DESIGN`? *Proposed:* network-trust only
+ today; operator fronts it; unauth-on-trusted-network is by design, unauth-on-untrusted-network is misuse.
+2. Does the **web UI** authenticate, and does it have **CSRF** protection on state-changing calls?
+ *Proposed:* same as the API; CSRF is a hardening item.
+3. Is **TLS** supported/expected for the API and managed-node connections? *Proposed:* operator-configurable;
+ plaintext acceptable only on trusted networks.
+
+**Wave 2 — store, nodes, SSRF (§4/§6/§9):**
+4. How are **managed-node admin credentials** stored and used (in the store? in config?), and what protects
+ them at rest? *Proposed:* operator-supplied; stored in the metadata store; protected at the store layer.
+5. Are **node addresses** registered via the API validated/allow-listed, or will the controller connect to
+ any host:port given (SSRF)? *Proposed:* currently connects as given; allow-listing is a hardening item.
+6. Does the controller **trust the metadata store and peer controllers** as honest (out of §7), or should a
+ tampered store / Byzantine peer be modelled? *Proposed:* trusted; out of scope.
+
+**Wave 3 — properties & §11a (§8/§11a):**
+7. What **failover-correctness / split-brain** guarantees does the controller make, and under what store/peer
+ assumptions? *Proposed:* correct given a healthy store and a quorum of honest peers.
+8. What do scanners/researchers most often report here that the PMC considers a **non-finding**? (Seeds §11a.)
+
+**Meta:**
+9. Confirm this model lives as root `THREAT_MODEL.md` referenced from a new `SECURITY.md`, separate from the
+ `apache/kvrocks` model. *Proposed:* yes.
Review Comment:
OK, on it.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@kvrocks.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Add draft threat model + SECURITY.md + AGENTS.md for security-model discoverability [kvrocks-controller]
Posted by "git-hulk (via GitHub)" <gi...@apache.org>.
git-hulk commented on PR #397:
URL: https://github.com/apache/kvrocks-controller/pull/397#issuecomment-4618556645
> Thanks @git-hulk — pushed a revision folding your answers in: no built-in authn/authz today, so the unauthenticated API is expected behavior (with auth tracked in #390); TLS via a fronting proxy (Nginx) rather than built-in; credentials stored in the backing store; node addresses validated as real Kvrocks nodes; the metadata store + peer nodes trusted as honest (trusted-environment requirement); and split-brain handling deferred to the store engine (majority-win with Raft/ETCD/ZK). Residual items kept as §14 questions for the PMC. Ready when you are.
Thanks for your revise and follow-up questions. I have confirmed them, please take a look again when you get time.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@kvrocks.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org