Add fsGroupChangePolicy option to Kubernetes backend (#5416)

Co-authored-by: Lilly Sell <sell@b1-systems.de>
This commit is contained in:
Robert Kaussow 2025-08-15 10:28:38 +02:00 committed by GitHub
parent 8912f8989c
commit dc7795e64b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 41 additions and 24 deletions

View file

@ -250,6 +250,15 @@ backend_options:
localhostProfile: k8s-apparmor-example-deny-write
```
or configure a specific `fsGroupChangePolicy` (Kubernetes defaults to 'Always')
```yaml
backend_options:
kubernetes:
securityContext:
fsGroupChangePolicy: OnRootMismatch
```
:::note
The feature requires Kubernetes v1.30 or above.
:::

View file

@ -2,6 +2,7 @@ package kubernetes
import (
"github.com/go-viper/mapstructure/v2"
v1 "k8s.io/api/core/v1"
backend "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types"
)
@ -50,13 +51,14 @@ const (
)
type SecurityContext struct {
Privileged *bool `mapstructure:"privileged"`
RunAsNonRoot *bool `mapstructure:"runAsNonRoot"`
RunAsUser *int64 `mapstructure:"runAsUser"`
RunAsGroup *int64 `mapstructure:"runAsGroup"`
FSGroup *int64 `mapstructure:"fsGroup"`
SeccompProfile *SecProfile `mapstructure:"seccompProfile"`
ApparmorProfile *SecProfile `mapstructure:"apparmorProfile"`
Privileged *bool `mapstructure:"privileged"`
RunAsNonRoot *bool `mapstructure:"runAsNonRoot"`
RunAsUser *int64 `mapstructure:"runAsUser"`
RunAsGroup *int64 `mapstructure:"runAsGroup"`
FSGroup *int64 `mapstructure:"fsGroup"`
FsGroupChangePolicy *v1.PodFSGroupChangePolicy `mapstructure:"fsGroupChangePolicy"`
SeccompProfile *SecProfile `mapstructure:"seccompProfile"`
ApparmorProfile *SecProfile `mapstructure:"apparmorProfile"`
}
type SecProfile struct {

View file

@ -462,12 +462,13 @@ func toleration(backendToleration Toleration) v1.Toleration {
func podSecurityContext(sc *SecurityContext, secCtxConf SecurityContextConfig, stepPrivileged bool) *v1.PodSecurityContext {
var (
nonRoot *bool
user *int64
group *int64
fsGroup *int64
seccomp *v1.SeccompProfile
apparmor *v1.AppArmorProfile
nonRoot *bool
user *int64
group *int64
fsGroup *int64
fsGroupChangePolicy *v1.PodFSGroupChangePolicy
seccomp *v1.SeccompProfile
apparmor *v1.AppArmorProfile
)
if secCtxConf.RunAsNonRoot {
@ -505,6 +506,7 @@ func podSecurityContext(sc *SecurityContext, secCtxConf SecurityContextConfig, s
seccomp = seccompProfile(sc.SeccompProfile)
apparmor = apparmorProfile(sc.ApparmorProfile)
fsGroupChangePolicy = sc.FsGroupChangePolicy
}
if nonRoot == nil && user == nil && group == nil && fsGroup == nil && seccomp == nil && apparmor == nil {
@ -512,12 +514,13 @@ func podSecurityContext(sc *SecurityContext, secCtxConf SecurityContextConfig, s
}
securityContext := &v1.PodSecurityContext{
RunAsNonRoot: nonRoot,
RunAsUser: user,
RunAsGroup: group,
FSGroup: fsGroup,
SeccompProfile: seccomp,
AppArmorProfile: apparmor,
RunAsNonRoot: nonRoot,
RunAsUser: user,
RunAsGroup: group,
FSGroup: fsGroup,
FSGroupChangePolicy: fsGroupChangePolicy,
SeccompProfile: seccomp,
AppArmorProfile: apparmor,
}
log.Trace().Msgf("pod security context that will be used: %v", securityContext)
return securityContext

View file

@ -293,6 +293,7 @@ func TestFullPod(t *testing.T) {
"runAsGroup": 101,
"runAsNonRoot": true,
"fsGroup": 101,
"fsGroupChangePolicy": "OnRootMismatch",
"appArmorProfile": {
"type": "Localhost",
"localhostProfile": "k8s-apparmor-example-deny-write"
@ -348,12 +349,14 @@ func TestFullPod(t *testing.T) {
{Number: 2345, Protocol: "tcp"},
{Number: 3456, Protocol: "udp"},
}
fsGroupChangePolicy := v1.PodFSGroupChangePolicy("OnRootMismatch")
secCtx := SecurityContext{
Privileged: newBool(true),
RunAsNonRoot: newBool(true),
RunAsUser: newInt64(101),
RunAsGroup: newInt64(101),
FSGroup: newInt64(101),
Privileged: newBool(true),
RunAsNonRoot: newBool(true),
RunAsUser: newInt64(101),
RunAsGroup: newInt64(101),
FSGroup: newInt64(101),
FsGroupChangePolicy: &fsGroupChangePolicy,
SeccompProfile: &SecProfile{
Type: "Localhost",
LocalhostProfile: "profiles/audit.json",