> ## Documentation Index
> Fetch the complete documentation index at: https://astronomer.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Astro Private Cloud MCP server security posture

> What an AI agent can reach through the Astro Private Cloud MCP server, and as whom.

The Astro Private Cloud (APC) Model Context Protocol (MCP) server is an additional interface to the same platform, subject to the same role-based access control (RBAC) as the APC UI and the Astro CLI. The APC API authorizes every call against the caller's own role.

> [!NOTE]
>
> **Astro Private Cloud 2.2**
>
> This feature was introduced in Astro Private Cloud 2.2. To access this feature, upgrade your Astro Private Cloud installation to 2.2 or later.

> [!NOTE]
>
> An agent can do exactly what its caller can do, and the server holds no credential of its own. Every call carries the caller's own token, and the APC API is the sole authority for authentication and authorization.

## How this holds

The MCP server contains no authentication or authorization code. It is only a client of the APC API and acts only as the caller.

* The MCP server forwards the caller's own token verbatim to the APC API and never substitutes a credential of its own.
* Authentication happens at two points: a cached admission check at the gate before a request reaches the server, and a fresh resolution of the caller's identity from the forwarded token at the APC API on every downstream call.
* Authorization happens only at the APC API, on every downstream call, never at the gate. It decides whether each individual action is allowed, against the identity resolved from that call's token.
* Tools take a Deployment identifier, never a URL, host, or base path. The server resolves the target itself, so a model can't steer an authenticated request elsewhere.

### Authentication

The control plane ingress intercepts every request and makes an NGINX `auth_request` sub-request to an agent authentication endpoint on the APC API. The endpoint resolves the token and answers `200` on success or `401` on failure. It returns no identity headers. The server re-presents the caller's own bearer token on each downstream call rather than trusting a gate header. This step only authenticates; it doesn't resolve Deployments or compute permissions.

The gate resolves all three of the APC API's existing token shapes:

| Token | Shape | Resolved by |
| - | - | - |
| APC API JSON Web Token (JWT) | Three dot-separated segments, `kid` in the header | Signature and database role bindings |
| Service account | 32 characters, no dots | Database lookup, no signature |
| Identity provider (IdP) token | Two comma-separated JWTs | The IdP's JSON Web Key Set (JWKS) and the APC API's claims mapping |

A client authenticates with an APC API service-account key as its bearer token.

The gate caches each verdict, keyed on the request's `Authorization` header: a success for five minutes and a denial for one minute by default (`astronomer.mcpServer.authCache.validSuccess` and `astronomer.mcpServer.authCache.validFailure`). A revoked or expired token can therefore continue to pass the gate until its cached success expires. This caching applies only to the verdict at the gate.

### Authorization

Because the gate runs ahead of the server, unauthenticated traffic never reaches it. The server forwards each tool call to the APC API, which resolves the caller's identity from the forwarded token and authorizes the action against the caller's own permissions.

> [!NOTE]
>
> The server listens on an in-cluster `ClusterIP` Service, so this guarantee assumes the network forces all traffic through the ingress. The platform NetworkPolicy, rendered when `global.networkPolicy.enabled` is set (the default), admits only the control plane ingress controller and the metrics scraper, so no other in-cluster workload can reach the server directly. An operator who disables this NetworkPolicy must provide equivalent isolation.

Platform operations are authorized at the APC API's GraphQL resolver, per operation. Airflow-state reads are authorized against a default-deny allowlist that maps each permitted `(method, path)` to a required permission, so a new read endpoint requires a deliberate change instead of being exposed by a blanket rule.

The operator's chart configuration (the enabled tool groups and any individually disabled tools) determines the tool catalog, which is otherwise the same for every caller. The control is the upstream authorization above, which refuses any call the caller's permissions don't allow, whether or not the tool appeared in that caller's catalog.

## What the agent can reach

The agent reaches the platform only through the APC API, across the following capability areas, bound to the caller's own RBAC.

| Capability | Source | Authorized by |
| - | - | - |
| Platform operations (Deployment lifecycle, Workspace management, variables, deploy history) | APC API GraphQL | The APC API resolver, per operation |
| Airflow run and task-instance state (Dag (directed acyclic graph) run state, task-instance state, stats, and run diagnosis) | Laminar Airflow-state service, through an APC API passthrough | The APC API, at Deployment level, against a default-deny route allowlist; operator-based Deployments only |
| Airflow diagnostics and remediation (task logs, import errors, installed providers, health; clearing and deleting Dag runs and task instances) | The Deployment's Airflow REST API, through an APC API passthrough | The APC API at Deployment level (default-deny route allowlist), then the Deployment's own Airflow per-resource permission check |
| Upgrade guidance | Knowledge base bundled into the server image | No network call and no external access |

## Stated limitations

> [!WARNING]
>
> These are intended design properties, stated so a security reviewer doesn't have to discover them.

* Airflow-state reads are authorized at Deployment level. Reads from the Laminar Airflow-state service don't carry per-resource Airflow (Flask-AppBuilder) permissions.
* Service accounts act as themselves. A service account resolves through the gate using its own role bindings, with no per-user attribution or per-caller delegation, so it can't act as another user.
* A Workspace-scoped service account reaches every Deployment in its Workspace. A Workspace user role covers platform operations only, but the APC API expands a Workspace service account's role to Deployment level on every Deployment in that Workspace, at the same tier: a Workspace Editor service account acts as a Deployment Editor on each, including Deployments created later. Where the Airflow tool groups are enabled, that token reaches the Airflow-state tools, read and destructive, on every Deployment. To limit an agent to specific Deployments, issue it a Deployment-scoped service account instead.
* Destructive operations are governed by RBAC and a required `confirm` argument, not by a user prompt. Where the caller's role allows it, the agent can take irreversible actions: deleting a Deployment or Workspace, deleting or clearing a Dag run, clearing task instances, or rolling back a Deployment. Destructive tools carry a `destructiveHint` annotation that a client can use to ask the user first, but the hint is advisory, and the agent decides whether to honor it. The server doesn't prompt the user itself, so showing a prompt is up to the client. The server requires `confirm: true` on the seven mutating and destructive tools that take a `confirm` argument, and rejects any call without it with a `denied` error, whatever the client does.
* Bring-your-own-ingress is unsupported. The authentication gate is an NGINX `auth_request` that exists only when the platform's own NGINX serves the ingress. Enabling the MCP server with `global.authSidecar.enabled` set triggers a Helm `fail`, so the install or upgrade stops instead of exposing the server without authentication. The Istio Gateway feature requires \`global.authSidecar. to be enabled, so the same restriction applies.

## Model inference

Astro Private Cloud is bring-your-own-LLM. The MCP server never sees a prompt or a completion. The customer owns the model endpoint, and this component doesn't host, proxy, or pay for model inference.
