Skip to content

try to use userNamespaces to avoid having privileged workspaces#182

Merged
bennyz merged 2 commits into
centos-automotive-suite:mainfrom
bennyz:unprivileged
Mar 26, 2026
Merged

try to use userNamespaces to avoid having privileged workspaces#182
bennyz merged 2 commits into
centos-automotive-suite:mainfrom
bennyz:unprivileged

Conversation

@bennyz

@bennyz bennyz commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

On OCP 4.20 we can use userNamespace and avoid using privileged workspace pods, older version will defer to privileged for now

Summary by CodeRabbit

  • New Features

    • Introduced a dedicated "ado-build" ServiceAccount for build operations.
  • Improvements

    • Build and pipeline executions now run under the new ServiceAccount with updated RBAC bindings.
    • Workspace deployment detects cluster user-namespace support and adapts pod and security configuration accordingly.
    • Container security tightened: capability-based controls with a narrower allowlist; privileged SCCs applied only when required.

@coderabbitai

coderabbitai Bot commented Mar 25, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Added a dedicated build ServiceAccount (ado-build) and reportable UserNamespacesSupported status; replaced hardcoded pipeline SA references with the new constant across token minting, Tekton/Shipwright/Job specs, RBAC/SCC resources, and workspace security logic; introduced privileged/non-privileged workspace SCC variants.

Changes

