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

# Permission boundaries

> Capping what a principal can ever be granted, so you can delegate permission management safely.

A permission boundary is a policy attached to a principal that sets the
**maximum** it can ever be granted. It grants nothing on its own — it is a
ceiling, not a floor.

```
effective permissions  =  what the policies allow  ∩  what the boundary allows
```

An action has to be allowed by **both**. A policy that grants something outside
the boundary grants nothing.

## Why they exist

Without boundaries, letting someone manage permissions means letting them grant
themselves anything. A boundary lets you delegate that safely: a team lead can
create service accounts and attach policies, and nothing they attach can reach
past the ceiling you set.

<Steps>
  <Step title="Write the ceiling">
    A policy describing the widest set of permissions anything in this team may
    ever hold.

    ```json theme={null}
    {
      "version": "2024-01-01",
      "statements": [{
        "sid": "TeamCeiling",
        "effect": "allow",
        "actions": ["compute:*", "storage:*", "dns:*"],
        "resources": ["*"],
        "conditions": [
          { "operator": "equals", "key": "basalt:ResourceTag/team", "values": ["platform"] }
        ]
      }]
    }
    ```
  </Step>

  <Step title="Attach it as a boundary">
    <Tabs>
      <Tab title="Console">
        Open the user, service account or role and find its **Permission
        Boundary** card. Choose **Set Boundary** and pick the policy. Once one
        is set the button reads **Change**, and clearing it confirms with
        **Remove Permission Boundary**.

        A group has no such card, which is the table below made visible.
      </Tab>

      <Tab title="API">
        ```bash theme={null}
        PUT /v1/service-accounts/{service_account_id}/permission-boundary
        { "policy_id": "..." }
        ```

        The same three routes exist for `users` and `roles`:
        `PUT`, `GET` and `DELETE`.
      </Tab>
    </Tabs>
  </Step>

  <Step title="Delegate policy management">
    Whoever manages this principal can now attach whatever policies they like.
    Anything outside the ceiling has no effect.
  </Step>
</Steps>

## What a boundary applies to

| Principal       | Bounded on                                             |
| --------------- | ------------------------------------------------------ |
| User            | Its own boundary                                       |
| Service account | Its own boundary                                       |
| Assumed role    | The **role's** boundary — the session inherits the cap |
| Group           | — Groups carry policies, not boundaries                |

<Note>
  An assumed-role session is bounded by the role it assumed, not by whoever
  assumed it. The role is the bounded entity; a session cannot escape its
  role's ceiling by being created from an unbounded caller.
</Note>

<Warning>
  **Organization owners are not bounded.** An owner's implicit access is
  subject only to an explicit `deny`; the boundary check is never reached for
  them. Do not model an owner as "an administrator with a ceiling" — use an
  explicit deny for a guardrail that has to hold for everyone.
</Warning>

## How it combines with everything else

A boundary is the **last** of the three narrowing steps, and each one can only
subtract:

```mermaid theme={null}
flowchart LR
    A[Identity policies] --> B[∩ session policy]
    B --> C[∩ permission boundary]
    C --> D[Effective permissions]
```

An explicit deny anywhere short-circuits all of it. See
[how a request is authorized](/iam#how-a-request-is-authorized).

## Failing closed

<Warning>
  If a boundary is set but the boundary or its policy **cannot be read**, the
  request is denied. A boundary that exists but is unreadable might be capping
  this very action, so the safe answer is no.

  The practical consequence: deleting a policy that is in use as a boundary
  does not widen access, it removes it.
</Warning>

## Worked example

Delegating instance management to a team, safely.

<AccordionGroup>
  <Accordion title="1. The boundary" icon="shield">
    Everything this team may ever touch — compute and storage, only on
    resources tagged as theirs, and never IAM.

    ```json theme={null}
    {
      "version": "2024-01-01",
      "statements": [
        {
          "sid": "Ceiling",
          "effect": "allow",
          "actions": ["compute:*", "storage:*"],
          "resources": ["*"],
          "conditions": [
            { "operator": "equals", "key": "basalt:ResourceTag/team", "values": ["platform"] }
          ]
        }
      ]
    }
    ```
  </Accordion>

  <Accordion title="2. What the team lead may attach" icon="user-cog">
    A policy letting them manage their own service accounts:

    ```json theme={null}
    {
      "version": "2024-01-01",
      "statements": [{
        "sid": "ManageTeamServiceAccounts",
        "effect": "allow",
        "actions": [
          "iam:CreateServiceAccount",
          "iam:AttachServiceAccountPolicy",
          "iam:PutServiceAccountInlinePolicy"
        ],
        "resources": ["crn:iam:::service-account/*"]
      }]
    }
    ```
  </Accordion>

  <Accordion title="3. Why this is safe" icon="check">
    Suppose the lead attaches `{"effect": "allow", "actions": ["*"],
            "resources": ["*"]}` to a bounded service account.

    That service account still cannot touch IAM, cannot touch a resource
    tagged for another team, and cannot reach any service outside compute and
    storage — the boundary intersects every one of those away. The broad
    policy is not rejected; it simply does not reach past the ceiling.

    <Note>
      Note what this example does **not** do: it does not let the lead attach
      or remove *boundaries*. If they could, they could raise their own
      ceiling. Grant boundary management only to whoever is meant to set the
      ceiling.
    </Note>
  </Accordion>
</AccordionGroup>

## Boundary or explicit deny?

Both restrict, and they are not interchangeable.

<Columns cols={2}>
  <Card title="Use a boundary" icon="shield">
    To cap **one principal** while letting someone else manage its policies.
    It is a ceiling on delegation, and it does not apply to organization
    owners.
  </Card>

  <Card title="Use an explicit deny" icon="ban">
    For a rule that must hold for **everyone**, including owners. A deny beats
    every allow and is never intersected away.
  </Card>
</Columns>

## Next

<CardGroup cols={2}>
  <Card title="Writing policies" icon="file-text" href="/iam/policies">
    The document format a boundary uses — it is an ordinary policy.
  </Card>

  <Card title="Roles and credentials" icon="key-round" href="/iam/roles">
    Session policies narrow the same way, per set of credentials.
  </Card>
</CardGroup>
