In-Cluster API Access
Code running inside a Miren sandbox can call the cluster's own API — deploy, read logs, open a shell, inspect status — authenticating as itself, with no API key to store or rotate. It's the Miren equivalent of a Kubernetes pod using its service-account token to reach the Kubernetes API.
Every sandbox already carries a workload identity token. That page is about presenting the token outward (to AWS, GCP, your own APIs). This page is about pointing it inward: using it to talk to Miren, and choosing what a given app's workloads are allowed to do once they do.
- Workload Identity — present the token to external services to prove which workload you are.
- In-Cluster API Access (this page) — present the same token to the Miren API, scoped by a role.
Typical uses: a CI job running inside a sandbox that redeploys its own app, a sidecar that tails its app's logs, an operator tool that reads status across the cluster, or an app that manages its own configuration.
Minimum working example
From inside any sandbox with the miren binary in its image, the CLI authenticates automatically:
miren app status
miren logs
That works out of the box under the default app-readonly role. To let an app do more — redeploy itself, for example — raise its role in .miren/app.toml:
name = "my-app"
workload_role = "app-deployer"
Connecting
From inside a sandbox, the miren CLI just works — it detects that it's running in-cluster and authenticates with the mounted token:
miren app status # your own app
miren logs # your own app's logs
No miren login, no config file. This assumes the miren binary is in your image — nothing mounts it into the sandbox, so a distroless or slim image needs the CLI installed first. If a config file is present (for example you ran miren login yourself), that wins — so you can still point the CLI at another cluster from inside a sandbox.
Miren wires this up through environment variables it injects into every sandbox:
| Environment variable | Value | Use |
|---|---|---|
MIREN_IN_CLUSTER | 1 | Marks the process as running inside a sandbox |
MIREN_API_ADDRESS | e.g. 10.x.x.1:8443 | The cluster API address, reachable from the sandbox |
MIREN_CA_CERT_PATH | /var/run/miren/ca.crt | The cluster CA, used to verify the API's certificate |
MIREN_IDENTITY_TOKEN_PATH | /var/run/miren/identity-token | The token presented on each request |
The connection is verified against the cluster CA — it is not insecure. Because sandboxes share a network bridge, skipping verification would let a neighbor impersonate the API, so the CA is mounted and checked.
Roles
A token authenticates as a role, and the role decides what it may call. Confinement is per app: an app-scoped role can only act on the app the sandbox belongs to, while a cluster-scoped role reaches across the whole cluster.
The default is app-readonly — a fresh app's workloads can read their own status and logs, and nothing else. You opt up from there.
| Role | Scope | What it grants |
|---|---|---|
none | — | Authenticates but authorizes nothing |
app-readonly (default) | own app | Read own app status, logs, and deployment history |
app-deployer | own app | app-readonly + build and (re)deploy its own app |
app-debugger | own app | app-readonly + open a shell / run commands in its own sandboxes |
app-admin | own app | app-deployer + edit config/env and exec — everything for its own app except deleting it |
cluster-readonly | cluster | Read status, logs, and infrastructure state across all apps |
cluster-deployer | cluster | cluster-readonly + build, deploy, and configure any app (but not create or destroy apps) |
cluster-debugger | cluster | cluster-readonly + exec and inspect any app |
cluster-admin | cluster | Broad control across the cluster (see the limits below) |
No role — not even cluster-admin — can mint identity tokens for other sandboxes, perform raw entity-store writes, or reconfigure the cluster's network fabric. Those stay on the internal operator (certificate) plane. A role is a bearer token mounted in a sandbox; these limits bound the blast radius if one leaks.
Choosing a role
There are two ways to set an app's role, and they draw the line between what an app owner can do and what an operator can do.
In .miren/app.toml — self-service, for app owners:
name = "my-app"
workload_role = "app-deployer"
An app confining a token to its own app isn't an escalation — you already control the app. Declaring a cluster-scoped role here fails the deploy, with a message pointing you at the operator command.
With the CLI — the operator path:
miren app set-workload-role -a my-app app-admin
miren app set-workload-role -a tooling cluster-readonly
set-workload-role is not reachable by in-sandbox workloads or app-scoped deploy identities — only a cluster operator can call it. That's what stops an app owner from self-granting cluster-wide access.
You can see an app's current role in miren app status.
Sharp edges
The role is baked into a sandbox's token when the sandbox is created, and the background token refresh preserves it. Changing a role — via app.toml on a redeploy, or set-workload-role — applies to sandboxes built after the change. A redeploy that reuses an existing pool keeps the old role until those sandboxes are actually rebuilt (for example by a deploy that changes the app, or a restart that recreates instances).
A cluster-scoped role is a powerful credential sitting on disk inside a sandbox. Prefer the narrowest role that does the job — an app-* role for anything that only touches one app — and reserve cluster roles for genuine cross-app tooling. Tokens are short-lived (refreshed on a fixed loop), which bounds exposure, but that is not a substitute for least privilege.
workload_role from app.toml does not revoke itDeleting the line leaves the last value in place — a deploy with no workload_role doesn't clear it. To drop back to the minimum, set workload_role = "none" explicitly (or app-readonly), which revokes on the next build.
MIREN_API_ADDRESS is the API as seen from the sandbox network. It is not a public endpoint and not a stable value — always read it from the environment rather than hardcoding it.
See also
- Workload Identity — the token itself, and presenting it to external services
- app.toml Reference — the
workload_rolefield