diff --git a/docs/docs.json b/docs/docs.json index e94d7a95..287d3f24 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -236,6 +236,7 @@ "group": "Secure & integrate", "pages": [ "tutorials/set-up-sso", + "tutorials/grant-scoped-stack-access", "tutorials/configure-environment-guardrails", "tutorials/set-up-a-webhook", "tutorials/resolve-stack-drift" diff --git a/docs/images/tutorials/grant-scoped-stack-access/audit-log.png b/docs/images/tutorials/grant-scoped-stack-access/audit-log.png new file mode 100644 index 00000000..ddc51d1d Binary files /dev/null and b/docs/images/tutorials/grant-scoped-stack-access/audit-log.png differ diff --git a/docs/images/tutorials/grant-scoped-stack-access/jordan-compose-readonly.png b/docs/images/tutorials/grant-scoped-stack-access/jordan-compose-readonly.png new file mode 100644 index 00000000..c26e3861 Binary files /dev/null and b/docs/images/tutorials/grant-scoped-stack-access/jordan-compose-readonly.png differ diff --git a/docs/images/tutorials/grant-scoped-stack-access/jordan-toolbar.png b/docs/images/tutorials/grant-scoped-stack-access/jordan-toolbar.png new file mode 100644 index 00000000..050dd9ff Binary files /dev/null and b/docs/images/tutorials/grant-scoped-stack-access/jordan-toolbar.png differ diff --git a/docs/images/tutorials/grant-scoped-stack-access/new-user-form.png b/docs/images/tutorials/grant-scoped-stack-access/new-user-form.png new file mode 100644 index 00000000..895eaceb Binary files /dev/null and b/docs/images/tutorials/grant-scoped-stack-access/new-user-form.png differ diff --git a/docs/images/tutorials/grant-scoped-stack-access/scope-added.png b/docs/images/tutorials/grant-scoped-stack-access/scope-added.png new file mode 100644 index 00000000..ea777443 Binary files /dev/null and b/docs/images/tutorials/grant-scoped-stack-access/scope-added.png differ diff --git a/docs/images/tutorials/grant-scoped-stack-access/scoped-permission-form.png b/docs/images/tutorials/grant-scoped-stack-access/scoped-permission-form.png new file mode 100644 index 00000000..f6d92dfe Binary files /dev/null and b/docs/images/tutorials/grant-scoped-stack-access/scoped-permission-form.png differ diff --git a/docs/tutorials/grant-scoped-stack-access.mdx b/docs/tutorials/grant-scoped-stack-access.mdx new file mode 100644 index 00000000..83c55c21 --- /dev/null +++ b/docs/tutorials/grant-scoped-stack-access.mdx @@ -0,0 +1,105 @@ +--- +title: Give a Teammate Deploy Access to One Stack, Not the Whole Fleet +sidebarTitle: Scope deploy access to one stack +description: Create a teammate account that can deploy and restart one stack, without editing its compose file, touching any other stack, or reaching system settings. +--- + +Say a new on-call engineer needs to be able to restart `support-portal` at 2 AM without waking you up, but they have no business editing its compose file, deleting stacks, or managing users. This walks through creating that account, granting it a scoped Deployer permission on `support-portal` alone, and confirming from the teammate's own session that the access is exactly as narrow as intended: they can act on the one stack they were granted, and nothing else. + +## Prerequisites + +- The `admin` role. Creating accounts and granting scoped permissions is Admin-only, on every tier. +- A running stack to scope the permission to. This tutorial uses a small stack called `support-portal`: + + ```yaml + services: + web: + image: nginx:alpine + restart: unless-stopped + ports: + - "8097:80" + depends_on: + - db + db: + image: postgres:16-alpine + restart: unless-stopped + environment: + POSTGRES_PASSWORD: supportportal + ``` + +- Available on Community and Admiral. Both tiers ship the same five built-in roles and the same additive stack and node scopes; nothing here requires a paid plan. + + + Stack scopes are node-specific: granting Deployer on `support-portal` authorizes only that stack name on the node you pick in the next section. The same stack name on a different node needs its own grant. If your fleet has more than one node, keep this in mind when you choose the node in Step 2. + + + + + Open your avatar in the top-right corner, choose **Settings**, then under **Access** pick **Users**. Click **Add user**. + + Fill in a **Username** (for example `jordan`), leave **Role** at its default of **Viewer** (the floor you'll add the scoped permission on top of), and set a **Password**. Leaving the global role at Viewer, rather than picking Deployer here, is the point: the account starts with read-only access everywhere, and the next step grants deploy rights on exactly one stack. + + + The New User form in Settings Users, with Username jordan, Role combobox defaulting to Viewer, and Password and Confirm Password fields filled. + + + Click **Create user**. The table refreshes with the new row. + + + Click the pencil icon on the new user's row to open **Edit User**. A **Scoped Permissions** box appears below the form. + + Set **Role** to **Deployer**, **Resource Type** to **Stack**, pick the **Node** that hosts `support-portal`, then pick **support-portal** in the **Stack** field that unlocks once a node is selected. + + + The Scoped Permissions form filled in: Role Deployer, Resource Type Stack, Node Local, Stack support-portal, with the Add button enabled. + + + Click **Add**. A toast confirms the scope was added, and it appears as a row above the form. + + + Log out and sign in as the account you just created. Open the `support-portal` stack: **Restart**, **Stop**, **Take down**, and **Update** all appear in the toolbar, matching the Deployer permission you granted. + + + The support-portal stack as the teammate account, with Restart, Stop, Take down, and Update buttons in the toolbar. + + + Open the `compose.yaml` tab. The file is visible (Viewer's global `stack:read` covers this), but there is no **Save & Deploy** button and no **Git Source** button, the way there would be for an account with `stack:edit`, only a close icon. + + + The compose.yaml tab as the teammate account, showing the file contents with only a close icon in the toolbar and no Save or Git Source button. + + + Click **Restart** to confirm the granted action actually works, then open a stack you did *not* grant a scope on. Its toolbar has no deploy actions at all: the scope really is limited to the one stack. + + + +## Verify it worked + +Check from two places, since a single screen showing "it looks right" isn't proof the permission is actually enforced. + +**The scope itself.** Sign back in as an admin, reopen the teammate's user record from **Settings · Users**, and confirm the Scoped Permissions box lists `deployer` on `stack: support-portal` for the node you picked. + + + The Edit User panel's Scoped Permissions box showing one row: deployer on stack support-portal at Local, with a trash icon to remove it. + + +**The audit log.** Open **Audit** from the navigation's **More** menu. Two entries confirm the setup, both attributed to your account: a **created user** entry (`POST /api/users`) and an **assigned role** entry (`POST /api/users/:id/roles`). If the teammate restarted the stack in Step 3, a third entry and a `manual` count on the dashboard's **Stack Restarts (7d)** card confirm the permission was exercised, not just granted. + + + Audit log showing entries for assigning a role (POST /api/users/3/roles) and creating a user (POST /api/users), both attributed to the admin account. + + +## If something goes wrong + +**The teammate says they can't deploy the stack you scoped them to.** The two most common causes are both silent: the scope was added for the wrong node (stack scopes are node-specific, and a multi-node fleet's node picker is easy to skip past), or the stack name doesn't match exactly (names are case-sensitive, though the picker prevents typos since it lists real stacks). Reopen the user's **Edit User** panel and check the existing-scope row reads the resource and node you expect. If it doesn't, remove it with the trash icon and add it again with the correct node selected first. See [RBAC & User Management · Troubleshooting](/features/rbac#troubleshooting) for the other ways a scoped assignment can fail to apply. + +## Related + + + + The full permission matrix, all five built-in roles, session security, and SSO auto-provisioning. + + + Provision accounts automatically from your identity provider instead of creating them one at a time. + +