Skip to content

Kubernetes: add instance-wide default and enforced Security Context#6310

Draft
Aex12 wants to merge 2 commits into
woodpecker-ci:mainfrom
Aex12:feat/kubernetes-security-context-flags
Draft

Kubernetes: add instance-wide default and enforced Security Context#6310
Aex12 wants to merge 2 commits into
woodpecker-ci:mainfrom
Aex12:feat/kubernetes-security-context-flags

Conversation

@Aex12

@Aex12 Aex12 commented Mar 23, 2026

Copy link
Copy Markdown
Contributor

This PR depends on PR #6307 being merged first.

Description

Currently, when using the Kubernetes backend, there is no mechanism for instance owners to define an instance-wide Security Context that applies to all CI workloads running in the cluster.

This poses several problems:

  • Repository maintainers are responsible for configuring their workflows to adhere to Pod Security Standards when running workloads in an unprivileged namespace.
  • Workflow files are cluttered with securityContext options, which could be defined globally (as this PR does)
  • If the namespace where workload pods are run is privileged, individual repositories can make their workflows run as root, posing potential security issues for the rest of the cluster.
  • If the namespace where workload pods are run is unprivileged and a repository fails to set the correct securityContext for their workflow, it'll never execute.

This PR tries to fix this by allowing instance owners to define two new variables on the agent:

  • WOODPECKER_BACKEND_K8S_DEFAULT_SECCTX: This is the securityContext that will be applied by default to all CI workloads running in the cluster, and it can be overridden by workflows.
  • WOODPECKER_BACKEND_K8S_ENFORCED_SECCTX: This is the securityContext that will be applied to all CI workloads, it cannot be overridden by individual workflows.

An example configuration of this two variables that will allow running the ci workloads in an unprivileged namespace is:

WOODPECKER_BACKEND_K8S_DEFAULT_SECCTX='{"runAsUser":1000,"runAsGroup":1000,"fsGroup":1000,"fsGroupChangePolicy": "OnRootMismatch"}'
WOODPECKER_BACKEND_K8S_ENFORCED_SECCTX='{"privileged":false,"runAsNonRoot":true,"allowPrivilegeEscalation":false,"seccompProfile": {"type": "RuntimeDefault"}, "capabilities": {"drop": ["ALL"]}}'

Possible deprecations

This PR preserves the functionality of the existing BACKEND_K8S_SECCTX_NONROOT variable for backward compatibility purposes, however with this PR changes we can achieve the same functionality by setting

WOODPECKER_BACKEND_K8S_ENFORCED_SECCTX='{"runAsNonRoot":true}'

With the added advantage of it being more flexible for instance owners to configure a wider range of enforced security context options.

About the environment variable names

I decided to go with SECCTX to make it more consistent with the existing BACKEND_K8S_SECCTX_NONROOT, however I think it'll be more appropiate to use SECURITY_CONTEXT, to make the intent clear. What is your opinion about this?

Added documentation

This PR also includes a small guide that explains how to run CI workloads in unprivileged namespaces using the added functionality. Currently the guide includes a workaround for the unprivileged clone step as mentioned in #5346. If PR #6312 gets merged, we can safely remove that from the guide, as it'll become unnecessary.

@Aex12 Aex12 marked this pull request as draft March 23, 2026 23:29
@Aex12 Aex12 force-pushed the feat/kubernetes-security-context-flags branch from efc9339 to 310a379 Compare March 24, 2026 01:54
@woodpecker-bot

woodpecker-bot commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

Surge PR preview deployment succeeded. View it at https://woodpecker-ci-woodpecker-pr-6310.surge.sh

@codecov

codecov Bot commented Mar 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.26984% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 33.40%. Comparing base (cca72ce) to head (b8bfe37).
⚠️ Report is 15 commits behind head on main.

Files with missing lines Patch % Lines
pipeline/backend/kubernetes/kubernetes.go 60.00% 6 Missing and 2 partials ⚠️
pipeline/backend/kubernetes/pod.go 97.16% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6310      +/-   ##
==========================================
+ Coverage   33.26%   33.40%   +0.13%     
==========================================
  Files         420      420              
  Lines       28344    28413      +69     
==========================================
+ Hits         9428     9490      +62     
- Misses      18037    18042       +5     
- Partials      879      881       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Aex12 Aex12 force-pushed the feat/kubernetes-security-context-flags branch from b8bfe37 to 68354ea Compare April 1, 2026 17:20
6543 pushed a commit that referenced this pull request Apr 28, 2026
### Problem
When the working directory is set to a directory that doesn't exists (for example, as `plugin-git` does), kubelet will pre-create it with ownership set to `root:root` and permissions `0755` . This makes pods running as non-root unable to write to it, causing permission errors.

### Solution
Added a `podInitContainer` function that conditionally creates an init container to pre-create the working directory with the correct permissions before the main step container starts.

### Behavior
- If the pod runs as root (`RunAsUser == 0` or unset), no init container is created. Kubelet handles directory creation automatically
- If the working directory matches a volume mount path exactly, no init container is needed. `FSGroupChangePolicy` handles permissions
- An init container is only created when the working directory is nested within a volume mount path
- The init container uses `busybox:stable-musl` with minimal resource limits (5m CPU, 5Mi memory) and drops all capabilities.

### Related issues and PRs
- Solves the error mentioned in #5346 (comment) without requiring a previous step.
- In addition to #6307 and #6310, this will make it easier to run woodpecker ci workloads in a namespace that enforces [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/)
@6543

6543 commented May 27, 2026

Copy link
Copy Markdown
Member

#6307 got merged ...

@6543 6543 added the wip label May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants