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

# IAM trust model

> How Nuphos federates into your cloud accounts — short-lived, least-privilege, and without a long-lived key.

For the cloud providers below, Nuphos holds no long-lived key at all. You
establish a **trust relationship** once, and Nuphos mints **short-lived
credentials on demand** for each session. This page explains the mechanism for
each provider and why it's built this way.

<Note>
  Federation is the model wherever the provider supports it. Some connectors have
  no equivalent and do take a token or key, which Nuphos stores encrypted — API
  tokens for [Linode](/connectors/linode) and [Hetzner](/connectors/hetzner), and
  the optional R2 S3 credentials on [Cloudflare](/connectors/cloudflare). Each
  connector page says which it uses.
</Note>

## AWS — OIDC web-identity federation

Nuphos runs an **OpenID Connect identity provider**. When the agent needs AWS
access, the backend signs a short-lived OIDC token and calls
`sts:AssumeRoleWithWebIdentity` against the IAM role you created.

The token carries:

* **Issuer:** `https://nuphos.ai` (its discovery document is published at
  `https://nuphos.ai/.well-known/openid-configuration`)
* **Audience (`aud`):** `sts.amazonaws.com`
* **Subject (`sub`):** `nuphos:team:<your-team-id>`

Your role's trust policy pins all three with a `StringEquals` condition. The
**`sub` condition is the key isolation control**: it ties the role to *your* team
specifically, so no other Nuphos team can assume it — the standard mitigation for
the confused-deputy problem. Nuphos also enforces that a given role ARN can only
be bound by one team.

|                          | Value             |
| ------------------------ | ----------------- |
| OIDC token lifetime      | \~5 minutes       |
| Assumed session lifetime | \~1 hour          |
| What Nuphos stores       | the role ARN only |

See [Connect AWS](/connectors/aws) for the exact provider URL and trust policy.

<Note>
  Older connections may use a legacy static-connector principal instead of OIDC.
  That path has no per-team `sub` condition, which is why OIDC web-identity is the
  recommended method for new connections.
</Note>

## Azure, Tencent, Alibaba Cloud, Volcengine — the same issuer

These four reuse the **same Nuphos OIDC identity provider** as AWS: same issuer,
same JWKS, same per-team `sub`. Only the audience differs, because each cloud
pins a different client id on its side.

| Provider      | Exchange                                        | Audience (`aud`)             | What Nuphos stores                  |
| ------------- | ----------------------------------------------- | ---------------------------- | ----------------------------------- |
| Azure         | Entra `client_credentials` + `client_assertion` | `api://AzureADTokenExchange` | tenant, client, and subscription id |
| Tencent Cloud | `sts:AssumeRoleWithWebIdentity`                 | `sts.tencentcloudapi.com`    | role ARN + OIDC provider name       |
| Alibaba Cloud | `sts:AssumeRoleWithOIDC`                        | `sts.aliyuncs.com`           | role ARN + OIDC provider ARN        |
| Volcengine    | `sts:AssumeRoleWithOIDC`                        | `sts.volcengineapi.com`      | role TRN                            |

No client secret, access key, or service-account key is stored for any of them.
The per-team `sub` does the same isolation work it does on AWS: the trust is
pinned to your team, so no other Nuphos team can exchange a token against it.

## GCP — workload identity federation, then impersonation

For GCP you create a **connector service account** in your project and grant
Nuphos the **Service Account Token Creator** role on it. Nuphos then impersonates
that account to mint short-lived access tokens. What differs is *which Nuphos
principal* you grant it to.

**New bindings** name a workload identity principal scoped to your team:

```
principal://iam.googleapis.com/projects/NUMBER/locations/global/workloadIdentityPools/POOL/subject/nuphos:team:YOUR_TEAM_ID
```

The pool lives in Nuphos's own GCP project — you create nothing — and Nuphos
federates into it with the same per-team token the other clouds use. Because the
subject is baked into your grant and Google checks it against the token, **a
token minted for another Nuphos team cannot use your grant**: the same
confused-deputy control the `sub` condition gives you on AWS, enforced by IAM
rather than by our code.

**Older bindings** name the platform service account
(`zeabur-byos-connector@zeabur-system.iam.gserviceaccount.com`) instead. They keep
working and still involve no key on your side: Nuphos federates as your team and
then delegates through that account.

|                             | Value                                         |
| --------------------------- | --------------------------------------------- |
| Federated token lifetime    | \~5 minutes                                   |
| Impersonated token lifetime | \~1 hour                                      |
| What Nuphos stores          | the service account email and project ID only |

See [Connect GCP](/connectors/gcp) for the exact grant — the binding dialog shows
which principal to use.

## Why short-lived and per-session

* **No standing keys to leak.** Nuphos stores only a reference (a role ARN or a
  service account email), never a usable secret.
* **Blast radius is bounded.** Credentials expire in about an hour and are scoped
  to the session that requested them.
* **You stay in control.** Trust is something you grant in your own cloud and can
  revoke at any time by editing the role's trust policy or removing the
  impersonation grant.

## Hardening

* Start the role/connector **read-only** and widen only as the agent needs it.
* Keep the AWS **`sub` condition** intact — it's what scopes the role to your team.
* Use [member allow-lists](/security/access-control) to limit which people can use
  sensitive accounts.
* Require [plan approvals](/security/approvals) for changes.
* Keep roles least-privilege and widen them through admin-approved
  [permission grants](/security/permission-admin) rather than over-provisioning up
  front.
