Skip to content

Latest commit

 

History

History
202 lines (153 loc) · 25.7 KB

THREAT_MODEL.md

File metadata and controls

202 lines (153 loc) · 25.7 KB

Apache Drill — Threat Model (v0 draft)

§1 Header

  • Project: Apache Drill (apache/drill), master @ HEAD (2026-06). Scope: apache/drill only.
  • Date: 2026-06-18. Author: ASF Security team, drafted via the threat-model-producer (Scovetta) rubric at the Drill PMC's request (path 3 — chosen by Charles Givre, 2026-06-17).
  • Status: DRAFT — under Drill PMC review (Charles Givre, 2026-06). Most load-bearing claims remain (inferred) pending further PMC confirmation (see §14).
  • Version binding: versioned with the project; a report against version N is triaged against the model as it stood at N.
  • Reporting cross-reference: §8-property violations → report privately per the ASF process (security@apache.org → private@drill.apache.org); §3/§9 findings are closed citing this document.
  • Provenance legend: (documented) = Drill's own docs/repo; (maintainer) = confirmed by a Drill PMC member through this process; (inferred) = reasoned from architecture/docs, not yet PMC-ratified — each has a matching §14 open question.
  • Draft confidence: ~10 documented / 3 maintainer / ~25 inferred (cgivre's PR #3052 review folded: contrib/ plugins in scope + the storage-enumeration non-finding; 2026-10: CREATE FUNCTION USING JAR / CREATE DAFFODIL SCHEMA USING JAR staging-area precondition).

What Drill is. Apache Drill is a schema-free, distributed SQL query engine for large-scale datasets. A cluster of Drillbit daemons (coordinated via Apache ZooKeeper) accepts ANSI-SQL queries over JDBC, ODBC, a REST API, and a Web UI (default port 8047), and executes them directly against data in configurable storage plugins (local/HDFS/S3 files, Hive, HBase, Kafka, MongoDB, RDBMS via JDBC, HTTP, …) — discovering schema at query time rather than requiring a pre-defined schema. (documented — drill.apache.org)

§2 Scope and intended use

Intended deployment: a clustered set of Drillbits inside an operator-controlled, network-isolated cluster, queried by analytics clients. Drill also runs in an embedded single-JVM mode (developer/laptop) where the caller controls everything. (documented — install docs; inferred that clustered behind a perimeter is the security-relevant shape)

Caller roles (Drill is a network service — the role splits):

  • SQL client — submits queries over JDBC/ODBC/REST. May be authenticated or, if auth is disabled, anonymous. The primary untrusted boundary. (inferred — §14 Q1)
  • Operator / admin — configures storage plugins, system/session options, security settings, and uploads dynamic UDFs via the Web UI/REST. Trusted. (documented — storage-plugin + option config is an admin function)
  • Embedding / submitting user under impersonation — when impersonation is enabled, the Drillbit accesses the underlying data source as the submitting user, delegating authorization to the data source. (documented — impersonation docs)
  • Peer Drillbit — another node in the cluster, authenticated over the inter-Drillbit RPC. Trusted once authenticated (§7 Byzantine note). (inferred — §14 Q3)

Component families.

Family Entry point Touches OS/network In model?
Client RPC / SQL front door Drillbit user RPC (JDBC/ODBC), the "foreman" network (listens) In — primary boundary (inferred — §14 Q1)
Web UI + REST API :8047 — query submit, storage-plugin config, profiles, options network (listens) In — high value (admin surface) (documented — Web UI)
SQL engine parse → plan (Calcite) → distributed execute depends on plugins In (inferred)
Storage plugins file/HDFS/S3, Hive, HBase, Kafka, Mongo, JDBC (RDBMS), HTTP filesystem + network out In — file-read / SSRF / connector surface (documented — storage plugins)
UDF layer built-in functions + dynamic UDFs (runtime jar upload) in-JVM code execution In as code-execution-by-design (documented — dynamic UDFs)
Inter-Drillbit RPC control + data RPC between Drillbits, SASL network (intra-cluster) In (boundary is authenticated) (inferred — §14 Q3)
Client connectors JDBC driver, ODBC driver, C++ client client trust domain client-side — out (§3)
contrib/ storage + format plugins connectors/formats bundled + maintained with Drill (contrib/storage-*, contrib/format-*) filesystem + network out In — same connector surface as the storage-plugin row (maintainer — cgivre)
Tests / examples / sample data exec/.../test, demo code, sample datasets n/a Out (see §3)

§3 Out of scope (explicit non-goals)

  • The security of the underlying data sources. HDFS/S3 permissions, the RDBMS behind the JDBC plugin, Hive authorization, the Kafka cluster — each enforces its own access control. Drill assumes them; it is not responsible for their misconfiguration. (inferred — §14 Q2)
  • Dynamic UDFs and storage-plugin configuration as code/connectivity execution. Uploading a UDF jar or configuring a storage plugin is an authorized admin operation; the code/connection runs with the Drillbit's privileges. This is a feature, not a sandbox escape — BY-DESIGN. A finding that requires admin rights to register a UDF or add a plugin is out of model. (documented — admin function; §14 Q4 confirms the trust line) For dynamic UDFs specifically, CREATE FUNCTION USING JAR only registers a jar that is already present in the UDF staging area (drill.exec.udf.directory.staging); the SQL statement cannot upload content. Placing a jar there requires write access to the Drill cluster's filesystem, which is the real trust gate (§11a). The same holds for DFDL schemas: CREATE DAFFODIL SCHEMA USING JAR only registers a jar already in drill.exec.daffodil.directory.staging, and the Daffodil format's schemaURI/schemaFile come from admin-only format config. (maintainer — cgivre, 2026-10)
  • An operator with cluster/root access, the Drillbit service account, or direct ZooKeeper write access. Anyone who controls the cluster processes or the coordination store has already won. OUT-OF-MODEL: adversary-not-in-scope. (inferred — §14 Q5)
  • Embedded / single-user mode, where the caller owns the JVM, the filesystem, and all input — equivalent to an in-process library call. (inferred — §14 Q1)
  • SQL injection in an embedding application that string-concatenates untrusted input into Drill SQL — that is the embedding app's bug, not Drill's. (inferred — §11)
  • Tests, examples, and sample data (exec/.../test, demo code, sample datasets) — not a shipped runtime surface. (inferred) NB: the contrib/ storage/format plugins are in scope — they ship with Drill and are PMC-maintained, carrying the same connector trust surface as the core storage plugins (§2); only tests/examples/samples are out. (maintainer — cgivre, PR #3052)

§4 Trust boundaries and data flow

  • Client → Drillbit (the foreman) is the primary boundary, over both the user RPC (JDBC/ODBC) and the Web UI/REST (:8047). The session is authenticated when drill.exec.security.auth is enabled (PLAIN via PAM/LDAP, Kerberos, or custom); every statement is then subject to the configured authorization (impersonation + storage permissions + views). Whether SQL text, connection properties, and storage-plugin references are treated as untrusted at this boundary is the load-bearing triage question. (documented — auth mechanisms; inferred — §14 Q6 on what is treated untrusted)
  • Drillbit → data source. With impersonation enabled, the Drillbit accesses the source as the submitting user, so the source's own ACLs bound the query; with impersonation disabled, all access runs as the Drillbit service principal and authorization collapses to whatever Drill itself enforces. The two modes have materially different blast radii. (documented — impersonation; §14 Q7)
  • Drillbit ↔ Drillbit (control/data RPC) and Drillbit ↔ ZooKeeper are intra-cluster boundaries assumed to run inside an operator-controlled, network-isolated perimeter, optionally SASL/encryption-protected. (inferred — §14 Q3)

Reachability precondition (triager's test). A finding is in-model only if it is reachable by an authenticated low-privilege SQL/REST client (or an anonymous one when auth is a supported-disabled posture, §5a) — i.e. without admin rights to configure plugins or upload UDFs, and without control of the data source or the cluster host. A finding that requires any of those is OUT-OF-MODEL. (inferred — §14 Q1/Q4/Q5)

§5 Assumptions about the environment

  • A JVM on each Drillbit; Apache ZooKeeper for cluster coordination; the cluster network is operator-controlled and not directly exposed to untrusted clients except through the intended client RPC / :8047 endpoints. (inferred — §14 Q5)
  • Authorization correctness depends on the data sources (and/or Drill views + impersonation) enforcing access; Drill does not re-implement source-side ACLs. (inferred — §14 Q2)
  • Negative side-effects inventory (inferred — §14 Q8; high-value to confirm): beyond listening on its RPC/Web ports, reading the storage plugins it is configured for, writing query profiles + spill files to its configured areas, and coordinating via ZooKeeper, a Drillbit is assumed to make no other outbound connections except those a query explicitly drives (JDBC/HTTP/Kafka/Mongo plugins, SERVICE-like federation). Confirm there is no ambient phone-home / auto-fetch.

§5a Build-time and configuration variants

The security envelope is set primarily by runtime configuration, not compile flags. The load-bearing knobs (all defaults to be confirmed — §14 Q9; the insecure-default question reshapes §8/§10/§11a/§13):

Knob Effect Default (to confirm)
drill.exec.security.auth.enabled (+ mechanism: PLAIN/Kerberos/…) Whether the client front door authenticates at all. disabled by default (inferred — §14 Q9)
drill.exec.impersonation.enabled Whether queries run as the submitting user against the source (delegating authz) vs. as the Drill service principal. disabled by default (inferred — §14 Q9)
Wire encryption (SASL / SSL-TLS, client↔Drillbit and inter-Drillbit) Whether sessions + data are in clear on the wire. off unless configured (inferred — §14 Q9)
Web UI / REST auth (form / SPNEGO) Whether :8047 — which can configure plugins + upload UDFs — is open. tied to auth.enabled (inferred — §14 Q9)
Dynamic UDF support (drill.exec.udf.*) Whether authorized users can upload UDF jars at runtime. enabled (inferred — §14 Q9/Q4)

Insecure-default question (wave 1). If auth and impersonation ship disabled, is a multi-user deployment left in that state a VALID finding, or OUT-OF-MODEL: non-default-build (operator is documented as required to enable them before exposing Drill)? — §14 Q9.

§6 Assumptions about inputs

Surface Input Attacker-controllable? Concern
Client RPC / REST SQL text yes (authenticated client) query-driven file/URL access, resource cost, planner bugs
Client RPC JDBC/ODBC connection properties (incl. impersonation target) yes inbound-impersonation / identity spoofing if not gated
Web UI / REST storage-plugin config JSON, option sets, UDF jar upload admin only (trusted) code/connection execution — by design (§3)
Query execution file paths / URIs named in queries (dfs, http, jdbc plugins) yes local-file read / SSRF / arbitrary-RDBMS reach, bounded by impersonation + plugin config
Storage scan data files (CSV/JSON/Parquet/Avro…) from configured sources maybe (whoever can write the source) parser robustness / resource use on malformed data
Inter-Drillbit RPC control/data frames no — authenticated peer §7 Byzantine-peer only

§7 Adversary model

  • In scope: an authenticated low-privilege SQL/REST client (and, if auth-disabled is a supported posture, an anonymous network client reaching the client RPC or :8047). Capabilities: submit arbitrary SQL, set connection properties, drive query-time file/URL access through configured plugins, submit pathological queries. Goals: read data outside their authorization, make a Drillbit issue outbound requests (SSRF via HTTP/JDBC plugins), read local files via the dfs plugin, exhaust cluster resources. (inferred — §14 Q1/Q6)
  • Network MITM between client and Drillbit, or between Drillbits, where encryption is not configured. (inferred — §14 Q9)
  • Out of scope: the operator/admin (configures plugins, uploads UDFs — trusted, §3); anyone with cluster-host / service-account / ZooKeeper-write access (§3); the data sources themselves (§3).
  • Authenticated-but-Byzantine peer. A compromised Drillbit holding a valid cluster identity could behave arbitrarily over the inter-Drillbit RPC. Drill is assumed to make no cross-node integrity claim against a malicious authenticated peer — full peer trust once authenticated. (inferred — §14 Q3)

§8 Security properties the project provides

(All (inferred) pending §14; each lists violation symptom + severity.)

  1. Client authentication (when enabled). With auth.enabled, no SQL/REST statement runs before the session authenticates via the configured mechanism. Violation: unauthenticated query execution against an auth-enabled cluster. Severity: security-critical. (inferred — §14 Q9/Q10)
  2. Authorization scoping via impersonation + views + storage permissions. A query reads/writes only what the effective identity is permitted at the data source (impersonation on) and/or what Drill views/permissions allow. Violation: a low-priv client reading data it is not authorized for, or bypassing a view. Severity: security-critical (CVE-class). (inferred — §14 Q7/Q10)
  3. No arbitrary code execution or plugin reconfiguration for a non-admin client. Registering UDFs and configuring storage plugins are admin-gated; a plain SQL client cannot reach them. Violation: a non-admin causing code exec / plugin change / arbitrary file or URL access beyond their authorization. Severity: security-critical. (inferred — §14 Q4)
  4. Inbound-impersonation is gated. A client cannot assume an arbitrary user identity unless the operator configured a proxy/impersonation policy permitting it. Violation: identity spoof via connection properties. Severity: critical. (inferred — §14 Q6)
  5. Memory safety on the JVM for well-formed input, to the extent the JVM provides it. (inferred)
  6. Bounded/fair resource use — deferred. Whether a single expensive query can exhaust a Drillbit (heap/direct memory/CPU) or whether per-query memory limits + queues bound it is a §14 question; stated as a property only if the PMC confirms a guarantee. (inferred — §14 Q11)

§9 Security properties the project does not provide

  • No sandbox around dynamic UDFs or storage-plugin configuration. Code/connections an authorized admin registers run with the Drillbit's privileges — by design. (inferred — §14 Q4)
  • No protection when auth/impersonation are left disabled (if that is a non-default posture, §5a) — an open, impersonation-off Drillbit exposes its service-principal access to any client. (inferred — §14 Q9)
  • No defense against query-driven SSRF / local-file read beyond what plugin config + impersonation bound. The http/jdbc/dfs plugins exist to reach those resources; restricting them is operator config, not an engine guarantee. (inferred — §14 Q2)
  • No hard resource-fairness / anti-DoS guarantee unless §14 Q11 says otherwise — a sufficiently expensive query may degrade a Drillbit.
  • Not a security boundary over its data sources — Drill does not add confidentiality/integrity on top of a source that lacks it.
  • Well-known classes (SQL-engine / connector): SSRF via outbound-connector plugins, local-file disclosure via filesystem plugins, decompression/parser resource attacks on scanned files, and SQL injection in embedding apps — the standard risks of a federated query engine that reaches arbitrary configured sources. (inferred)

§10 Downstream (operator) responsibilities

  • Enable authentication and impersonation before exposing Drill to more than one trusted user; do not run a multi-user cluster with the shipped auth-off / impersonation-off defaults. (inferred — §14 Q9)
  • Lock down the Web UI / REST (:8047) — it can configure storage plugins and upload UDFs; restrict it to admins and protect it with auth + TLS.
  • Restrict who can configure storage plugins and upload dynamic UDFs to trusted admins (these are code/connectivity-execution surfaces).
  • Restrict write access to the UDF staging area (drill.exec.udf.directory.staging, on drill.exec.udf.directory.fs). Write access there is equivalent to code execution on every Drillbit once any user runs CREATE FUNCTION USING JAR. Set exec.udf.enable_dynamic_support = false if dynamic UDFs are not needed. Apply the same restriction to the Daffodil schema staging area (drill.exec.daffodil.directory.staging, on drill.exec.daffodil.directory.fs).
  • Configure wire encryption (SASL/SSL) on client↔Drillbit and inter-Drillbit links on untrusted networks.
  • Network-isolate the Drillbit cluster + ZooKeeper from untrusted networks; give data-source credentials least privilege.

§11 Known misuse patterns

  • Exposing the client RPC or :8047 to an untrusted network with auth/impersonation disabled.
  • Granting storage-plugin-config or UDF-upload rights to untrusted users (= handing them code execution + arbitrary connectivity).
  • Configuring a dfs/http/jdbc plugin broadly (e.g. filesystem root, open egress) and exposing it to low-priv query clients without impersonation.
  • Treating Drill as an authorization layer over a data source that has none.
  • String-concatenating untrusted input into Drill SQL in an embedding application.

§11a Known non-findings (recurring false positives)

(v0 seed — the PMC will own the authoritative list; §14 Q12.)

  • "A dynamic UDF / storage plugin can run arbitrary code or reach any URL/file." By design — both are admin-authorized operations. BY-DESIGN unless a non-admin can reach them. (inferred)
  • "The REST API / Web UI accepts requests without authentication." Only when auth is disabled — a non-default/operator-chosen posture (pending §14 Q9), not a Drill defect. OUT-OF-MODEL: non-default-build.
  • "A query can read an arbitrary local file via the dfs plugin." In-model only if it crosses the impersonated identity's authorization or the configured workspace; otherwise it is the operator's plugin-scope choice. (inferred — §14 Q2/Q7)
  • "Drill can enumerate / read the files, schemas, or storage systems it is pointed at." That is the function of a federated query engine — exposing configured storage to SQL is the point of Drill, not a vulnerability. KNOWN-NON-FINDING / BY-DESIGN. In-model only if the access crosses the authenticated identity's authorization (reading data an impersonated user shouldn't, or bypassing a Drill view — §8.2). (maintainer — cgivre, PR #3052: "yes… that's the point of Drill".)
  • "CREATE FUNCTION USING JAR / CREATE DAFFODIL SCHEMA USING JAR lets a user load a malicious jar or DFDL schema." Recurring report. Neither statement uploads anything: each only registers a jar that already sits in its staging area on the cluster filesystem (UDF: drill.exec.udf.directory.staging, binary + sources; Daffodil: drill.exec.daffodil.directory.staging). CreateFunctionHandler and CreateDaffodilSchemaHandler fail if the file is missing. To exploit it, the attacker must already have write access to that filesystem location, i.e. filesystem/cluster access the model already treats as having won (§3, §7). OUT-OF-MODEL: adversary-not-in-scope. In-model only if a low-privilege client can get attacker-controlled bytes into the staging area through Drill itself (e.g. a CTAS/export or REST path that writes into either staging directory), which would be a VALID §8.3 break. Pointing the Daffodil format at an arbitrary schemaURI is format config, i.e. admin-tier (OUT-OF-MODEL: trusted-input). (maintainer — cgivre, 2026-10)
  • "SQL injection in Drill" where the untrusted string was concatenated by an embedding app — that app's bug (§11), not Drill's.
  • Dependency-tail CVEs (Calcite, Hadoop, Jackson, Netty, a transitive jar) from an SCA scan — triage upstream unless Drill's own code reaches the vulnerable path with untrusted input.

§12 Conditions that would change this model

  • A new client-facing surface or a change to the auth/impersonation defaults (§5a).
  • A new storage plugin or connector with a new outbound/trust surface.
  • Sandboxing UDFs, or moving plugin config out of the admin-only trust tier.
  • A report that cannot be routed to a §13 disposition → revise §8/§9.

§13 Triage dispositions

Disposition Meaning Licensed by
VALID A §8 property breaks via an in-scope (authenticated low-priv / anonymous-if-supported) client on a realistic config. §8, §6, §7
VALID-HARDENING A §11 misuse is too easy (e.g. an over-broad default plugin scope). §11
OUT-OF-MODEL: trusted-input Requires admin-tier input (plugin config / UDF jar) or data the operator already trusts. §6
OUT-OF-MODEL: adversary-not-in-scope Requires operator / cluster-host / ZooKeeper / data-source control. §7
OUT-OF-MODEL: unsupported-component Lands in tests, examples/sample data, or embedded single-user mode. (NB: contrib/ storage/format plugins are in scope — §2.) §3
OUT-OF-MODEL: non-default-build Only manifests with auth/impersonation/encryption left at a discouraged setting. §5a
BY-DESIGN: property-disclaimed Concerns a property §9 disclaims (UDF/plugin code exec, SSRF-by-config, data-source security). §9
KNOWN-NON-FINDING Matches §11a. §11a
MODEL-GAP Unroutable. triggers §12

§14 Open questions for the maintainers

Wave 1 — scope & intended use

  • Q1. Confirm the in-scope surface is "an authenticated SQL/REST client at the Drillbit front door (JDBC/ODBC/REST/Web UI), in a clustered multi-user deployment", with embedded single-user mode out of scope. Anything to add?
  • Q2. Confirm Drill is not responsible for the underlying data sources' own access control — that HDFS/S3/RDBMS/Hive/Kafka security is theirs, and Drill's job is to honor it (via impersonation/views), not replace it.
  • Q4. (Partially answered — cgivre, 2026-10: CREATE FUNCTION USING JAR and CREATE DAFFODIL SCHEMA USING JAR require the jar to be pre-placed in a staging area, so filesystem write access is the gate; folded into §3/§10/§11a.) Confirm dynamic-UDF upload and storage-plugin configuration are admin-only, code/connectivity-execution-by-design — i.e. a finding that requires those rights is out of model.
  • Q5. Confirm operators with cluster-host / Drillbit-service-account / ZooKeeper-write access (and the data sources themselves) are out of model.

Wave 2 — auth, impersonation, defaults

  • Q9. (reshapes §5a/§8/§10/§11a/§13) What are the shipped defaults for security.auth.enabled, impersonation.enabled, wire encryption, and Web-UI auth — and is "left at the default in a multi-user deployment" a VALID finding or OUT-OF-MODEL: non-default-build?
  • Q6. At the client→Drillbit boundary, are SQL text, connection properties, and inbound-impersonation targets all treated as untrusted (i.e. is identity-spoof via connection properties prevented unless an explicit proxy policy permits it)?
  • Q7. Which impersonation posture is the supported/recommended one, and does authorization fully delegate to the data source when it's on?
  • Q10. What does Drill claim to uphold given a valid authenticated session (auth, authz scoping, others) — confirm the §8 list.

Wave 3 — boundaries, resources, false-friends

  • Q3. Inter-Drillbit + ZooKeeper trust: confirm these are assumed network-isolated, the RPC is authenticated (SASL), and Drill makes no integrity claim against a Byzantine authenticated peer.
  • Q8. Confirm the §5 "no ambient side effects" inventory — beyond its ports, configured plugins, profile/spill writes, and ZooKeeper, a Drillbit makes no other outbound connection except those a query drives.
  • Q11. Is super-linear CPU/memory in query/data size a bug, or is bounding it the operator's job (per-query memory limits, queues)? Is a hang on a pathological query a security issue? Or is no resource guarantee made?
  • Q12. (Partially answered — cgivre, PR #3052: storage/filesystem enumeration via Drill is by-design, not a finding — folded into §11a. More welcome.) What do scanners/researchers most often report against Drill that you consider a non-finding? (Feeds §11a.)