You've already forked woodpecker
							
							
				mirror of
				https://github.com/woodpecker-ci/woodpecker.git
				synced 2025-10-30 23:27:39 +02:00 
			
		
		
		
	Simple security context options (Kubernetes) (#2550)
This commit is contained in:
		| @@ -42,6 +42,10 @@ agent: | ||||
|  | ||||
|   Additional annotations to apply to worker pods. Must be a YAML object, e.g. `{"example.com/test-annotation":"test-value"}`. | ||||
|  | ||||
| - `WOODPECKER_BACKEND_K8S_SECCTX_NONROOT` (default: `false`) | ||||
|  | ||||
|   Determines if containers must be required to run as non-root users. | ||||
|  | ||||
| ## Job specific configuration | ||||
|  | ||||
| ### Resources | ||||
|   | ||||
| @@ -57,6 +57,11 @@ var Flags = []cli.Flag{ | ||||
| 		Usage:   "backend k8s additional worker pod annotations", | ||||
| 		Value:   "", | ||||
| 	}, | ||||
| 	&cli.BoolFlag{ | ||||
| 		EnvVars: []string{"WOODPECKER_BACKEND_K8S_SECCTX_NONROOT"}, | ||||
| 		Name:    "backend-k8s-secctx-nonroot", | ||||
| 		Usage:   "`run as non root` Kubernetes security context option", | ||||
| 	}, | ||||
| 	&cli.IntFlag{ | ||||
| 		EnvVars: []string{"WOODPECKER_CONNECT_RETRY_COUNT"}, | ||||
| 		Name:    "connect-retry-count", | ||||
|   | ||||
| @@ -55,12 +55,16 @@ type kube struct { | ||||
| } | ||||
|  | ||||
| type Config struct { | ||||
| 	Namespace      string | ||||
| 	StorageClass   string | ||||
| 	VolumeSize     string | ||||
| 	StorageRwx     bool | ||||
| 	PodLabels      map[string]string | ||||
| 	PodAnnotations map[string]string | ||||
| 	Namespace       string | ||||
| 	StorageClass    string | ||||
| 	VolumeSize      string | ||||
| 	StorageRwx      bool | ||||
| 	PodLabels       map[string]string | ||||
| 	PodAnnotations  map[string]string | ||||
| 	SecurityContext SecurityContextConfig | ||||
| } | ||||
| type SecurityContextConfig struct { | ||||
| 	RunAsNonRoot bool | ||||
| } | ||||
|  | ||||
| func configFromCliContext(ctx context.Context) (*Config, error) { | ||||
| @@ -73,6 +77,9 @@ func configFromCliContext(ctx context.Context) (*Config, error) { | ||||
| 				StorageRwx:     c.Bool("backend-k8s-storage-rwx"), | ||||
| 				PodLabels:      make(map[string]string), // just init empty map to prevent nil panic | ||||
| 				PodAnnotations: make(map[string]string), // just init empty map to prevent nil panic | ||||
| 				SecurityContext: SecurityContextConfig{ | ||||
| 					RunAsNonRoot: c.Bool("backend-k8s-secctx-nonroot"), | ||||
| 				}, | ||||
| 			} | ||||
| 			// Unmarshal label and annotation settings here to ensure they're valid on startup | ||||
| 			if labels := c.String("backend-k8s-pod-labels"); labels != "" { | ||||
| @@ -191,7 +198,7 @@ func (e *kube) SetupWorkflow(ctx context.Context, conf *types.Config, taskUUID s | ||||
|  | ||||
| // Start the pipeline step. | ||||
| func (e *kube) StartStep(ctx context.Context, step *types.Step, taskUUID string) error { | ||||
| 	pod, err := Pod(e.config.Namespace, step, e.config.PodLabels, e.config.PodAnnotations, e.goos) | ||||
| 	pod, err := Pod(e.config.Namespace, step, e.config.PodLabels, e.config.PodAnnotations, e.goos, e.config.SecurityContext) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|   | ||||
| @@ -28,7 +28,7 @@ import ( | ||||
| 	"go.woodpecker-ci.org/woodpecker/pipeline/backend/types" | ||||
| ) | ||||
|  | ||||
| func Pod(namespace string, step *types.Step, labels, annotations map[string]string, goos string) (*v1.Pod, error) { | ||||
| func Pod(namespace string, step *types.Step, labels, annotations map[string]string, goos string, secCtxConf SecurityContextConfig) (*v1.Pod, error) { | ||||
| 	var ( | ||||
| 		vols       []v1.Volume | ||||
| 		volMounts  []v1.VolumeMount | ||||
| @@ -142,6 +142,11 @@ func Pod(namespace string, step *types.Step, labels, annotations map[string]stri | ||||
| 		log.Trace().Msgf("Tolerations that will be used in the backend options: %v", beTolerations) | ||||
| 	} | ||||
|  | ||||
| 	beSecurityContext := step.BackendOptions.Kubernetes.SecurityContext | ||||
| 	log.Trace().Interface("Security context", beSecurityContext).Msg("Security context that will be used for pods/containers") | ||||
| 	podSecCtx := podSecurityContext(beSecurityContext, secCtxConf) | ||||
| 	containerSecCtx := containerSecurityContext(beSecurityContext, step.Privileged) | ||||
|  | ||||
| 	pod := &v1.Pod{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{ | ||||
| 			Name:        podName, | ||||
| @@ -155,6 +160,7 @@ func Pod(namespace string, step *types.Step, labels, annotations map[string]stri | ||||
| 			NodeSelector:       nodeSelector, | ||||
| 			Tolerations:        tolerations, | ||||
| 			ServiceAccountName: serviceAccountName, | ||||
| 			SecurityContext:    podSecCtx, | ||||
| 			Containers: []v1.Container{{ | ||||
| 				Name:            podName, | ||||
| 				Image:           step.Image, | ||||
| @@ -165,9 +171,7 @@ func Pod(namespace string, step *types.Step, labels, annotations map[string]stri | ||||
| 				Env:             mapToEnvVars(step.Environment), | ||||
| 				VolumeMounts:    volMounts, | ||||
| 				Resources:       resourceRequirements, | ||||
| 				SecurityContext: &v1.SecurityContext{ | ||||
| 					Privileged: &step.Privileged, | ||||
| 				}, | ||||
| 				SecurityContext: containerSecCtx, | ||||
| 			}}, | ||||
| 			ImagePullSecrets: []v1.LocalObjectReference{{Name: "regcred"}}, | ||||
| 			Volumes:          vols, | ||||
| @@ -195,3 +199,55 @@ func volumeMountPath(i string) string { | ||||
| 	} | ||||
| 	return s[0] | ||||
| } | ||||
|  | ||||
| func podSecurityContext(sc *types.SecurityContext, secCtxConf SecurityContextConfig) *v1.PodSecurityContext { | ||||
| 	var ( | ||||
| 		nonRoot *bool | ||||
| 		user    *int64 | ||||
| 		group   *int64 | ||||
| 		fsGroup *int64 | ||||
| 	) | ||||
|  | ||||
| 	if sc != nil && sc.RunAsNonRoot != nil { | ||||
| 		if *sc.RunAsNonRoot { | ||||
| 			nonRoot = sc.RunAsNonRoot // true | ||||
| 		} | ||||
| 	} else if secCtxConf.RunAsNonRoot { | ||||
| 		nonRoot = &secCtxConf.RunAsNonRoot // true | ||||
| 	} | ||||
|  | ||||
| 	if sc != nil { | ||||
| 		user = sc.RunAsUser | ||||
| 		group = sc.RunAsGroup | ||||
| 		fsGroup = sc.FSGroup | ||||
| 	} | ||||
|  | ||||
| 	if nonRoot == nil && user == nil && group == nil && fsGroup == nil { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	return &v1.PodSecurityContext{ | ||||
| 		RunAsNonRoot: nonRoot, | ||||
| 		RunAsUser:    user, | ||||
| 		RunAsGroup:   group, | ||||
| 		FSGroup:      fsGroup, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func containerSecurityContext(sc *types.SecurityContext, stepPrivileged bool) *v1.SecurityContext { | ||||
| 	var privileged *bool | ||||
|  | ||||
| 	if sc != nil && sc.Privileged != nil && *sc.Privileged { | ||||
| 		privileged = sc.Privileged // true | ||||
| 	} else if stepPrivileged { | ||||
| 		privileged = &stepPrivileged // true | ||||
| 	} | ||||
|  | ||||
| 	if privileged == nil { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	return &v1.SecurityContext{ | ||||
| 		Privileged: privileged, | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -20,6 +20,7 @@ type KubernetesBackendOptions struct { | ||||
| 	ServiceAccountName string            `json:"serviceAccountName,omitempty"` | ||||
| 	NodeSelector       map[string]string `json:"nodeSelector,omitempty"` | ||||
| 	Tolerations        []Toleration      `json:"tolerations,omitempty"` | ||||
| 	SecurityContext    *SecurityContext  `json:"securityContext,omitempty"` | ||||
| } | ||||
|  | ||||
| // Resources defines two maps for kubernetes resource definitions | ||||
| @@ -51,3 +52,11 @@ const ( | ||||
| 	TolerationOpExists TolerationOperator = "Exists" | ||||
| 	TolerationOpEqual  TolerationOperator = "Equal" | ||||
| ) | ||||
|  | ||||
| type SecurityContext struct { | ||||
| 	Privileged   *bool  `json:"privileged,omitempty"` | ||||
| 	RunAsNonRoot *bool  `json:"runAsNonRoot,omitempty"` | ||||
| 	RunAsUser    *int64 `json:"runAsUser,omitempty"` | ||||
| 	RunAsGroup   *int64 `json:"runAsGroup,omitempty"` | ||||
| 	FSGroup      *int64 `json:"fsGroup,omitempty"` | ||||
| } | ||||
|   | ||||
| @@ -116,28 +116,9 @@ func (c *Compiler) createProcess(name string, container *yaml_types.Container, s | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var tolerations []backend_types.Toleration | ||||
| 	for _, t := range container.BackendOptions.Kubernetes.Tolerations { | ||||
| 		tolerations = append(tolerations, backend_types.Toleration{ | ||||
| 			Key:               t.Key, | ||||
| 			Operator:          backend_types.TolerationOperator(t.Operator), | ||||
| 			Value:             t.Value, | ||||
| 			Effect:            backend_types.TaintEffect(t.Effect), | ||||
| 			TolerationSeconds: t.TolerationSeconds, | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	// Kubernetes advanced settings | ||||
| 	// Advanced backend settings | ||||
| 	backendOptions := backend_types.BackendOptions{ | ||||
| 		Kubernetes: backend_types.KubernetesBackendOptions{ | ||||
| 			Resources: backend_types.Resources{ | ||||
| 				Limits:   container.BackendOptions.Kubernetes.Resources.Limits, | ||||
| 				Requests: container.BackendOptions.Kubernetes.Resources.Requests, | ||||
| 			}, | ||||
| 			ServiceAccountName: container.BackendOptions.Kubernetes.ServiceAccountName, | ||||
| 			NodeSelector:       container.BackendOptions.Kubernetes.NodeSelector, | ||||
| 			Tolerations:        tolerations, | ||||
| 		}, | ||||
| 		Kubernetes: convertKubernetesBackendOptions(&container.BackendOptions.Kubernetes), | ||||
| 	} | ||||
|  | ||||
| 	memSwapLimit := int64(container.MemSwapLimit) | ||||
| @@ -223,3 +204,40 @@ func (c *Compiler) stepWorkdir(container *yaml_types.Container) string { | ||||
| 	} | ||||
| 	return path.Join(c.base, c.path, container.Directory) | ||||
| } | ||||
|  | ||||
| func convertKubernetesBackendOptions(kubeOpt *yaml_types.KubernetesBackendOptions) backend_types.KubernetesBackendOptions { | ||||
| 	resources := backend_types.Resources{ | ||||
| 		Limits:   kubeOpt.Resources.Limits, | ||||
| 		Requests: kubeOpt.Resources.Requests, | ||||
| 	} | ||||
|  | ||||
| 	var tolerations []backend_types.Toleration | ||||
| 	for _, t := range kubeOpt.Tolerations { | ||||
| 		tolerations = append(tolerations, backend_types.Toleration{ | ||||
| 			Key:               t.Key, | ||||
| 			Operator:          backend_types.TolerationOperator(t.Operator), | ||||
| 			Value:             t.Value, | ||||
| 			Effect:            backend_types.TaintEffect(t.Effect), | ||||
| 			TolerationSeconds: t.TolerationSeconds, | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	var securityContext *backend_types.SecurityContext | ||||
| 	if kubeOpt.SecurityContext != nil { | ||||
| 		securityContext = &backend_types.SecurityContext{ | ||||
| 			Privileged:   kubeOpt.SecurityContext.Privileged, | ||||
| 			RunAsNonRoot: kubeOpt.SecurityContext.RunAsNonRoot, | ||||
| 			RunAsUser:    kubeOpt.SecurityContext.RunAsUser, | ||||
| 			RunAsGroup:   kubeOpt.SecurityContext.RunAsGroup, | ||||
| 			FSGroup:      kubeOpt.SecurityContext.FSGroup, | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return backend_types.KubernetesBackendOptions{ | ||||
| 		Resources:          resources, | ||||
| 		ServiceAccountName: kubeOpt.ServiceAccountName, | ||||
| 		NodeSelector:       kubeOpt.NodeSelector, | ||||
| 		Tolerations:        tolerations, | ||||
| 		SecurityContext:    securityContext, | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -14,28 +14,58 @@ | ||||
|     "variables": { | ||||
|       "description": "Use yaml aliases to define variables. Read more: https://woodpecker-ci.org/docs/usage/advanced-yaml-syntax" | ||||
|     }, | ||||
|     "clone": { "$ref": "#/definitions/clone" }, | ||||
|     "skip_clone": { "type": "boolean" }, | ||||
|     "branches": { "$ref": "#/definitions/branches" }, | ||||
|     "when": { "$ref": "#/definitions/pipeline_when" }, | ||||
|     "steps": { "$ref": "#/definitions/step_list" }, | ||||
|     "pipeline": { "$ref": "#/definitions/step_list", "description": "deprecated, use steps" }, | ||||
|     "services": { "$ref": "#/definitions/services" }, | ||||
|     "workspace": { "$ref": "#/definitions/workspace" }, | ||||
|     "matrix": { "$ref": "#/definitions/matrix" }, | ||||
|     "platform": { "$ref": "#/definitions/platform" }, | ||||
|     "labels": { "$ref": "#/definitions/labels" }, | ||||
|     "clone": { | ||||
|       "$ref": "#/definitions/clone" | ||||
|     }, | ||||
|     "skip_clone": { | ||||
|       "type": "boolean" | ||||
|     }, | ||||
|     "branches": { | ||||
|       "$ref": "#/definitions/branches" | ||||
|     }, | ||||
|     "when": { | ||||
|       "$ref": "#/definitions/pipeline_when" | ||||
|     }, | ||||
|     "steps": { | ||||
|       "$ref": "#/definitions/step_list" | ||||
|     }, | ||||
|     "pipeline": { | ||||
|       "$ref": "#/definitions/step_list", | ||||
|       "description": "deprecated, use steps" | ||||
|     }, | ||||
|     "services": { | ||||
|       "$ref": "#/definitions/services" | ||||
|     }, | ||||
|     "workspace": { | ||||
|       "$ref": "#/definitions/workspace" | ||||
|     }, | ||||
|     "matrix": { | ||||
|       "$ref": "#/definitions/matrix" | ||||
|     }, | ||||
|     "platform": { | ||||
|       "$ref": "#/definitions/platform" | ||||
|     }, | ||||
|     "labels": { | ||||
|       "$ref": "#/definitions/labels" | ||||
|     }, | ||||
|     "depends_on": { | ||||
|       "type": "array", | ||||
|       "minLength": 1, | ||||
|       "items": { "type": "string" } | ||||
|       "items": { | ||||
|         "type": "string" | ||||
|       } | ||||
|     }, | ||||
|     "runs_on": { | ||||
|       "type": "array", | ||||
|       "minLength": 1, | ||||
|       "items": { "type": "string" } | ||||
|       "items": { | ||||
|         "type": "string" | ||||
|       } | ||||
|     }, | ||||
|     "version": { "type": "number", "default": 1 } | ||||
|     "version": { | ||||
|       "type": "number", | ||||
|       "default": 1 | ||||
|     } | ||||
|   }, | ||||
|   "definitions": { | ||||
|     "clone": { | ||||
| @@ -74,20 +104,28 @@ | ||||
|               "oneOf": [ | ||||
|                 { | ||||
|                   "type": "array", | ||||
|                   "items": { "type": "string" }, | ||||
|                   "items": { | ||||
|                     "type": "string" | ||||
|                   }, | ||||
|                   "minLength": 1 | ||||
|                 }, | ||||
|                 { "type": "string" } | ||||
|                 { | ||||
|                   "type": "string" | ||||
|                 } | ||||
|               ] | ||||
|             }, | ||||
|             "include": { | ||||
|               "oneOf": [ | ||||
|                 { | ||||
|                   "type": "array", | ||||
|                   "items": { "type": "string" }, | ||||
|                   "items": { | ||||
|                     "type": "string" | ||||
|                   }, | ||||
|                   "minLength": 1 | ||||
|                 }, | ||||
|                 { "type": "string" } | ||||
|                 { | ||||
|                   "type": "string" | ||||
|                 } | ||||
|               ] | ||||
|             } | ||||
|           } | ||||
| @@ -97,8 +135,20 @@ | ||||
|     "step_list": { | ||||
|       "description": "The steps section defines a list of steps which will be executed serially, in the order in which they are defined. Read more: https://woodpecker-ci.org/docs/usage/pipeline-syntax", | ||||
|       "oneOf": [ | ||||
|         { "type": "object", "additionalProperties": { "$ref": "#/definitions/step" }, "minProperties": 1 }, | ||||
|         { "type": "array", "items": { "$ref": "#/definitions/step" }, "minLength": 1 } | ||||
|         { | ||||
|           "type": "object", | ||||
|           "additionalProperties": { | ||||
|             "$ref": "#/definitions/step" | ||||
|           }, | ||||
|           "minProperties": 1 | ||||
|         }, | ||||
|         { | ||||
|           "type": "array", | ||||
|           "items": { | ||||
|             "$ref": "#/definitions/step" | ||||
|           }, | ||||
|           "minLength": 1 | ||||
|         } | ||||
|       ] | ||||
|     }, | ||||
|     "pipeline_when": { | ||||
| @@ -107,7 +157,9 @@ | ||||
|         { | ||||
|           "type": "array", | ||||
|           "minLength": 1, | ||||
|           "items": { "$ref": "#/definitions/pipeline_when_condition" } | ||||
|           "items": { | ||||
|             "$ref": "#/definitions/pipeline_when_condition" | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           "$ref": "#/definitions/pipeline_when_condition" | ||||
| @@ -133,7 +185,9 @@ | ||||
|             { | ||||
|               "type": "array", | ||||
|               "minLength": 1, | ||||
|               "items": { "$ref": "#/definitions/event_enum" } | ||||
|               "items": { | ||||
|                 "$ref": "#/definitions/event_enum" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|               "$ref": "#/definitions/event_enum" | ||||
| @@ -163,7 +217,9 @@ | ||||
|         "path": { | ||||
|           "description": "Execute a step only on commit with certain files added/removed/modified. Read more: https://woodpecker-ci.org/docs/usage/pipeline-syntax#path", | ||||
|           "oneOf": [ | ||||
|             { "type": "string" }, | ||||
|             { | ||||
|               "type": "string" | ||||
|             }, | ||||
|             { | ||||
|               "type": "array", | ||||
|               "items": { | ||||
| @@ -264,7 +320,9 @@ | ||||
|         { | ||||
|           "type": "array", | ||||
|           "minLength": 1, | ||||
|           "items": { "$ref": "#/definitions/step_when_condition" } | ||||
|           "items": { | ||||
|             "$ref": "#/definitions/step_when_condition" | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           "$ref": "#/definitions/step_when_condition" | ||||
| @@ -290,7 +348,9 @@ | ||||
|             { | ||||
|               "type": "array", | ||||
|               "minLength": 1, | ||||
|               "items": { "$ref": "#/definitions/event_enum" } | ||||
|               "items": { | ||||
|                 "$ref": "#/definitions/event_enum" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|               "$ref": "#/definitions/event_enum" | ||||
| @@ -311,7 +371,10 @@ | ||||
|             { | ||||
|               "type": "array", | ||||
|               "minLength": 1, | ||||
|               "items": { "type": "string", "enum": ["success", "failure"] } | ||||
|               "items": { | ||||
|                 "type": "string", | ||||
|                 "enum": ["success", "failure"] | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|               "type": "string", | ||||
| @@ -341,7 +404,9 @@ | ||||
|         "path": { | ||||
|           "description": "Execute a step only on commit with certain files added/removed/modified. Read more: https://woodpecker-ci.org/docs/usage/pipeline-syntax#path", | ||||
|           "oneOf": [ | ||||
|             { "type": "string" }, | ||||
|             { | ||||
|               "type": "string" | ||||
|             }, | ||||
|             { | ||||
|               "type": "array", | ||||
|               "items": { | ||||
| @@ -388,7 +453,9 @@ | ||||
|         { | ||||
|           "type": "array", | ||||
|           "minLength": 1, | ||||
|           "items": { "type": "string" } | ||||
|           "items": { | ||||
|             "type": "string" | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           "type": "object", | ||||
| @@ -402,7 +469,9 @@ | ||||
|                 { | ||||
|                   "type": "array", | ||||
|                   "minLength": 1, | ||||
|                   "items": { "type": "string" } | ||||
|                   "items": { | ||||
|                     "type": "string" | ||||
|                   } | ||||
|                 } | ||||
|               ] | ||||
|             }, | ||||
| @@ -414,7 +483,9 @@ | ||||
|                 { | ||||
|                   "type": "array", | ||||
|                   "minLength": 1, | ||||
|                   "items": { "type": "string" } | ||||
|                   "items": { | ||||
|                     "type": "string" | ||||
|                   } | ||||
|                 } | ||||
|               ] | ||||
|             } | ||||
| @@ -440,10 +511,14 @@ | ||||
|       "oneOf": [ | ||||
|         { | ||||
|           "type": "array", | ||||
|           "items": { "type": "string" }, | ||||
|           "items": { | ||||
|             "type": "string" | ||||
|           }, | ||||
|           "minLength": 1 | ||||
|         }, | ||||
|         { "type": "string" } | ||||
|         { | ||||
|           "type": "string" | ||||
|         } | ||||
|       ] | ||||
|     }, | ||||
|     "step_environment": { | ||||
| @@ -451,7 +526,9 @@ | ||||
|       "oneOf": [ | ||||
|         { | ||||
|           "type": "array", | ||||
|           "items": { "type": "string" }, | ||||
|           "items": { | ||||
|             "type": "string" | ||||
|           }, | ||||
|           "minLength": 1 | ||||
|         }, | ||||
|         { | ||||
| @@ -467,13 +544,19 @@ | ||||
|       "type": "array", | ||||
|       "items": { | ||||
|         "oneOf": [ | ||||
|           { "type": "string" }, | ||||
|           { | ||||
|             "type": "string" | ||||
|           }, | ||||
|           { | ||||
|             "type": "object", | ||||
|             "required": ["source", "target"], | ||||
|             "properties": { | ||||
|               "source": { "type": "string" }, | ||||
|               "target": { "type": "string" } | ||||
|               "source": { | ||||
|                 "type": "string" | ||||
|               }, | ||||
|               "target": { | ||||
|                 "type": "string" | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         ] | ||||
| @@ -490,7 +573,9 @@ | ||||
|     "step_volumes": { | ||||
|       "description": "Mount files or folders from the host machine into your step container. Read more: https://woodpecker-ci.org/docs/usage/volumes", | ||||
|       "type": "array", | ||||
|       "items": { "type": "string" }, | ||||
|       "items": { | ||||
|         "type": "string" | ||||
|       }, | ||||
|       "minLength": 1 | ||||
|     }, | ||||
|     "step_directory": { | ||||
| @@ -502,7 +587,7 @@ | ||||
|       "type": "object", | ||||
|       "properties": { | ||||
|         "kubernetes": { | ||||
|           "$ref": "#/definitions/step_backend_kubernetes_resources" | ||||
|           "$ref": "#/definitions/step_backend_kubernetes" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
| @@ -512,6 +597,9 @@ | ||||
|       "properties": { | ||||
|         "resources": { | ||||
|           "$ref": "#/definitions/step_backend_kubernetes_resources" | ||||
|         }, | ||||
|         "securityContext": { | ||||
|           "$ref": "#/definitions/step_backend_kubernetes_security_context" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
| @@ -527,6 +615,27 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "step_backend_kubernetes_security_context": { | ||||
|       "description": "Pods / containers security context. Read more: https://woodpecker-ci.org/docs/administration/backends/kubernetes", | ||||
|       "type": "object", | ||||
|       "properties": { | ||||
|         "privileged": { | ||||
|           "type": "boolean" | ||||
|         }, | ||||
|         "runAsNonRoot": { | ||||
|           "type": "boolean" | ||||
|         }, | ||||
|         "runAsUser": { | ||||
|           "type": "number" | ||||
|         }, | ||||
|         "runAsGroup": { | ||||
|           "type": "number" | ||||
|         }, | ||||
|         "fsGroup": { | ||||
|           "type": "number" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "step_kubernetes_resources_object": { | ||||
|       "description": "A list of kubernetes resource mappings", | ||||
|       "type": "object", | ||||
| @@ -556,7 +665,9 @@ | ||||
|     "services": { | ||||
|       "description": "Read more: https://woodpecker-ci.org/docs/usage/services", | ||||
|       "type": "object", | ||||
|       "additionalProperties": { "$ref": "#/definitions/service" }, | ||||
|       "additionalProperties": { | ||||
|         "$ref": "#/definitions/service" | ||||
|       }, | ||||
|       "minProperties": 1 | ||||
|     }, | ||||
|     "service": { | ||||
| @@ -597,7 +708,14 @@ | ||||
|           "description": "expose ports to which other steps can connect to", | ||||
|           "type": "array", | ||||
|           "items": { | ||||
|             "oneOf": [{ "type": "number" }, { "type": "string" }] | ||||
|             "oneOf": [ | ||||
|               { | ||||
|                 "type": "number" | ||||
|               }, | ||||
|               { | ||||
|                 "type": "string" | ||||
|               } | ||||
|             ] | ||||
|           }, | ||||
|           "minLength": 1 | ||||
|         } | ||||
|   | ||||
| @@ -24,6 +24,7 @@ type KubernetesBackendOptions struct { | ||||
| 	ServiceAccountName string            `yaml:"serviceAccountName,omitempty"` | ||||
| 	NodeSelector       map[string]string `yaml:"nodeSelector,omitempty"` | ||||
| 	Tolerations        []Toleration      `yaml:"tolerations,omitempty"` | ||||
| 	SecurityContext    *SecurityContext  `yaml:"securityContext,omitempty"` | ||||
| } | ||||
|  | ||||
| type Resources struct { | ||||
| @@ -53,3 +54,11 @@ const ( | ||||
| 	TolerationOpExists TolerationOperator = "Exists" | ||||
| 	TolerationOpEqual  TolerationOperator = "Equal" | ||||
| ) | ||||
|  | ||||
| type SecurityContext struct { | ||||
| 	Privileged   *bool  `yaml:"privileged,omitempty"` | ||||
| 	RunAsNonRoot *bool  `yaml:"runAsNonRoot,omitempty"` | ||||
| 	RunAsUser    *int64 `yaml:"runAsUser,omitempty"` | ||||
| 	RunAsGroup   *int64 `yaml:"runAsGroup,omitempty"` | ||||
| 	FSGroup      *int64 `yaml:"fsGroup,omitempty"` | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user