Skip to main content

Dremio's MCP Server Doesn't Give AI Agents a Separate Policy — Here's the Kubernetes Version for a Self-Hosted PaaS's Deploy Tools

9 min readDora NodaDora Noda
Share
On this page

An AI agent connects to your platform's deploy tool, authenticates as "the platform," and calls rollback_release. Nothing in that call proves which tenant the human on the other end of the chat window actually owns. If the tool's authorization check is a line of application code — if user.tenant_id == release.tenant_id — a bug in that one if statement, or a tool call the agent wasn't supposed to be able to make in the first place, is the only thing standing between "roll back my own app" and "roll back someone else's." That's the exact shape of failure Dremio's lakehouse quietly closed for SQL access last November, and it's worth stealing the fix wholesale.

What "Governance Travels With the Agent" Actually Means

Dremio shipped its Model Context Protocol server back in May 2025 — a way to point Claude, ChatGPT, or any MCP-speaking client at an Iceberg lakehouse and query it in natural language. The interesting part came six months later. With the November 13, 2025 release of Dremio's Next Generation Cloud, that MCP server moved from something a customer self-hosted to a managed endpoint, and it picked up OAuth-based identity propagation on the way: an agent connecting through the hosted server carries the actual signed-in user's identity into every query, not a shared service credential standing in for "whoever's using AI today."

The concrete claim, straight from Dremio's own writeup: "If a user can't see certain columns or rows in the Dremio UI, they won't see them through the MCP Server either." That's a testable guarantee, not a marketing line — it means an agent's SQL query is authorized by the exact same role-based access control (RBAC) and fine-grained access control (FGAC) — row filters, column masks — that a human hits when they log into the Dremio UI directly. There's no separate "agent policy" someone had to remember to write and keep in sync with the human one.

That distinction matters more than it sounds. The lazy version of "let AI agents use our platform" is almost always: mint one API key or service account with broad rights, hand it to the MCP server process, and let the tool's own code decide what a given request is allowed to do. That code is one more place authorization logic can drift out of sync with the real policy, and — this is the part that bites — the underlying data store never sees a reason to say no, because as far as it's concerned every request comes from the same maximally-privileged identity. Dremio's fix is structural instead: the query engine itself enforces RBAC/FGAC on every request, so an agent literally cannot see a row or column its human didn't already have rights to, regardless of what the MCP tool code does or doesn't check.

The Layer Underneath: Credentials the Query Engine Never Gets to Keep

RBAC and FGAC decide what a query is allowed to return. They don't, by themselves, decide who's allowed to touch the actual bytes sitting in S3 or ADLS — that's a separate, older piece of lakehouse plumbing called credential vending, and it's worth understanding because it's the part of the pattern with a direct Kubernetes analog.

