Skip to content

Commit 61e10fa

Browse files
potiukclaude
andcommitted
Add draft project security threat-model document
Adds a draft project-level security threat-model document (draft-THREAT-MODEL.md) at repo root, improving discoverability for automated security scanners running against this repository. The file follows the rubric format used by several other ASF projects piloting security-model discoverability. The "draft-" prefix signals this is a proposal for the PMC to review, correct, or reject — not a finalised maintainer-blessed model. Every claim carries a provenance tag (documented / inferred / maintainer) so reviewers can see where each claim originates; §14 collects open questions for the maintainers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 76df16c commit 61e10fa

1 file changed

Lines changed: 259 additions & 0 deletions

File tree

draft-THREAT-MODEL.md

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
<!--
2+
Licensed to the Apache Software Foundation (ASF) under one
3+
or more contributor license agreements. See the NOTICE file
4+
distributed with this work for additional information
5+
regarding copyright ownership. The ASF licenses this file
6+
to you under the Apache License, Version 2.0 (the
7+
"License"); you may not use this file except in compliance
8+
with the License. You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing,
13+
software distributed under the License is distributed on an
14+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
KIND, either express or implied. See the License for the
16+
specific language governing permissions and limitations
17+
under the License.
18+
-->
19+
20+
# Apache CloudStack CloudMonkey Security Threat Model — delta (draft)
21+
22+
> **Delta document.** Inherits §3, §4 B1, and §7 from
23+
> `cloudstack-threat-model-draft.md`. Read the main model first.
24+
25+
## §1 Header
26+
27+
- **Project:** Apache CloudStack CloudMonkey (`apache/cloudstack-cloudmonkey`)
28+
— interactive shell and CLI for the CloudStack management server.
29+
- **Commit:** `76df16c` (HEAD of `main` at draft time).
30+
- **Date:** 2026-05-29.
31+
- **Authors:** ASF Security team draft.
32+
- **Status:** Draft delta over `cloudstack-threat-model-draft.md`.
33+
- **Version binding:** as of the commit above.
34+
- **Reporting:** as in the main model.
35+
- **Provenance legend:** as in the main model.
36+
- **Draft confidence:** 7 documented / 0 maintainer / 9 inferred.
37+
38+
**About the project.** CloudMonkey is a Go-language interactive shell
39+
and command-line tool that simplifies CloudStack management
40+
*(documented: `README.md`)*. It is the modern rewrite of the legacy
41+
Python `cloudmonkey`. It is compatible with Apache CloudStack 4.9+. Its
42+
moving parts: the `cli/` interactive REPL with autocompletion, the
43+
`cmd/` command dispatch, the `config/` package that owns credential
44+
storage and TLS-verify policy, and a bundled `apis.json` describing the
45+
CloudStack API surface *(documented: `config/apis.json`)*.
46+
47+
## §2 Scope and intended use
48+
49+
**Primary intended use.** Run interactively from an operator's
50+
workstation or non-interactively from a CI / scripting context to drive
51+
the CloudStack JSON API. Used by admins and end users.
52+
53+
**Deployment shape.** A single user-space binary, run on the operator's
54+
machine. No daemon, no listener.
55+
56+
**Caller expectations.** The caller (the operator running `cmk`) is
57+
trusted to:
58+
59+
- supply a `~/.cmk/config` (INI-style) file (or env-equivalent) with
60+
the management-server URL, API key, secret, and `verifycert`
61+
preference,
62+
- not run untrusted CloudMonkey extension scripts.
63+
64+
**Component-family table.**
65+
66+
| Family | Representative entry | Touches outside the process? | In this delta? |
67+
| --- | --- | --- | --- |
68+
| Config loader and signer (`config/config.go`) | `cfg.NewRequest` | **yes — network + creds** | yes |
69+
| REPL / autocompletion (`cli/`) | `cmk` interactive prompt | reads `~/.cmk/` config and history | yes |
70+
| Command dispatch (`cmd/`) | one-shot CLI invocation | as above | yes |
71+
| Bundled `apis.json` | static description of API surface | none | yes |
72+
| `snap/`, `Dockerfile` packaging | builds the binary for distribution | n/a at runtime | **out of model** *(§3)* |
73+
| `vendor/` | vendored Go dependencies | n/a | **out of model** *(§3)* — vendored upstream code is in-model only at the wrapper boundary |
74+
75+
## §3 Out of scope (explicit non-goals)
76+
77+
The main model's §3 applies. **Additional** out-of-scope items
78+
specific to CloudMonkey:
79+
80+
1. **Where the operator stores `~/.cmk/config`.** File permissions on
81+
the config file are the operator's responsibility. *(inferred — Q1)*
82+
2. **Server-side correctness of CloudStack responses.** Same as the
83+
Go SDK delta.
84+
3. **TLS verification when `verifycert = false`.** When the operator
85+
sets `verifycert = false` in the config, the HTTP client uses
86+
`InsecureSkipVerify: true` *(documented: `config/config.go` line
87+
~226)*. That is operator choice.
88+
4. **Operator typing wrong commands.** A wrong destructive command
89+
correctly executed is not a vulnerability.
90+
5. **`vendor/`, `snap/`, `Dockerfile`, `performrelease.sh`.**
91+
6. **The four sibling repos.**
92+
93+
## §4 Trust boundaries and data flow
94+
95+
The boundary is **the operator's invocation of `cmk` and its access to
96+
`~/.cmk/config`**. The config file is operator-supplied credentials
97+
+ endpoint + TLS-verify policy. Per-call API parameters typed at the
98+
REPL are likewise operator input.
99+
100+
Bytes that come back from the management server (JSON responses) are
101+
trusted control-plane content per the main model B1 transition.
102+
103+
**Per-call request shape** *(inferred — Q2)*: CloudMonkey uses the same
104+
HMAC-SHA1 signing flow as the Go SDK (likely via the SDK or a near-copy).
105+
See main model §8 P1 and §11a "SHA1 / constant-time" notes.
106+
107+
## §5 Assumptions about the environment
108+
109+
- **Host OS**: Linux, macOS, Windows; binaries published on GitHub
110+
Releases and as Docker / snap packages *(documented: `README.md`)*.
111+
- **Filesystem**: writes a config file under `~/.cmk/`; writes a
112+
shell-history file *(inferred — Q1)*.
113+
- **Network**: outbound HTTPS to the configured `apiurl`.
114+
- **Auth**: stdlib TLS, opt-out via `verifycert = false`.
115+
- **What CloudMonkey does not do**: no listener, no env-var
116+
consumption beyond shell defaults, no background process *(inferred
117+
— Q3)*.
118+
119+
## §5a Build-time and configuration variants
120+
121+
| Knob | Default | Stance | Effect |
122+
| --- | --- | --- | --- |
123+
| `verifycert` | `true` *(inferred — Q4)* | dev / self-signed | flips `InsecureSkipVerify` *(documented: `config/config.go` line ~226)* |
124+
| `apikey` / `secretkey` | none | operator config | persisted in `~/.cmk/config` |
125+
| `output` (`json`/`text`/`table`/`csv`) | per-config | display | not security-relevant |
126+
| `timeout` | per-config | bounds async polling | not security-relevant by itself |
127+
| history-file path | `~/.cmk/history` *(inferred — Q5)* | operator | may contain sensitive params (passwords, API keys typed inline) |
128+
| `theme`, profiles | per-config | operator | not security-relevant |
129+
130+
## §6 Assumptions about inputs
131+
132+
| Entry point | Parameter | Attacker-controllable in the model? | Caller must enforce |
133+
| --- | --- | --- | --- |
134+
| `~/.cmk/config` | URL, key, secret, verifycert | **no** — operator config | filesystem permissions; do not check into VCS |
135+
| Interactive REPL | typed command | **no** — operator input | nothing |
136+
| `-p` profile selection from command line | name | **no** | nothing |
137+
| Bundled `apis.json` | static description | **no** — ships with binary | n/a |
138+
| HTTP response | JSON body | trusted (B1) | typed-decoded |
139+
140+
## §7 Adversary model
141+
142+
Main-model §7 applies. **Adjustments specific to CloudMonkey**:
143+
144+
- "Unauthenticated network peer reaching `:8080`" actor is upstream of
145+
CloudMonkey.
146+
- An additional adversary worth naming: **a local attacker on the
147+
operator's host with non-operator UID who can read `~/.cmk/config`
148+
or `~/.cmk/history`**. Whether CloudMonkey enforces strict file
149+
perms on these files is Q1.
150+
151+
## §8 Security properties the CLI provides
152+
153+
### C1 — HMAC-SHA1 signature per the main model (via shared signer logic)
154+
155+
- **Property.** Each API call carries a valid HMAC-SHA1 signature, with
156+
the canonical parameter string. *(inferred — Q2; needs maintainer
157+
confirmation that CloudMonkey uses the same signer as the Go SDK or
158+
a vetted equivalent.)*
159+
- **Conditions / violation / severity.** As main model §8 P1.
160+
161+
### C2 — TLS verification on by default
162+
163+
- **Property.** *(inferred — Q4)* default `verifycert = true`.
164+
- **Conditions / violation / severity.** As Go-SDK delta §8 S2.
165+
166+
### C3 — Strict permissions on `~/.cmk/config`
167+
168+
- **Property.** *(inferred — Q1)* CloudMonkey writes its config with
169+
mode 0600 (or similar) on POSIX so that other users on the same host
170+
cannot read the API secret.
171+
- **Violation symptom.** Config file is world-readable after `cmk`
172+
writes it.
173+
- **Severity.** Security-critical, `VALID` per main-model §13.
174+
175+
## §9 Security properties the CLI does *not* provide
176+
177+
- **No protection against a local attacker on the same host with
178+
shell access.** If they can read `~/.cmk/config`, they have the API
179+
secret.
180+
- **No history-file scrubbing.** Sensitive parameters typed inline
181+
(e.g. `createUser password=...`) end up in `~/.cmk/history`
182+
*(inferred — Q5)*.
183+
- **No defence when `verifycert = false`.**
184+
- **No re-validation of management-server response correctness.**
185+
186+
### False-friend properties
187+
188+
- **`verifycert = false` is not a "test mode."** It silently disables
189+
TLS verification across all subsequent calls.
190+
- **HMAC-SHA1 — see main model §11a.**
191+
192+
## §10 Downstream responsibilities
193+
194+
The operator running `cmk` MUST:
195+
196+
1. Keep `~/.cmk/config` mode 0600 and outside any shared/synced
197+
location.
198+
2. Set `verifycert = true` unless connecting to a known dev cluster.
199+
3. Avoid typing API secrets / passwords on the interactive prompt
200+
(they land in history). Prefer scripted invocations that read from
201+
a secret store.
202+
4. Rotate `apikey` / `secretkey` on suspicion of compromise.
203+
5. Match `cmk` version to the management-server version where API
204+
compatibility matters *(inferred — Q6)*.
205+
206+
## §11 Known misuse patterns
207+
208+
- Checking `~/.cmk/config` into a Git repo.
209+
- Setting `verifycert = false` in production.
210+
- Sharing `~/.cmk/` across users on a multi-user host.
211+
- Running `cmk` over an unencrypted SSH session that gets logged on
212+
the jump host.
213+
214+
## §11a Known non-findings (recurring false positives)
215+
216+
- **"HMAC-SHA1 — SHA1 is deprecated."**`KNOWN-NON-FINDING` per main
217+
model §11a.
218+
- **"`InsecureSkipVerify` is reachable from a config setting."** Gated
219+
by `verifycert`. → `OUT-OF-MODEL: trusted-input`.
220+
- **"Config file contains plaintext credentials."** By design — see
221+
§10 item 1. → `BY-DESIGN: property-disclaimed`.
222+
- **"`vendor/` has CVE-X."** Vendored upstream. → `OUT-OF-MODEL:
223+
unsupported-component` (upstream pointer).
224+
225+
## §12 Conditions that would change this delta
226+
227+
- A credential-store integration (keychain / agent) replacing the
228+
plaintext config file.
229+
- A history-scrubbing feature.
230+
- Change in signing algorithm at the main-model layer.
231+
232+
## §13 Triage dispositions
233+
234+
Use the same table as the main model.
235+
236+
## §14 Open questions for the maintainers
237+
238+
**Q1.** Does CloudMonkey set strict permissions (mode 0600) on
239+
`~/.cmk/config` when it writes it? Does it warn the operator if the
240+
file is found with looser perms?
241+
242+
**Q2.** Does CloudMonkey use `apache/cloudstack-go` as its signer, or
243+
does it have its own near-copy? If a copy, does it stay in sync? Does
244+
it set `signatureversion=3`?
245+
246+
**Q3.** Confirm CloudMonkey has no background daemon, no
247+
env-var-credential channel, no listener.
248+
249+
**Q4.** Confirm `verifycert` default — `true`?
250+
251+
**Q5.** Does `~/.cmk/history` redact sensitive parameter values
252+
(passwords, secret keys typed inline)? Is history per-profile or
253+
shared?
254+
255+
**Q6.** Compatibility matrix between `cmk` version and CloudStack
256+
version — where is it documented?
257+
258+
**Q7.** Meta — should this delta live at `docs/threat-model.md` in
259+
`apache/cloudstack-cloudmonkey`?

0 commit comments

Comments
 (0)