You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/concepts/authorization/assigning-roles-stacks.md
+77-33Lines changed: 77 additions & 33 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,4 +1,4 @@
1
-
# Stack role attachments
1
+
# Stack role bindings
2
2
3
3
Stacks can receive role bindings to perform operations with elevated permissions, similar to how users, API keys, and IdP groups receive permissions through [Spacelift's RBAC system](rbac-system.md).
4
4
@@ -32,9 +32,9 @@ This means a stack can create contexts and worker pools, but cannot manage any o
32
32
33
33
**Administrative flag**: Basic audit trail with stack actor information.
34
34
35
-
**Role attachments advantage**: Audit trail webhooks include role information in the `ActorRoles` field (array of role slugs).
35
+
**Role attachments advantage**: Audit trail webhooks include role information in the `actor_roles` field (array of role slugs).
36
36
37
-
This provides better visibility into what permissions the stack was using when performing actions. See the [audit trail documentation](../../integrations/audit-trail.md) for details.
37
+
This provides better visibility into what permissions the stack was using when performing actions. See the [audit trail documentation](../../integrations/audit-trail.md#usage) for details.
38
38
39
39
### Modern RBAC consistency
40
40
@@ -46,8 +46,8 @@ Role attachments align stacks with the broader role-based access model already u
46
46
47
47
To attach a role to a stack, you need:
48
48
49
-
-`StackManage` permission (or `SpaceAdmin` permission as fallback) to the stack's space
50
-
-`SpaceAdmin` permission to the binding space (the space where the role will be effective)
49
+
-`StackManage`[permission](./rbac-system.md#actions-the-building-blocks-of-permissions) (or Space admin permission as fallback) to the stack's space
50
+
-Space admin permission to the binding space (the space where the role will be effective)
51
51
52
52
!!! info "Why both permissions are required"
53
53
Creating a role binding that grants permissions to a space effectively allows the stack to act in that space. To prevent privilege escalation, you must have admin access to both spaces: the space where the stack resides and the space where the role will be effective.
@@ -64,49 +64,78 @@ To attach a role to a stack, you need:
64
64
Use the `spacelift_role_attachment` resource:
65
65
66
66
```hcl
67
-
resource "spacelift_stack" "admin" {
68
-
name = "Admin stack"
69
-
repository = "spacelift-resources"
67
+
resource "spacelift_space" "devops" {
68
+
name = "devops"
69
+
description = "A space for devops engineers"
70
+
parent_space_id = "root"
71
+
}
72
+
73
+
resource "spacelift_stack" "devops_admin" {
74
+
name = "Admin stacks for Devs"
75
+
repository = "spacelift-dev-resources"
76
+
space_id = spacelift_space.devops.id
70
77
description = "Only has permissions to create another stacks in the dev space"
2. The [role](./rbac-system.md#roles) to attach to the stack.
103
+
3. The target space: this is where the role will be effective.
104
+
105
+
In the above scenario, the `devops_admin` stack will have the `Stack creator` role effective in the `dev` space, allowing it to create and manage stacks within that space.
106
+
92
107
For more information, see the [Spacelift Terraform provider documentation](https://search.opentofu.org/provider/spacelift-io/spacelift/latest/docs/resources/role_attachment){: rel="nofollow"}.
93
108
94
109
## Permission cascading
95
110
96
111
Role attachments cascade down to child spaces, similar to how the administrative flag worked:
97
112
98
-
```text
99
-
parentSpace
100
-
├── childSpace1
101
-
└── childSpace2
102
-
└── grandchildSpace
113
+
```mermaid
114
+
graph TD
115
+
role{{Role}}
116
+
parentSpace[ParentSpace]
117
+
childSpace1[ChildSpace1]
118
+
childSpace2[ChildSpace2]
119
+
grandchildSpace[GrandchildSpace]
120
+
121
+
role ~~~ parentSpace
122
+
role e1@-. Attached to .-> parentSpace
123
+
e1@{animate: true}
124
+
parentSpace --> childSpace1
125
+
parentSpace --> childSpace2
126
+
childSpace2 --> grandchildSpace
103
127
```
104
128
105
-
If a role is attached to `parentSpace`, the same role will be effective in `childSpace1`, `childSpace2`, and `grandchildSpace`.
129
+
If a role is attached to `ParentSpace`, the same role will be effective in `ChildSpace1`, `ChildSpace2`, and `GrandchildSpace` as well.
106
130
107
-
!!! warning "Root space caution"
131
+
!!! danger "Root space caution"
108
132
Since the `root` space is the parent of all spaces, attaching roles to it affects **all spaces** in your account. Use this with extreme caution and only when necessary.
109
133
134
+
### Root space restriction
135
+
136
+
You can only assign a role to the `root` space if the stack itself is located in the `root` space. This restriction prevents unintentional access elevation - a stack in a _child-of-root_ space cannot be granted permissions that cascade to all spaces in your account.
137
+
If you need a stack in a child space to access resources across multiple spaces, attach roles to specific spaces rather than the root space.
138
+
110
139
## Administrative flag precedence
111
140
112
141
The administrative flag takes precedence over role attachments:
@@ -126,10 +155,12 @@ package spacelift
126
155
127
156
reject_with_note["Don't use the Space Admin role!"] {
128
157
role := input.stack.roles[_]
129
-
role.id == "space-admin" # Role slug. Use the "Copy Slug" button in the UI to get it.
158
+
role.id == "space-admin" # (1)
130
159
}
131
160
```
132
161
162
+
1. Role slug. Use either "Copy Slug" button in the UI or the [`spacelift_role` data source](https://search.opentofu.org/provider/spacelift-io/spacelift/latest/docs/datasources/role){: rel="nofollow"} to retrieve it.
External state access allows you to read the state of the stack from outside authorized runs and [tasks](../../concepts/run/task.md). See the documentation [here](../../vendors/terraform/external-state-access.md) for further details.
192
+
External state access allows you to read the state of a stack from outside authorized runs and tasks. See the documentation [here](../../vendors/terraform/external-state-access.md) for further details.
162
193
163
194
In order for your stack to access another stack's OpenTofu/Terraform state, the stack needs to have **Space writer** role to the target stack's space. This can be achieved by attaching the **Space writer** role to the stack for the target stack's space.
The **Space admin** role also includes **Space writer** permissions.
220
+
The Space admin role also includes Space writer permissions.
181
221
182
222
## Migration from administrative flag
183
223
184
-
!!! warning "Automatic Migration on June 1st, 2026"
185
-
On June 1st, 2026, Spacelift will automatically disable all administrative flags and attach the Space Admin role to each stack's own space. This automatic migration is **100% backward compatible** and ensures no functionality loss.
224
+
On June 1st, 2026, Spacelift will automatically disable all administrative flags and attach the Space Admin role to each stack's own space. This automatic migration is **100% backward compatible** and ensures no functionality loss.
186
225
187
-
However, **manual migration is strongly recommended** to take advantage of advanced features like cross-space access and fine-grained permissions that are not available with automatic migration.
226
+
However, **manual migration is strongly recommended** to avoid breaking the OpenTofu/Terraform state: since the administrative flag will be disabled during this process, the stacks will experience a drift. The administrative flag will be ineffective (even if set to true, it'll return false), so the only solution to reconcile will be to attach the Space Admin role to the stack's own space.
227
+
228
+
!!! note
229
+
The Space admin role is a built-in system role so you don't need to create it manually, it already exists in your Spacelift account.
188
230
189
231
### What happens on June 1st, 2026
190
232
@@ -231,19 +273,19 @@ Assuming your stack is in the `dev` [Space](../spaces/README.md), the role attac
Once you've verified the roles have been attached, disable the administrative flag:
278
+
Once you've verified the roles have been attached, remove the administrative attibute:
237
279
238
-
```hcl
280
+
```diff
239
281
resource "spacelift_stack" "management" {
240
-
# [... other stack settings ...]
241
-
administrative = false
282
+
name = "Management Stack"
283
+
- administrative = true
242
284
}
243
285
```
244
286
245
287
!!! important
246
-
The administrative flag takes precedence over role attachments. If `administrative = true`, any attached roles will be ignored. You must set `administrative = false` for role attachments to take effect.
288
+
The administrative flag takes precedence over role attachments. If `administrative = true`, any attached roles will be ignored. You must either set `administrative = false`, or entirely remove the administrative attribute (recommended) for role attachments to take effect.
247
289
248
290
#### 4. Verify the role attachment
249
291
@@ -263,10 +305,12 @@ deny_with_note["Administrative stacks are not allowed"] {
263
305
# Would become:
264
306
deny_with_note["Administrative stacks are not allowed"] {
265
307
role := input.stack.roles[_]
266
-
role.id == "space-admin" # Role slug. Use the "Copy Slug" button in the UI to get it.
308
+
role.id == "space-admin" # (1)
267
309
}
268
310
```
269
311
312
+
1. Role slug. Use either "Copy Slug" button in the UI or the [`spacelift_role` data source](https://search.opentofu.org/provider/spacelift-io/spacelift/latest/docs/datasources/role){: rel="nofollow"} to retrieve it.
0 commit comments