Apache Iceberg tables are typically registered with a REST catalog (Polaris is the reference implementation; Dremio's catalog implements the same contract). When a query engine needs to read or write a table, it doesn't hold a standing credential to the storage bucket at all. It asks the catalog to load the table, the catalog checks whether that caller is authorized, and only then calls out to the cloud IAM layer — AWS STS AssumeRole, Azure Managed Identity, a GCP service account — to mint a temporary, narrowly-scoped credential: typically a 15-to-60-minute token that grants access to exactly the S3 prefix or ADLS path that one table's data lives in, nothing broader. The catalog logs every one of those vends: which engine, which table, which operation, when.

Stack the two together and the shape is: OAuth identity propagates from the agent's human all the way to the query engine (RBAC/FGAC layer), and the query engine's own storage access is itself scoped down to short-lived, table-specific credentials it re-requests constantly rather than a standing key it holds forever (credential-vending layer). Neither layer trusts the other to be the only line of defense, and neither one is something a client — human, BI tool, or agent — can see or route around.

The Pattern, Named

Pull the Dremio-specific nouns out and what's left is a three-layer template that applies to any system deciding whether to let an AI agent touch something with real consequences:

LayerWhat it doesDremio's implementation
1. Identity propagationThe caller's real identity reaches the resource layer — not a shared credential standing in for "the agent"OAuth authorization-code flow through the hosted MCP server; the connecting user's identity, not a pooled service account
2. Authorization at the resource itselfAccess rules are enforced where the data lives, not in application code the caller's own request passes throughRBAC + FGAC (row filters, column masks) evaluated by the query engine on every query
3. Scoped, short-lived credential issuanceWhatever ends up touching the actual storage/compute holds the narrowest, shortest-lived grant possible, freshly issued and logged per useIceberg REST catalog credential vending: 15–60 min, prefix-scoped STS tokens, audit-logged per vend

Skip layer 1 and you're back to one shared credential standing in for every caller — the tool code has to reinvent authorization from scratch. Skip layer 2 and identity propagates correctly but nothing stops a caller from asking for something outside their remit; you're trusting the caller's client to be honest. Skip layer 3 and even a correctly-scoped request touches storage with a credential broader and longer-lived than that one request needed, which is exactly the blast radius a compromised or over-eager agent turns into a real incident.

Applying It to a Self-Hosted PaaS's Deploy and Rollback Tools

Trade "query a lakehouse" for "deploy or roll back a service" and the naive failure mode looks like this: the platform runs an MCP server that exposes deploy_release and rollback_release tools, and under the hood that server holds one Kubernetes kubeconfig — a single ServiceAccount token, usually with cluster-wide rights to touch Deployments, because that was the fastest way to make the demo work. Every tenant's agent session talks to the same MCP server process, which talks to the cluster as that one privileged identity. Tenant-scoping, if it exists at all, is an if tenant_id == release.tenant_id check in the tool handler — application code standing in for layer 2, with nothing underneath enforcing it if that check is ever wrong, bypassed, or simply missing from a new tool someone ships in a hurry.

That's layer 1 and layer 3 both skipped: no real per-tenant identity reaches the Kubernetes API, and the credential the MCP server holds is neither scoped nor short-lived — it's a standing, cluster-wide key sitting in an environment variable. An agent authorized only to operate on tenant A's app is, from the Kubernetes API server's point of view, indistinguishable from cluster-admin.

The fix is the same three layers, built from primitives Kubernetes already ships:

LayerKubernetes-native primitiveWhat it buys
1. Identity propagationThe MCP server authenticates the human via the platform's own OAuth flow (same identity provider used for the dashboard), and carries that identity — not its own — into every tool callAn agent's deploy call is tied to the tenant who's actually logged in, the same way a Dremio query is tied to the signed-in user, not to "the AI feature"
2. Authorization at the resource itselfRBAC impersonate verb: the MCP server's own ServiceAccount is granted rights only to impersonate specific tenant identities (--as=tenant-a-deploy-bot), and the Kubernetes API server evaluates the impersonated identity's RBAC bindings — scoped to that tenant's namespace — on every requestThe tool handler's own code stops being the last line of defense; even a bug in the MCP server's logic hits the API server's RBAC wall, not an empty namespace boundary
3. Scoped, short-lived credential issuanceKubernetes TokenRequest API: mint an audience-bound, time-limited (e.g. 10-minute) ServiceAccount token scoped to one tenant's namespace, per deploy/rollback call, instead of a standing kubeconfig the MCP server holds indefinitelyKubernetes's direct analog to Iceberg's STS-vended, prefix-scoped storage credential — a leaked or logged token is worthless in ten minutes and never had cluster-wide reach to begin with

The audit trail closes the loop the same way it does for Dremio's catalog: Kubernetes' own audit policy logs every impersonated request — who was impersonated, what verb, what object, when — giving a fleet operator the same "which engine, which table, which operation, at what time" record Iceberg's catalog keeps for storage access, except for deploys and rollbacks instead of table reads.

None of these three primitives are exotic. TokenRequest, RBAC impersonate, and audit logging all ship in stock Kubernetes — a Cluster API-managed fleet already has them available; what's missing in the naive version isn't a capability gap, it's that nobody wired the MCP server to use them instead of a static, over-privileged kubeconfig. That's the actual work: not "should an AI agent be allowed to deploy code," but "does the deploy tool's own credential have any less reach than the tenant who's allowed to call it" — and building bex's deploy/rollback MCP tools on impersonated, TokenRequest-issued, namespace-scoped tokens from the start is what keeps that answer "no" true by construction, the same way Dremio's query engine makes "the agent literally is that user" true by construction instead of by convention.


Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. The deploy and rollback MCP tools follow the pattern above: per-tenant identity propagation, Kubernetes RBAC as the actual enforcement layer, and short-lived TokenRequest-issued credentials instead of a standing privileged kubeconfig. Star the repo on GitHub or deploy your first app today.

Sources

Related articles

Give your agents a chain backend

Autonomous agents hit RPC endpoints very differently than people do. See what bex router handles on their behalf.

Read the agents guide