blob: 15708c6f6dbdd733b11094063d3e63d461864f4e [file] [view]
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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
http://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.
-->
# Security and permission model
[English](security-model.md) | [简体中文](security-model.zh-CN.md)
Security is layered. MCP authentication, exact operation authorization,
capability visibility, query safety, transport policy, and Apache Doris RBAC
each protect a different boundary. Enabling one layer does not remove the need
for the others.
## Trust model
```text
Network and proxy
-> HTTP Host/Origin/TLS policy
-> credential authentication
-> MCP operation scope
-> domain discovery scope
-> exact child execution scope
-> provider allowlist and capability gate
-> SQL/identifier/result guard
-> request-specific Doris identity and RBAC
-> sanitized bounded response
```
The MCP Server is not an authorization proxy that can grant more data access
than Doris. Doris remains the final authority for catalogs, databases, tables,
columns, rows, UDFs, audit metadata, and system views.
## Authentication modes
### Anonymous local development
Unauthenticated HTTP is permitted only on a loopback bind under the default
policy. It is not a production mode. Non-loopback startup without an enabled
authentication method fails unless the operator sets the explicit dangerous
`ALLOW_UNAUTHENTICATED_NON_LOOPBACK=true` override.
stdio relies on the local process boundary and environment supplied by the
Host. Protect local environment variables, config files, and process access.
### Static bearer tokens
Enable with `ENABLE_TOKEN_AUTH=true`. Static tokens are validated at the MCP
boundary and can be bound to a dedicated Doris route. Persisted token records
use self-describing SHA-256/SHA-512 digests and atomic owner-only writes;
plaintext legacy records are migrated one way.
The optional HTTP token-management interface is disabled by default and must
remain localhost-only, IP-restricted, and protected by a separate high-entropy
admin credential. Admin credentials belong in headers, never query strings.
### JWT
Enable with `ENABLE_JWT_AUTH=true` and configure the expected issuer/key/
algorithm boundary. Private signing keys and shared secrets must be injected
from a secret manager or protected process environment. Do not store real keys
in the repository.
### External OAuth 2.0/OIDC
Enable external access-token validation with `ENABLE_OAUTH_AUTH=true`. Tokens
must pass trusted issuer, audience/resource, lifetime, active-state, and exact
scope validation before optional user information is accepted. An invalid or
insufficient token returns a standards-aligned Bearer challenge without
exposing provider internals.
Email/domain-to-role mappings are normalized and validated. Domain elevation
requires verified identity evidence; fallback mappings do not silently widen
exact child scopes.
### Doris-backed OAuth
`ENABLE_DORIS_OAUTH_AUTH=true` provides an OAuth boundary whose resulting
request identity owns a Doris user connection pool. It requires HTTP, a
configured service account, a public resource/base URL, and `WORKERS=1` in
1.0. External OAuth and Doris-backed OAuth are mutually exclusive.
Authorization codes, access tokens, clients, and user pool state are
process-local. Access tokens are bound to the canonical MCP resource. Required
RFC resource values, redirect policies, PKCE/client rules, and application type
are validated. Raw Doris passwords are not persisted in the token store.
Database-backed child access is disabled by default and uses explicit
feature-ID allowlists and exact scopes when enabled. A Doris OAuth token cannot
silently fall back to the global service account for a protected data call.
## Exact authorization
Authorization is performed more than once:
1. **MCP operation:** for example `list_tools`, `call_tool`, `read_resource`.
2. **Domain discovery:** whether the identity can learn about a child.
3. **Child execution:** exact policy such as
`child:call:doris_query:execute_query`.
4. **Channel/provider:** whether Doris OAuth, semantic, ADBC, MetricFlow, or custom
provider access is enabled and allowlisted.
5. **Doris RBAC:** whether the selected Doris identity can execute the actual
statement or read the actual metadata.
OAuth paths require exact domain/child scopes. Wildcard guesses and pre-1.0
tool scopes do not grant access. Discovery does not imply execution.
Unauthorized children are filtered from manifests and execute as not found to
avoid capability-name disclosure.
## Doris identities and connection routing
The route manager selects credentials in explicit order:
1. Doris OAuth request identity and its user-owned pool;
2. static-token-bound Doris configuration;
3. global service account for configurations that permit it.
Pools are isolated by canonical route identity. Timeout, cancellation,
credential mismatch, or unsafe owner/pool state fails closed rather than
falling through to a more privileged pool. Query, metadata, FE HTTP, and
capability evidence must remain aligned to the same request route.
Use a dedicated least-privileged Doris account for every trust boundary. See
[Doris fine-grained access control](../doris-fine-grained-access-control.md)
for grants, row policies, and token-bound examples.
## SQL and identifier safety
The built-in 1.0 domains are read-only. `doris_admin` is not registered.
The shared query guard:
- parses and accepts one supported read-only statement;
- rejects DDL, DML, administrative commands, stacked statements, comments or
constructs that violate policy, and malformed parameters;
- validates/quotes catalog, database, table, column, function, and metric
identifiers;
- binds caller values instead of concatenating them where the driver permits;
- checks query target SQL used by Explain/diagnosis as well as direct queries;
- applies timeout, row, serialized-byte, depth, collection, and text limits;
- classifies timeout/read-only/argument/backend failures without returning raw
backend exception text.
Structured Search never accepts arbitrary filter SQL or a raw search DSL.
Allowlisted FE/BE HTTP clients validate configured destinations and prevent
caller-controlled SSRF targets.
## Result and metadata safety
- Configured masking rules run before model-facing results are returned.
- Sensitive table/column policies can restrict or transform data.
- Raw SQL, client addresses, authentication mappings, object locations,
catalog properties, Variant samples, and backend errors are removed or
bounded where the domain contract does not require them.
- Query results, tool inputs, and structured outputs have absolute size/depth
limits.
- Schema validation errors report paths and keywords, not rejected secret
values.
- Trace baggage keys resembling credentials are redacted before propagation.
- Public capability snapshots use stable reason codes and sanitized evidence,
not connection strings or probe exception details.
## Transport security
- Bind local development to `127.0.0.1`, `localhost`, or `::1`.
- Validate both HTTP `Host` and `Origin` to mitigate DNS rebinding.
- A bind address such as `0.0.0.0` is not a public hostname allowlist.
- Use HTTPS when traffic leaves the machine.
- Configure trusted proxy CIDRs before accepting forwarded identity/scheme
headers; never trust proxy headers globally.
- Keep credentials in authorization headers or protected environment/secret
mounts, never URLs.
- Run the management interface separately from ordinary MCP access policy.
## State and secret handling
- MCP state handles are HMAC signed, principal/scope/expiry bound, and contain
no credentials or query data.
- Set a shared high-entropy `MCP_STATE_HANDLE_SECRET` only when independent
replicas share traffic; rotate it as a deployment secret.
- Token digests are not reversible bearer credentials.
- Logs use redacted credential DTOs and safe representations.
- Do not enable debug logging that serializes request headers or environment
secrets at the reverse proxy or process supervisor.
- `.env`, token files, OAuth client files, JWT keys, private Ossie binding
manifests, and MetricFlow projects/provider commands require owner-only
access and must not be committed when they contain private definitions.
## Custom providers
Only installed entry points named in `MCP_TOOL_PROVIDERS` load. Provider names,
tool names, schemas, lifecycle, audit metadata, and bounded rate limits are
validated. Startup fails closed on an invalid allowlisted provider. Provider
tools cannot shadow built-in tools or silently inherit built-in authorization.
Review [Custom tool providers](../custom-tool-providers.md) before enabling an
extension.
## Security limitations in 1.0
- Doris-backed OAuth is single-worker and process-local.
- Process-local custom-provider rate limits are not a distributed quota.
- ADBC is default-off, requires explicit user intent on every call, and is
fail-closed for token-bound routes because the Flight client is process-global.
- The MetricFlow sidecar receives model requests but no Doris credentials. It
compiles SQL only; the MCP read-only guard, request route, Doris RBAC, and
result limits remain mandatory.
- Native lineage delivery is asynchronous best effort; it is evidence, not a
transactional authorization source.
- Application-level SQL guards do not replace Doris grants and row policies.
- Public reverse-proxy host/origin shapes require explicit validation and are
not made safe merely by binding `0.0.0.0`.
## Production checklist
- Use TLS and an authenticated non-loopback deployment.
- Use least-privileged Doris accounts and test negative grants.
- Select one intentional authentication mode and validate exact scopes.
- Keep token-management endpoints disabled unless actively administered.
- Store secrets outside source control and verify filesystem permissions.
- Configure only trusted FE/BE/provider endpoints.
- Verify `/live` and `/ready` separately.
- Run read-only and permission-denial regression tests against the target
Doris patch.
- Review availability reason codes after upgrades.
- Monitor audit logs without logging bearer values or raw sensitive data.