Cohort / File(s) Summary
API Type Definition
api/v1alpha1/operatorconfig_types.go
Added exported constant BuildServiceAccountName = "ado-build" and OperatorConfigStatus.UserNamespacesSupported status field.
Token minting & build server
internal/buildapi/server.go
Replaced hardcoded SA name with BuildServiceAccountName for CreateToken calls; set TaskRun spec ServiceAccountName to BuildServiceAccountName; updated error messages.
Job/task generation
internal/common/tasks/tasks.go
Changed generated Job/Pod ServiceAccountName from "pipeline" to BuildServiceAccountName.
Shipwright / Image build controllers
internal/controller/containerbuild/controller.go, internal/controller/imagebuild/controller.go, internal/controller/imagereseal/controller.go
Set Shipwright BuildRunSpec.ServiceAccount and Tekton TaskRunTemplate.ServiceAccountName / PipelineRun templates to BuildServiceAccountName; preserve configured SA when applying node selectors.
OperatorConfig controller & SCC/RBAC resources
internal/controller/operatorconfig/controller.go, internal/controller/operatorconfig/resources.go, config/rbac/*rolebinding.yaml
Create/delete dedicated ado-build ServiceAccount; swap pipeline-specific SCC/RBAC artifacts to build-specific ones; update RoleBinding subjects to ado-build; add privileged and non-privileged workspace SCC constructors and adjust SCC capability lists and permissions.
Workspace security context
internal/controller/workspace/controller.go
Switch workspace pod security handling to depend on config.Status.UserNamespacesSupported: use capability-based non-privileged context when supported (explicit allowlist, ProcMount unmasked, allowPrivilegeEscalation), else fall back to privileged mode; set HostUsers accordingly.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant OperatorCtrl as Operator Ctrl
  participant K8sAPI as Kubernetes API
  participant TokenSvc as SA Token
  participant BuildSystem as Tekton/Shipwright
  participant Registry

  User->>OperatorCtrl: reconcile OperatorConfig (create build SA & workspace SCC)
  OperatorCtrl->>K8sAPI: create ServiceAccount `ado-build`
  OperatorCtrl->>K8sAPI: create/update workspace SCC (priv/non-priv variants)
  OperatorCtrl->>K8sAPI: read SCC -> determine UserNamespacesSupported
  OperatorCtrl-->>User: update OperatorConfig.Status.UserNamespacesSupported

  User->>BuildSystem: trigger build (PipelineRun / BuildRun)
  BuildSystem->>K8sAPI: request token for registry using SA `ado-build`
  K8sAPI->>TokenSvc: ServiceAccounts(namespace).CreateToken(ado-build)
  TokenSvc-->>BuildSystem: token
  BuildSystem->>Registry: push/pull using token
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • bkhizgiy

"I am a rabbit, hopping through the build,
I name the service account, tidy and skilled.
RBAC and SCC now follow my cue,
Capabilities chosen, privileges few—
Hooray for tidy builds and carrots anew! 🥕"

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main objective of the pull request: introducing user namespaces support to reduce reliance on privileged workspaces by adding UserNamespacesSupported status field and conditional security context logic.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/controller/operatorconfig/resources.go (1)

908-967: ⚠️ Potential issue | 🟠 Major

Add ado-build registry-editor RoleBinding.

The migration to ado-build ServiceAccount for internal-registry tokens (in internal/buildapi/server.go) is incomplete. The pipeline-registry-editor RoleBinding in config/rbac/pipeline_registry_rolebinding.yaml still targets only the pipeline ServiceAccount, but the code now creates tokens for ado-build. Without an equivalent registry-editor binding for ado-build, internal-registry authentication will fail.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/controller/operatorconfig/resources.go` around lines 908 - 967, The
code creates the ado-build ServiceAccount
(automotivev1alpha1.BuildServiceAccountName) but does not create a corresponding
registry-editor RoleBinding, so internal-registry tokens for ado-build will
fail; add a new function (e.g., buildBuildRegistryRoleBinding(namespace string)
*rbacv1.RoleBinding) that constructs a RoleBinding which references the same
registry-editor Role/ClusterRole used by the existing pipeline registry
RoleBinding (the role name from config/rbac/pipeline_registry_rolebinding.yaml)
and includes a Subject for automotivev1alpha1.BuildServiceAccountName in the
given namespace; return this RoleBinding from reconciliation where other build
RBs (e.g., buildBuildSCCRoleBinding) are created so ado-build receives the
registry-editor permissions.
🧹 Nitpick comments (1)
internal/controller/operatorconfig/resources.go (1)

25-26: Rename the leftover pipelineSCCBindingName symbol.

The value is build-specific now, but the identifier still points readers at the old model and makes the new helpers harder to follow.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/controller/operatorconfig/resources.go` around lines 25 - 26, The
constant pipelineSCCBindingName is misnamed for build-specific usage; rename it
to a clearer identifier (e.g., buildSCCBindingName or
buildPrivilegedSCCBindingName) and update all references to it across the
package (including any helper functions that consume pipelineSCCBindingName and
any tests or docs), leaving sccPrivilegedRoleName as-is; ensure you update
imports/usages and run unit tests to confirm no missing symbol errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/controller/workspace/controller.go`:
- Around line 232-239: The container capabilities currently only append to the
runtime defaults (using caps/Capabilities.Add), so the container still runs with
the full default capability set; update the pod spec where the Capabilities are
set (the caps slice and the usage of Capabilities.Add) to explicitly drop all
defaults first by setting Capabilities.Drop = ["ALL"] before setting
Capabilities.Add = caps (and keep the conditional append of "SYS_ADMIN" for
configuredImage); apply the same Drop addition to the other instance referenced
around the 320-324 region so the allowlist is enforced.

---

Outside diff comments:
In `@internal/controller/operatorconfig/resources.go`:
- Around line 908-967: The code creates the ado-build ServiceAccount
(automotivev1alpha1.BuildServiceAccountName) but does not create a corresponding
registry-editor RoleBinding, so internal-registry tokens for ado-build will
fail; add a new function (e.g., buildBuildRegistryRoleBinding(namespace string)
*rbacv1.RoleBinding) that constructs a RoleBinding which references the same
registry-editor Role/ClusterRole used by the existing pipeline registry
RoleBinding (the role name from config/rbac/pipeline_registry_rolebinding.yaml)
and includes a Subject for automotivev1alpha1.BuildServiceAccountName in the
given namespace; return this RoleBinding from reconciliation where other build
RBs (e.g., buildBuildSCCRoleBinding) are created so ado-build receives the
registry-editor permissions.

---

Nitpick comments:
In `@internal/controller/operatorconfig/resources.go`:
- Around line 25-26: The constant pipelineSCCBindingName is misnamed for
build-specific usage; rename it to a clearer identifier (e.g.,
buildSCCBindingName or buildPrivilegedSCCBindingName) and update all references
to it across the package (including any helper functions that consume
pipelineSCCBindingName and any tests or docs), leaving sccPrivilegedRoleName
as-is; ensure you update imports/usages and run unit tests to confirm no missing
symbol errors.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: defc076a-b25f-4169-b860-a6d216b6316f

📥 Commits

Reviewing files that changed from the base of the PR and between d11c83b and e7b8553.

📒 Files selected for processing (9)
  • api/v1alpha1/operatorconfig_types.go
  • internal/buildapi/server.go
  • internal/common/tasks/tasks.go
  • internal/controller/containerbuild/controller.go
  • internal/controller/imagebuild/controller.go
  • internal/controller/imagereseal/controller.go
  • internal/controller/operatorconfig/controller.go
  • internal/controller/operatorconfig/resources.go
  • internal/controller/workspace/controller.go

Comment thread internal/controller/workspace/controller.go Outdated
Signed-off-by: Benny Zlotnik <bzlotnik@redhat.com>
Assisted-by: claude-sonnet-4.6

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/controller/workspace/controller.go`:
- Around line 235-255: The fallback branch that sets secCtx.Privileged when
userNamespaces is false currently grants privileged mode to any workspace image;
change it so Privileged is only applied for the trusted toolchain image: in the
else branch of the userNamespaces check, test if image == configuredImage and
only then set secCtx = &corev1.SecurityContext{Privileged: ptr.To(true),
AllowPrivilegeEscalation: ptr.To(true)}; otherwise create a non-privileged
SecurityContext (e.g. secCtx = &corev1.SecurityContext{AllowPrivilegeEscalation:
ptr.To(true)}) so untrusted user-specified images cannot run privileged. Ensure
you update uses of secCtx accordingly (symbols: userNamespaces, operatorConfig,
image, configuredImage, secCtx, SecurityContext, Privileged).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3675624f-9356-44e3-80cf-18ef843ba9e2

📥 Commits

Reviewing files that changed from the base of the PR and between 4f828ba and 50c669e.

⛔ Files ignored due to path filters (1)
  • config/crd/bases/automotive.sdv.cloud.redhat.com_operatorconfigs.yaml is excluded by !config/crd/bases/**
📒 Files selected for processing (4)
  • api/v1alpha1/operatorconfig_types.go
  • internal/controller/operatorconfig/controller.go
  • internal/controller/operatorconfig/resources.go
  • internal/controller/workspace/controller.go

Comment thread internal/controller/operatorconfig/controller.go
Comment thread internal/controller/workspace/controller.go
on OCP 4.20+ we don't have to use privileged pods
to run nested podman

Signed-off-by: Benny Zlotnik <bzlotnik@redhat.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@api/v1alpha1/operatorconfig_types.go`:
- Around line 583-585: The new UserNamespacesSupported bool field added to the
OperatorConfig status type (UserNamespacesSupported) is not present in the
generated deepcopy implementations; regenerate the API artifacts so
zz_generated.deepcopy.go and CRD manifests include this field by running the
project codegen: regenerate deepcopy/clients/listers/informers by running the
generation targets (e.g., run make generate manifests) and commit the updated
generated files so the deepcopy methods for the OperatorConfig status include
UserNamespacesSupported.

In `@internal/controller/workspace/controller.go`:
- Around line 232-235: The current logic computes userNamespaces :=
operatorConfig != nil && operatorConfig.Status.UserNamespacesSupported which
conflates “not yet observed” and “explicitly unsupported”; change
ensurePod()/the workspace controller to treat operatorConfig.Status as unknown
until status.ObservedGeneration >= operatorConfig.Generation (or equivalent
reconciliation marker) and requeue the workspace reconcile when the
OperatorConfig status is not yet observed, so you only decide HostUsers /
container security context (and the userNamespaces boolean) after the
OperatorConfig status has caught up; alternatively introduce an explicit
tri-state (unknown/true/false) for userNamespaces and ensure the code path at
both occurrences (the userNamespaces assignment and the logic at lines
referenced) defers to requeue when unknown instead of taking the fallback.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 43669371-f40a-4b68-8c65-bfb1246ecc26

📥 Commits

Reviewing files that changed from the base of the PR and between 50c669e and 87afaf2.

⛔ Files ignored due to path filters (1)
  • config/crd/bases/automotive.sdv.cloud.redhat.com_operatorconfigs.yaml is excluded by !config/crd/bases/**
📒 Files selected for processing (4)
  • api/v1alpha1/operatorconfig_types.go
  • internal/controller/operatorconfig/controller.go
  • internal/controller/operatorconfig/resources.go
  • internal/controller/workspace/controller.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/controller/operatorconfig/controller.go
  • internal/controller/operatorconfig/resources.go

Comment thread api/v1alpha1/operatorconfig_types.go
Comment thread internal/controller/workspace/controller.go
@bennyz bennyz requested a review from bkhizgiy March 26, 2026 09:17
@bennyz bennyz merged commit cf96e5b into centos-automotive-suite:main Mar 26, 2026
4 checks passed
@bennyz bennyz deleted the unprivileged branch March 26, 2026 10:48
@coderabbitai coderabbitai Bot mentioned this pull request Apr 26, 2026
10 tasks
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.

2 participants