● Zion Boggan
repos/Cyclops V2/vault/01-archetypes/devops-infra.md
zionboggan.com ↗
115 lines · markdown
History for this file →
1
---
2
archetype: devops-infra
3
primary_gate_families: [1, 7, 8, 2]
4
---
5
 
6
# Archetype - Self-Hosted DevOps & Infra Services
7
 
8
Targets: Jenkins, Grafana, Gitea/Forgejo, Redis, Jupyter, Argo CD/Workflows, MinIO, Metabase,
9
Prometheus, Vault-adjacent tooling, Consul, Nomad, Harbor, Nexus. The thesis: these run with
10
**high privilege at the center of an org** (they hold cloud creds, signing keys, DB access, and the
11
deploy keys to everything), they are *meant* to execute things (pipelines, queries, dashboards), and
12
self-hosters routinely misconfigure auth. A single unauth RCE here is a foothold into the entire
13
estate - [[../00-doctrine/SEVERITY-GATE#family-8-exposed-critical-service-trust-infrastructure-compromise|Family 8]] / [[../00-doctrine/SEVERITY-GATE#family-1-remote-code-execution-the-crown|Family 1]] / Family 7 / Family 2.
14
 
15
See: [[cicd-supplychain]] (Jenkins/Argo overlap), [[ai-agent-mcp]] (often co-hosted).
16
 
17
---
18
 
19
## Principals & trust boundaries
20
 
21
- **Principals:** unauthenticated internet/intranet caller, low-priv authenticated user, the service
22
  process (holding cloud/DB/signing creds), the host & the orchestrator (Docker/K8s) it runs on.
23
- **Core boundaries:** *unauth → service* (the exposed-service problem), *low-priv user → admin
24
  capability*, *service → host/orchestrator* (a query/pipeline that reaches the OS or the K8s API),
25
  *service → the credentials it holds* (SSRF/template/file-read that dumps the cloud creds).
26
 
27
**Boundary map template:**
28
```
29
principals:        unauth-caller | low-priv-user | service-process(holds creds) | host/orchestrator
30
trust inputs:      HTTP API params, dashboard/query definitions, pipeline/job configs, datasource
31
                   configs, template strings, uploaded plugins, webhook payloads, the auth token itself
32
enforcement pts:   authn/authz on each route, the query/datasource sandbox, template sandbox,
33
                   SSRF allowlist, the service-account scope, RBAC
34
cross-boundary
35
sinks:             groovy/script console (Jenkins), datasource URL fetch (Grafana SSRF),
36
                   SQL/native-query (Metabase), MODULE LOAD / CONFIG SET (Redis),
37
                   notebook exec (Jupyter), workflow templates (Argo), git hooks (Gitea),
38
                   the cloud-cred env/metadata the service can reach
39
confusion
40
hypotheses:        "an admin route is reachable unauth via path normalization";
41
                   "the SSRF allowlist misses 169.254.169.254 / a redirect / DNS-rebind";
42
                   "a low-priv role can reach a script/query sink";
43
                   "default creds / no creds on the management port"
44
```
45
 
46
---
47
 
48
## Kill chains (each lands on a Gate family)
49
 
50
### KC-1 - Unauth or default-cred RCE on the exposed service (Family 8 → 1)
51
The bread and butter. The service is reachable without (real) auth and exposes an exec primitive.
52
- **Per-target sinks:**
53
  - **Jenkins:** the Groovy *script console* (`/script`), the CLI deserialization channel, agent
54
    protocols; pipeline `sh` steps. (Cite the Jenkins CLI/Groovy RCE class.)
55
  - **Redis:** unauth `CONFIG SET dir/dbfilename` → write cron / `authorized_keys` / a webroot file;
56
    `MODULE LOAD` → native RCE; replication-based module load. (Cite the Redis-unauth-RCE class.)
57
  - **Jupyter:** an open notebook server (no token) → `os.system` in a cell.
58
  - **Metabase:** unauth setup-token → DB connection → H2/native-query RCE (cite the Metabase
59
    pre-auth RCE class).
60
  - **Argo CD/Workflows:** an exposed API → run a workflow template with a container we control.
61
  - **Gitea/Forgejo:** git hooks / a malicious migration URL (SSRF) / a webhook→exec path.
62
  - **MinIO/Harbor/Nexus:** default creds, an SSRF in the remote-fetch, an admin API exposed.
63
- **Oracle:** the unauth/default path lands command output / a callback / a written canary → Family 1.
64
 
65
### KC-2 - SSRF → cloud metadata → credential theft → cloud ATO (Family 7 → 3)
66
These services constantly fetch URLs the user supplies (Grafana datasource proxy, Gitea migrate,
67
webhook tests, image registries). An SSRF that reaches `169.254.169.254` (AWS), the GCP/Azure metadata
68
endpoints, or an internal admin API steals the service's IAM credentials.
69
- **Sinks:** the datasource/proxy fetch, the avatar/webhook/import URL fetch, any "test connection".
70
- **The gate discipline:** a *bare* SSRF callback is **not** a finding (Family 7 trap). You must
71
  **capture the metadata credential** and minimally prove it works → that's the Family 3 ATO.
72
- **Oracle:** the IMDS token captured + a benign `GetCallerIdentity` confirming the role → Family 3.
73
 
74
### KC-3 - Template / query injection → file read or RCE (Family 1 / 7)
75
Grafana template variables, Metabase/Superset SQL, Prometheus/Alertmanager templates, Argo workflow
76
templates - expression/template engines that can reach the FS or OS.
77
- **Sinks:** the template render, the native-query executor, the alerting template (SSTI).
78
- **Oracle:** template/query reads our canary secret (Family 7) or executes (Family 1).
79
 
80
### KC-4 - Service → orchestrator takeover (Family 2)
81
The service runs in a container/pod with a mounted Docker socket or a powerful K8s service-account.
82
RCE in the service (KC-1) then pivots: read the SA token, hit the K8s API, schedule a pod, or use the
83
Docker socket to escape to the node.
84
- **Sinks:** `/var/run/docker.sock` mounted in, the SA token at
85
  `/var/run/secrets/kubernetes.io/serviceaccount/token`, an over-scoped RBAC role.
86
- **Oracle:** an action on the node / cross-namespace, per [[../00-doctrine/SEVERITY-GATE#family-2-container-vm-sandbox-hypervisor-escape-orchestrator-takeover|Family 2]].
87
 
88
---
89
 
90
## The dynamic oracle, concretely
91
 
92
1. `docker run` the exact version in a disposable env with **planted canary cloud creds** (a fake IMDS
93
   or a real throwaway role) and a canary secret file. Pin version.
94
2. `test_unauth_access` / `discover_paths` / `discover_api_endpoints` to map the real auth surface
95
   (path-normalization unauth bypasses are common - try `..;/`, `%2e`, double-slash, case).
96
3. For SSRF: stand up a fake metadata endpoint + `start_callback_server`; require the **credential
97
   capture**, not just the callback.
98
4. REPLICA_CONFIRMED on the artifact; LIVE_CANARY only within explicit program scope (these are often
99
   internet-exposed third-party installs - **do not** touch non-consenting ones; replica-first).
100
 
101
---
102
 
103
## BORING traps - do NOT spend time here
104
 
105
- **"The service is exposed to the internet without auth."** That is a *port-scan observation*, the
106
  start of Family 8, not a finding. The capability must fire (data read / RCE). v1 loved reporting
107
  these as criticals - don't.
108
- **Bare blind SSRF.** Per the gate and Zion's standing rule, never standalone - chain to metadata
109
  cred or internal-admin or RCE.
110
- **Default creds with nothing behind them / a read-only dashboard.** Prove the privileged action.
111
- **Version-banner "vulnerabilities".** "Old Jenkins/Grafana" is not a finding; demonstrate it.
112
- **Re-finding the public CVE (Metabase/Redis/Jenkins) on an unpatched box.** Sibling-CVE - that's a
113
  patching observation, not novel research. Hunt fresh code/routes or a misconfig that yields *new*
114
  impact.
115
- **Self-DoS / crashing the service.** Not in scope of the gate families.