Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: add prebuilt_workspace resource type logic in rego policy #18400

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

ssncferreira
Copy link
Contributor

@ssncferreira ssncferreira commented Jun 17, 2025

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:

  • 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 and user levels to:
    • Dynamically include prebuilt_workspace in the permission set if is_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 and benchstat comparisons for performance evaluation.

Benchmark tests

Performance was evaluated using the RBAC benchmark tests in coderd/rbac/authz_test.go:

  • BenchmarkRBACAuthorize and BenchmarkRBACAuthorizeGroups (full evaluation): No measurable impact.
  • ⚠️ BenchmarkRBACFilter (partial evaluation used in SQL filtering): Noticeable slowdown due to added logic for conditionally including the prebuilt_workspace resource type.

Setup

Benchmark tests were conducted in a workspace setup of https://dev.coder.com/

goos: linux
goarch: amd64
pkg: github.com/coder/coder/v2/coderd/rbac
cpu: 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 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 and BenchmarkRBACAuthorizeGroups)

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, while BenchmarkRBACAuthorizeGroups 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 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 and input.subject.scope) while also depending on the unknown input.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 in coderd/rbac/ in this PR containing the benchmark results as well as the output from benchstat comparing the performance between main and this PoC branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant