PoC (Do Not Merge)
Description
This PR introduces a proof of concept for the support of deleting prebuilt workspaces by enhancing the Rego policy. It modifies the Rego policy to dynamically detect and enforce permissions for prebuilt workspaces based on ownership (owner_id = PREBUILD_SYSTEM_USER_ID
). This approach allows authorization logic for prebuilt workspaces to be fully handled within Rego, with no changes required to application-level authorization logic or SQL query construction.
When a user attempts to perform an action on a workspace resource, Rego first checks whether the workspace is a prebuilt. If it is, it dynamically includes theprebuilt_workspace
resource type in the set of permissions being evaluated. This means:
- A user with
workspace
permissions will be able to perform actions on both normal and prebuilt workspaces. - A user with only
prebuilt_workspace
permissions will be able to perform actions exclusively on prebuilt workspaces.
This behavior is transparent to developers and maintains compatibility with current role definitions and authorization flows.
This PoC PR is based on the initial PoC proposal#18079.
Changes
- Added a new
is_prebuild_workspace
rule to detect prebuilt workspaces based on ownership. - Updated the role and scope associated rules for
site
,org
anduser
levels to:- Dynamically include
prebuilt_workspace
in the permission set ifis_prebuild_workspace
is true. - Default to
default_object_set
which contains[input.object.type, "*"]
- No changes to application code or SQL query construction.
- Authorization logic for all other resource types remains unchanged.
- Added a
benchmarks/
folder containing benchmark results andbenchstat
comparisons for performance evaluation.
Benchmark tests
Performance was evaluated using the RBAC benchmark tests incoderd/rbac/authz_test.go
:
- ✅
BenchmarkRBACAuthorize
andBenchmarkRBACAuthorizeGroups
(full evaluation): No measurable impact. - ⚠️
BenchmarkRBACFilter
(partial evaluation used in SQL filtering): Noticeable slowdown due to added logic for conditionally including theprebuilt_workspace
resource type.
Setup
Benchmark tests were conducted in a workspace setup ofhttps://dev.coder.com/
goos: linuxgoarch: amd64pkg: github.com/coder/coder/v2/coderd/rbaccpu: AMD EPYC 9454P 48-Core Processor
using the Go test tool with the following configurations:
GOMAXPROCS=16
: Limits the number of OS threads that can execute user-level Go code simultaneously to 16, enabling parallelism for performance testing on multi-core machines.timeout 30m
: Sets the maximum allowed time for the test run to 30 minutes to avoid premature test termination during long benchmark runs.benchtime=5s
: Each benchmark iteration runs for 5 seconds to gather stable and statistically meaningful performance data.count=5
: Runs the benchmark 5 times to average out noise and get consistent results.
An example command used:
> GOMAXPROCS=16 go test -timeout 30m -bench '^BenchmarkRBACFilter$' -run=^$ -benchtime=5s -count=5
The base benchmark was taken on the main branch at commitaf4a668
to serve as a performance baseline for comparison.
To analyze performance differences between the baseline (main) and the proposed changes (PoC),benchstat was used to compare the benchmark outputs.
The following tables show the average time it takes to perform a single authorization operation (sec/op). The first column (main) represents the baseline performance, and the second column (PoC) shows the performance of the new implementation compared to the baseline. The times are shown in microseconds (µs).
Full evaluation (BenchmarkRBACAuthorize
andBenchmarkRBACAuthorizeGroups
)
Benchmark | main (sec/op) | PoC (sec/op) | PoC vs base |
---|
BenchmarkRBACAuthorize | 3.860µ | 3.958µ | +2.54% |
BenchmarkRBACAuthorizeGroups | 11.36µ | 11.01µ | -3.06% |
In this case,BenchmarkRBACAuthorize
is 2.54% slower, whileBenchmarkRBACAuthorizeGroups
is 3.06% faster.
Partial evaluation (BenchmarkRBACFilter
)
Benchmark | main (sec/op) | PoC (sec/op) | PoC vs base |
---|
BenchmarkRBACFilter | 212.7µ | 1.136m | +434.09% |
In this case,BenchmarkRBACFilter
is significantly slower in the new implementation, with a +434.09% increase in execution time, roughly 6 times slower than the baseline.
The slowdown occurs becauseinput.object.owner
is unknown during partial evaluation, and OPA depends on this value to determine which permission set to apply. This causes OPA to split the evaluation into two primary branches: (1) evaluating the subject’s roles, and (2) evaluating the subject’s scope. Additionally, each of these branches further splits depending on whether the workspace is a normal or a prebuilt workspace. This branching is not a limitation of Rego itself but rather an inevitable consequence of the policy definition, which explicitly requires validating two distinct permission sets (input.subject.roles
andinput.subject.scope
) while also depending on the unknowninput.object.owner
to generate those sets correctly. Consequently, the partial evaluation generates a large number of partial queries, often duplicated due to the interaction between the role-scope branching and the unknown workspace type.
This impact is limited to workspace authorization and does not affect other resource types.
Note: Abenchmarks/
folder was added incoderd/rbac/
in this PR containing the benchmark results as well as the output frombenchstat
comparing the performance between main and this PoC branch.
Uh oh!
There was an error while loading.Please reload this page.
PoC (Do Not Merge)
Description
This PR introduces a proof of concept for the support of deleting prebuilt workspaces by enhancing the Rego policy. It modifies the Rego policy to dynamically detect and enforce permissions for prebuilt workspaces based on ownership (
owner_id = PREBUILD_SYSTEM_USER_ID
). This approach allows authorization logic for prebuilt workspaces to be fully handled within Rego, with no changes required to application-level authorization logic or SQL query construction.When a user attempts to perform an action on a workspace resource, Rego first checks whether the workspace is a prebuilt. If it is, it dynamically includes the
prebuilt_workspace
resource type in the set of permissions being evaluated. This means:workspace
permissions will be able to perform actions on both normal and prebuilt workspaces.prebuilt_workspace
permissions will be able to perform actions exclusively on prebuilt workspaces.This behavior is transparent to developers and maintains compatibility with current role definitions and authorization flows.
This PoC PR is based on the initial PoC proposal#18079.
Changes
is_prebuild_workspace
rule to detect prebuilt workspaces based on ownership.site
,org
anduser
levels to:prebuilt_workspace
in the permission set ifis_prebuild_workspace
is true.default_object_set
which contains[input.object.type, "*"]
benchmarks/
folder containing benchmark results andbenchstat
comparisons for performance evaluation.Benchmark tests
Performance was evaluated using the RBAC benchmark tests in
coderd/rbac/authz_test.go
:BenchmarkRBACAuthorize
andBenchmarkRBACAuthorizeGroups
(full evaluation): No measurable impact.BenchmarkRBACFilter
(partial evaluation used in SQL filtering): Noticeable slowdown due to added logic for conditionally including theprebuilt_workspace
resource type.Setup
Benchmark tests were conducted in a workspace setup ofhttps://dev.coder.com/
using the Go test tool with the following configurations:
GOMAXPROCS=16
: Limits the number of OS threads that can execute user-level Go code simultaneously to 16, enabling parallelism for performance testing on multi-core machines.timeout 30m
: Sets the maximum allowed time for the test run to 30 minutes to avoid premature test termination during long benchmark runs.benchtime=5s
: Each benchmark iteration runs for 5 seconds to gather stable and statistically meaningful performance data.count=5
: Runs the benchmark 5 times to average out noise and get consistent results.An example command used:
The base benchmark was taken on the main branch at commit
af4a668
to serve as a performance baseline for comparison.To analyze performance differences between the baseline (main) and the proposed changes (PoC),benchstat was used to compare the benchmark outputs.
The following tables show the average time it takes to perform a single authorization operation (sec/op). The first column (main) represents the baseline performance, and the second column (PoC) shows the performance of the new implementation compared to the baseline. The times are shown in microseconds (µs).
Full evaluation (
BenchmarkRBACAuthorize
andBenchmarkRBACAuthorizeGroups
)In this case,
BenchmarkRBACAuthorize
is 2.54% slower, whileBenchmarkRBACAuthorizeGroups
is 3.06% faster.Partial evaluation (
BenchmarkRBACFilter
)In this case,
BenchmarkRBACFilter
is significantly slower in the new implementation, with a +434.09% increase in execution time, roughly 6 times slower than the baseline.The slowdown occurs because
input.object.owner
is unknown during partial evaluation, and OPA depends on this value to determine which permission set to apply. This causes OPA to split the evaluation into two primary branches: (1) evaluating the subject’s roles, and (2) evaluating the subject’s scope. Additionally, each of these branches further splits depending on whether the workspace is a normal or a prebuilt workspace. This branching is not a limitation of Rego itself but rather an inevitable consequence of the policy definition, which explicitly requires validating two distinct permission sets (input.subject.roles
andinput.subject.scope
) while also depending on the unknowninput.object.owner
to generate those sets correctly. Consequently, the partial evaluation generates a large number of partial queries, often duplicated due to the interaction between the role-scope branching and the unknown workspace type.This impact is limited to workspace authorization and does not affect other resource types.
Note: A
benchmarks/
folder was added incoderd/rbac/
in this PR containing the benchmark results as well as the output frombenchstat
comparing the performance between main and this PoC branch.