This is an automated email from the ASF dual-hosted git repository. tsato pushed a commit to branch release-1.8.x in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit e7a6d6c289b38ffffdd645e8e393d0485537de17 Author: Adriano Machado <unknown> AuthorDate: Thu Jun 16 09:46:52 2022 -0400 feat: add basic support for PodSecurityContext --- .../crd/bases/camel.apache.org_integrations.yaml | 168 ++++++++++++++++++++ .../bases/camel.apache.org_kameletbindings.yaml | 172 +++++++++++++++++++++ .../attachments/schema/integration-schema.json | 105 ++++++++++++- docs/modules/ROOT/partials/apis/camel-k-crds.adoc | 10 +- .../files/template-with-supplemental-groups.yaml | 25 +++ e2e/common/traits/pod_test.go | 75 ++++++--- helm/camel-k/crds/crd-integration.yaml | 168 ++++++++++++++++++++ helm/camel-k/crds/crd-kamelet-binding.yaml | 172 +++++++++++++++++++++ pkg/apis/camel/v1/integration_types.go | 2 + pkg/apis/camel/v1/zz_generated.deepcopy.go | 1 + pkg/cmd/run_test.go | 33 ++++ .../integration/integration_controller.go | 2 +- pkg/resources/resources.go | 12 +- pkg/trait/pod_test.go | 14 +- 14 files changed, 930 insertions(+), 29 deletions(-) diff --git a/config/crd/bases/camel.apache.org_integrations.yaml b/config/crd/bases/camel.apache.org_integrations.yaml index 871a03177..f32e2e989 100644 --- a/config/crd/bases/camel.apache.org_integrations.yaml +++ b/config/crd/bases/camel.apache.org_integrations.yaml @@ -3710,6 +3710,174 @@ spec: may be specified. If none of the following policies is specified, the default one is RestartPolicyAlways. type: string + securityContext: + description: PodSecurityContext + properties: + fsGroup: + description: "A special supplemental group that applies + to all containers in a pod. Some volume types allow + the Kubelet to change the ownership of that volume to + be owned by the pod: \n 1. The owning GID will be the + FSGroup 2. The setgid bit is set (new files created + in the volume will be owned by FSGroup) 3. The permission + bits are OR'd with rw-rw---- \n If unset, the Kubelet + will not modify the ownership and permissions of any + volume." + format: int64 + type: integer + fsGroupChangePolicy: + description: 'fsGroupChangePolicy defines behavior of + changing ownership and permission of the volume before + being exposed inside Pod. This field will only apply + to volume types which support fsGroup based ownership(and + permissions). It will have no effect on ephemeral volume + types such as: secret, configmaps and emptydir. Valid + values are "OnRootMismatch" and "Always". If not specified, + "Always" is used.' + type: string + runAsGroup: + description: The GID to run the entrypoint of the container + process. Uses runtime default if unset. May also be + set in SecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run as + a non-root user. If true, the Kubelet will validate + the image at runtime to ensure that it does not run + as UID 0 (root) and fail to start the container if it + does. If unset or false, no such validation will be + performed. May also be set in SecurityContext. If set + in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container + process. Defaults to user specified in image metadata + if unspecified. May also be set in SecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence + for that container. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to all + containers. If unspecified, the container runtime will + allocate a random SELinux context for each container. May + also be set in SecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by the containers + in this pod. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. The + profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's + configured seccomp profile location. Must only be + set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: \n Localhost + - a profile defined in a file on the node should + be used. RuntimeDefault - the container runtime + default profile should be used. Unconfined - no + profile should be applied." + type: string + required: + - type + type: object + supplementalGroups: + description: A list of groups applied to the first process + run in each container, in addition to the container's + primary GID. If unspecified, no groups will be added + to any container. + items: + format: int64 + type: integer + type: array + sysctls: + description: Sysctls hold a list of namespaced sysctls + used for the pod. Pods with unsupported sysctls (by + the container runtime) might fail to launch. + items: + description: Sysctl defines a kernel parameter to be + set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + windowsOptions: + description: The Windows specific settings applied to + all containers. If unspecified, the options within a + container's SecurityContext will be used. If set in + both SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA + admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential spec + named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of + the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container + should be run as a 'Host Process' container. This + field is alpha-level and will only be honored by + components that enable the WindowsHostProcessContainers + feature flag. Setting this field without the feature + flag will result in errors when validating the Pod. + All of a Pod's containers must have the same effective + HostProcess value (it is not allowed to have a mix + of HostProcess containers and non-HostProcess containers). In + addition, if HostProcess is true then HostNetwork + must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the entrypoint + of the container process. Defaults to the user specified + in image metadata if unspecified. May also be set + in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object terminationGracePeriodSeconds: format: int64 type: integer diff --git a/config/crd/bases/camel.apache.org_kameletbindings.yaml b/config/crd/bases/camel.apache.org_kameletbindings.yaml index 64b950baf..23aa7228d 100644 --- a/config/crd/bases/camel.apache.org_kameletbindings.yaml +++ b/config/crd/bases/camel.apache.org_kameletbindings.yaml @@ -3892,6 +3892,178 @@ spec: policies may be specified. If none of the following policies is specified, the default one is RestartPolicyAlways. type: string + securityContext: + description: PodSecurityContext + properties: + fsGroup: + description: "A special supplemental group that applies + to all containers in a pod. Some volume types allow + the Kubelet to change the ownership of that volume + to be owned by the pod: \n 1. The owning GID will + be the FSGroup 2. The setgid bit is set (new files + created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- \n + If unset, the Kubelet will not modify the ownership + and permissions of any volume." + format: int64 + type: integer + fsGroupChangePolicy: + description: 'fsGroupChangePolicy defines behavior + of changing ownership and permission of the volume + before being exposed inside Pod. This field will + only apply to volume types which support fsGroup + based ownership(and permissions). It will have no + effect on ephemeral volume types such as: secret, + configmaps and emptydir. Valid values are "OnRootMismatch" + and "Always". If not specified, "Always" is used.' + type: string + runAsGroup: + description: The GID to run the entrypoint of the + container process. Uses runtime default if unset. + May also be set in SecurityContext. If set in both + SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence for + that container. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run + as a non-root user. If true, the Kubelet will validate + the image at runtime to ensure that it does not + run as UID 0 (root) and fail to start the container + if it does. If unset or false, no such validation + will be performed. May also be set in SecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the + container process. Defaults to user specified in + image metadata if unspecified. May also be set in + SecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to + all containers. If unspecified, the container runtime + will allocate a random SELinux context for each + container. May also be set in SecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence + for that container. + properties: + level: + description: Level is SELinux level label that + applies to the container. + type: string + role: + description: Role is a SELinux role label that + applies to the container. + type: string + type: + description: Type is a SELinux type label that + applies to the container. + type: string + user: + description: User is a SELinux user label that + applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by the containers + in this pod. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. + The profile must be preconfigured on the node + to work. Must be a descending path, relative + to the kubelet's configured seccomp profile + location. Must only be set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: + \n Localhost - a profile defined in a file on + the node should be used. RuntimeDefault - the + container runtime default profile should be + used. Unconfined - no profile should be applied." + type: string + required: + - type + type: object + supplementalGroups: + description: A list of groups applied to the first + process run in each container, in addition to the + container's primary GID. If unspecified, no groups + will be added to any container. + items: + format: int64 + type: integer + type: array + sysctls: + description: Sysctls hold a list of namespaced sysctls + used for the pod. Pods with unsupported sysctls + (by the container runtime) might fail to launch. + items: + description: Sysctl defines a kernel parameter to + be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + windowsOptions: + description: The Windows specific settings applied + to all containers. If unspecified, the options within + a container's SecurityContext will be used. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA + admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name + of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container + should be run as a 'Host Process' container. + This field is alpha-level and will only be honored + by components that enable the WindowsHostProcessContainers + feature flag. Setting this field without the + feature flag will result in errors when validating + the Pod. All of a Pod's containers must have + the same effective HostProcess value (it is + not allowed to have a mix of HostProcess containers + and non-HostProcess containers). In addition, + if HostProcess is true then HostNetwork must + also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the + entrypoint of the container process. Defaults + to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. + type: string + type: object + type: object terminationGracePeriodSeconds: format: int64 type: integer diff --git a/docs/modules/ROOT/attachments/schema/integration-schema.json b/docs/modules/ROOT/attachments/schema/integration-schema.json index 186329956..c1117d555 100644 --- a/docs/modules/ROOT/attachments/schema/integration-schema.json +++ b/docs/modules/ROOT/attachments/schema/integration-schema.json @@ -3392,6 +3392,109 @@ "description": "RestartPolicy describes how the container should be restarted. Only one of the following restart policies may be specified. If none of the following policies is specified, the default one is RestartPolicyAlways.", "type": "string" }, + "securityContext": { + "description": "PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.", + "properties": { + "fsGroup": { + "description": "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod:\n\n1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw----\n\nIf unset, the Kubelet will not modify the ownership and permissions of any volume.", + "format": "int64", + "type": "integer" + }, + "fsGroupChangePolicy": { + "description": "fsGroupChangePolicy defines behavior of changing ownership and permission of the volume before being exposed inside Pod. This field will only apply to volume types which support fsGroup based ownership(and permissions). It will have no effect on ephemeral volume types such as: secret, configmaps and emptydir. Valid values are \"OnRootMismatch\" and \"Always\". If not specified defaults to \"Always\".", + "type": "string" + }, + "runAsGroup": { + "description": "The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", + "format": "int64", + "type": "integer" + }, + "runAsNonRoot": { + "description": "Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", + "type": "boolean" + }, + "runAsUser": { + "description": "The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", + "format": "int64", + "type": "integer" + }, + "seLinuxOptions": { + "description": "The SELinux context to be applied to the container. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", + "properties": { + "level": { + "description": "Level is SELinux level label that applies to the container.", + "type": "string" + }, + "role": { + "description": "Role is a SELinux role label that applies to the container.", + "type": "string" + }, + "type": { + "description": "Type is a SELinux type label that applies to the container.", + "type": "string" + }, + "user": { + "description": "User is a SELinux user label that applies to the container.", + "type": "string" + } + }, + "type": "object" + }, + "supplementalGroups": { + "description": "A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container.", + "items": { + "format": "int64", + "type": "integer" + }, + "type": "array" + }, + "sysctls": { + "description": "Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported sysctls (by the container runtime) might fail to launch.", + "items": { + "description": "Sysctl defines a kernel parameter to be set", + "properties": { + "name": { + "description": "Name of a property to set", + "type": "string" + }, + "value": { + "description": "Value of a property to set", + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "windowsOptions": { + "description": "The Windows specific settings applied to all containers. If unspecified, the options from the PodSecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", + "properties": { + "gmsaCredentialSpec": { + "description": "GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field.", + "type": "string" + }, + "gmsaCredentialSpecName": { + "description": "GMSACredentialSpecName is the name of the GMSA credential spec to use.", + "type": "string" + }, + "hostProcess": { + "description": "HostProcess determines if a container should be run as a 'Host Process' container. This field is alpha-level and will only be honored by components that enable the WindowsHostProcessContainers feature flag. Setting this field without the feature flag will result in errors when validating the Pod. All of a Pod's containers must have the same effective HostProcess value (it is not allowed to have a mix of HostProcess containers and non-HostProcess [...] + "type": "boolean" + }, + "runAsUserName": { + "description": "The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, "serviceAccount": { "type": "string" }, @@ -9269,4 +9372,4 @@ } } } -} \ No newline at end of file +} diff --git a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc index e0d81b348..5b8e07dce 100644 --- a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc +++ b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc @@ -2444,6 +2444,14 @@ map[string]string +|`securityContext` + +*https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#podsecuritycontext-v1-core[[\]Kubernetes core/v1.PodSecurityContext]* +| + + +PodSecurityContext + + |=== [#_camel_apache_org_v1_PodSpecTemplate] @@ -3109,4 +3117,4 @@ Selects a key of a ConfigMap. Selects a key of a secret. -|=== \ No newline at end of file +|=== diff --git a/e2e/common/traits/files/template-with-supplemental-groups.yaml b/e2e/common/traits/files/template-with-supplemental-groups.yaml new file mode 100644 index 000000000..fdb1c034b --- /dev/null +++ b/e2e/common/traits/files/template-with-supplemental-groups.yaml @@ -0,0 +1,25 @@ +# --------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# --------------------------------------------------------------------------- + +containers: + - name: integration + env: + - name: TEST_VARIABLE + value: "hello from the template" +securityContext: + supplementalGroups: + - 666 diff --git a/e2e/common/traits/pod_test.go b/e2e/common/traits/pod_test.go index 1fa802505..9fe447090 100644 --- a/e2e/common/traits/pod_test.go +++ b/e2e/common/traits/pod_test.go @@ -34,27 +34,64 @@ import ( ) func TestPodTrait(t *testing.T) { + + tc := []struct { + name string + templateName string + assertions func(t *testing.T, ns string, name string) + }{ + { + name: "pod trait with env vars and volume mounts", + templateName: "files/template.yaml", + assertions: func(t *testing.T, ns string, name string) { + // check that integrations is working and reading data created by sidecar container + Eventually(IntegrationLogs(ns, name), TestTimeoutShort).Should(ContainSubstring("Content from the sidecar container")) + // check that env var is injected + Eventually(IntegrationLogs(ns, name), TestTimeoutShort).Should(ContainSubstring("hello from the template")) + pod := IntegrationPod(ns, name)() + + // check if ENV variable is applied + envValue := getEnvVar("TEST_VARIABLE", pod.Spec) + Expect(envValue).To(Equal("hello from the template")) + }, + }, + { + name: "pod trait with supplemental groups", + templateName: "files/template-with-supplemental-groups.yaml", + assertions: func(t *testing.T, ns string, name string) { + pod := IntegrationPod(ns, name)() + Expect(pod.Spec).NotTo(BeNil()) + Expect(pod.Spec.SecurityContext).NotTo(BeNil()) + Expect(pod.Spec.SecurityContext.SupplementalGroups).NotTo(BeNil()) + Expect(pod.Spec.SecurityContext.SupplementalGroups).Should(ContainElements(int64(666))) + }, + }, + } + WithNewTestNamespace(t, func(ns string) { - name := "pod-template-test" Expect(Kamel("install", "-n", ns).Execute()).To(Succeed()) - Expect(Kamel("run", "-n", ns, "files/PodTest.groovy", - "--name", name, - "--pod-template", "files/template.yaml", - ).Execute()).To(Succeed()) - - // check integration is deployed - Eventually(IntegrationPodPhase(ns, name), TestTimeoutLong).Should(Equal(corev1.PodRunning)) - Eventually(IntegrationConditionStatus(ns, name, v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue)) - - // check that integrations is working and reading data created by sidecar container - Eventually(IntegrationLogs(ns, name), TestTimeoutShort).Should(ContainSubstring("Content from the sidecar container")) - // check that env var is injected - Eventually(IntegrationLogs(ns, name), TestTimeoutShort).Should(ContainSubstring("hello from the template")) - pod := IntegrationPod(ns, name)() - - // check if ENV variable is applied - envValue := getEnvVar("TEST_VARIABLE", pod.Spec) - Expect(envValue).To(Equal("hello from the template")) + + name := "pod-template-test" + + for i := range tc { + test := tc[i] + + t.Run(test.name, func(t *testing.T) { + Expect(Kamel("run", "-n", ns, "files/PodTest.groovy", + "--name", name, + "--pod-template", test.templateName, + ).Execute()).To(Succeed()) + + // check integration is deployed + Eventually(IntegrationPodPhase(ns, name), TestTimeoutLong).Should(Equal(corev1.PodRunning)) + Eventually(IntegrationConditionStatus(ns, name, v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue)) + + test.assertions(t, ns, name) + + // Clean up + Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed()) + }) + } }) } diff --git a/helm/camel-k/crds/crd-integration.yaml b/helm/camel-k/crds/crd-integration.yaml index 871a03177..f32e2e989 100644 --- a/helm/camel-k/crds/crd-integration.yaml +++ b/helm/camel-k/crds/crd-integration.yaml @@ -3710,6 +3710,174 @@ spec: may be specified. If none of the following policies is specified, the default one is RestartPolicyAlways. type: string + securityContext: + description: PodSecurityContext + properties: + fsGroup: + description: "A special supplemental group that applies + to all containers in a pod. Some volume types allow + the Kubelet to change the ownership of that volume to + be owned by the pod: \n 1. The owning GID will be the + FSGroup 2. The setgid bit is set (new files created + in the volume will be owned by FSGroup) 3. The permission + bits are OR'd with rw-rw---- \n If unset, the Kubelet + will not modify the ownership and permissions of any + volume." + format: int64 + type: integer + fsGroupChangePolicy: + description: 'fsGroupChangePolicy defines behavior of + changing ownership and permission of the volume before + being exposed inside Pod. This field will only apply + to volume types which support fsGroup based ownership(and + permissions). It will have no effect on ephemeral volume + types such as: secret, configmaps and emptydir. Valid + values are "OnRootMismatch" and "Always". If not specified, + "Always" is used.' + type: string + runAsGroup: + description: The GID to run the entrypoint of the container + process. Uses runtime default if unset. May also be + set in SecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run as + a non-root user. If true, the Kubelet will validate + the image at runtime to ensure that it does not run + as UID 0 (root) and fail to start the container if it + does. If unset or false, no such validation will be + performed. May also be set in SecurityContext. If set + in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container + process. Defaults to user specified in image metadata + if unspecified. May also be set in SecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence + for that container. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to all + containers. If unspecified, the container runtime will + allocate a random SELinux context for each container. May + also be set in SecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by the containers + in this pod. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. The + profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's + configured seccomp profile location. Must only be + set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: \n Localhost + - a profile defined in a file on the node should + be used. RuntimeDefault - the container runtime + default profile should be used. Unconfined - no + profile should be applied." + type: string + required: + - type + type: object + supplementalGroups: + description: A list of groups applied to the first process + run in each container, in addition to the container's + primary GID. If unspecified, no groups will be added + to any container. + items: + format: int64 + type: integer + type: array + sysctls: + description: Sysctls hold a list of namespaced sysctls + used for the pod. Pods with unsupported sysctls (by + the container runtime) might fail to launch. + items: + description: Sysctl defines a kernel parameter to be + set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + windowsOptions: + description: The Windows specific settings applied to + all containers. If unspecified, the options within a + container's SecurityContext will be used. If set in + both SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA + admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential spec + named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of + the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container + should be run as a 'Host Process' container. This + field is alpha-level and will only be honored by + components that enable the WindowsHostProcessContainers + feature flag. Setting this field without the feature + flag will result in errors when validating the Pod. + All of a Pod's containers must have the same effective + HostProcess value (it is not allowed to have a mix + of HostProcess containers and non-HostProcess containers). In + addition, if HostProcess is true then HostNetwork + must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the entrypoint + of the container process. Defaults to the user specified + in image metadata if unspecified. May also be set + in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object terminationGracePeriodSeconds: format: int64 type: integer diff --git a/helm/camel-k/crds/crd-kamelet-binding.yaml b/helm/camel-k/crds/crd-kamelet-binding.yaml index 64b950baf..23aa7228d 100644 --- a/helm/camel-k/crds/crd-kamelet-binding.yaml +++ b/helm/camel-k/crds/crd-kamelet-binding.yaml @@ -3892,6 +3892,178 @@ spec: policies may be specified. If none of the following policies is specified, the default one is RestartPolicyAlways. type: string + securityContext: + description: PodSecurityContext + properties: + fsGroup: + description: "A special supplemental group that applies + to all containers in a pod. Some volume types allow + the Kubelet to change the ownership of that volume + to be owned by the pod: \n 1. The owning GID will + be the FSGroup 2. The setgid bit is set (new files + created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- \n + If unset, the Kubelet will not modify the ownership + and permissions of any volume." + format: int64 + type: integer + fsGroupChangePolicy: + description: 'fsGroupChangePolicy defines behavior + of changing ownership and permission of the volume + before being exposed inside Pod. This field will + only apply to volume types which support fsGroup + based ownership(and permissions). It will have no + effect on ephemeral volume types such as: secret, + configmaps and emptydir. Valid values are "OnRootMismatch" + and "Always". If not specified, "Always" is used.' + type: string + runAsGroup: + description: The GID to run the entrypoint of the + container process. Uses runtime default if unset. + May also be set in SecurityContext. If set in both + SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence for + that container. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run + as a non-root user. If true, the Kubelet will validate + the image at runtime to ensure that it does not + run as UID 0 (root) and fail to start the container + if it does. If unset or false, no such validation + will be performed. May also be set in SecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the + container process. Defaults to user specified in + image metadata if unspecified. May also be set in + SecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to + all containers. If unspecified, the container runtime + will allocate a random SELinux context for each + container. May also be set in SecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence + for that container. + properties: + level: + description: Level is SELinux level label that + applies to the container. + type: string + role: + description: Role is a SELinux role label that + applies to the container. + type: string + type: + description: Type is a SELinux type label that + applies to the container. + type: string + user: + description: User is a SELinux user label that + applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by the containers + in this pod. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. + The profile must be preconfigured on the node + to work. Must be a descending path, relative + to the kubelet's configured seccomp profile + location. Must only be set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: + \n Localhost - a profile defined in a file on + the node should be used. RuntimeDefault - the + container runtime default profile should be + used. Unconfined - no profile should be applied." + type: string + required: + - type + type: object + supplementalGroups: + description: A list of groups applied to the first + process run in each container, in addition to the + container's primary GID. If unspecified, no groups + will be added to any container. + items: + format: int64 + type: integer + type: array + sysctls: + description: Sysctls hold a list of namespaced sysctls + used for the pod. Pods with unsupported sysctls + (by the container runtime) might fail to launch. + items: + description: Sysctl defines a kernel parameter to + be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + windowsOptions: + description: The Windows specific settings applied + to all containers. If unspecified, the options within + a container's SecurityContext will be used. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA + admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name + of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container + should be run as a 'Host Process' container. + This field is alpha-level and will only be honored + by components that enable the WindowsHostProcessContainers + feature flag. Setting this field without the + feature flag will result in errors when validating + the Pod. All of a Pod's containers must have + the same effective HostProcess value (it is + not allowed to have a mix of HostProcess containers + and non-HostProcess containers). In addition, + if HostProcess is true then HostNetwork must + also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the + entrypoint of the container process. Defaults + to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set + in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. + type: string + type: object + type: object terminationGracePeriodSeconds: format: int64 type: integer diff --git a/pkg/apis/camel/v1/integration_types.go b/pkg/apis/camel/v1/integration_types.go index e2ae0e9e6..d9676fd81 100644 --- a/pkg/apis/camel/v1/integration_types.go +++ b/pkg/apis/camel/v1/integration_types.go @@ -262,4 +262,6 @@ type PodSpec struct { NodeSelector map[string]string `json:"nodeSelector,omitempty" protobuf:"bytes,7,rep,name=nodeSelector"` TopologySpreadConstraints []corev1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty" patchStrategy:"merge" patchMergeKey:"topologyKey" protobuf:"bytes,33,opt,name=topologySpreadConstraints"` + // PodSecurityContext + SecurityContext corev1.PodSecurityContext `json:"securityContext,omitempty" protobuf:"bytes,34,opt,name=securityContext"` } diff --git a/pkg/apis/camel/v1/zz_generated.deepcopy.go b/pkg/apis/camel/v1/zz_generated.deepcopy.go index ba10726f3..0fe649eb0 100644 --- a/pkg/apis/camel/v1/zz_generated.deepcopy.go +++ b/pkg/apis/camel/v1/zz_generated.deepcopy.go @@ -1357,6 +1357,7 @@ func (in *PodSpec) DeepCopyInto(out *PodSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + in.SecurityContext.DeepCopyInto(&out.SecurityContext) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodSpec. diff --git a/pkg/cmd/run_test.go b/pkg/cmd/run_test.go index dc35ee4b0..85241a2c5 100644 --- a/pkg/cmd/run_test.go +++ b/pkg/cmd/run_test.go @@ -631,3 +631,36 @@ func TestFilterBuildPropertyFiles(t *testing.T) { assert.Equal(t, len(outputValues), 1) assert.Equal(t, outputValues[0], "/tmp/test") } + +func TestResolveYamlPodTemplateWithSupplementalGroups(t *testing.T) { + //_, rootCmd, _ := initializeRunCmdOptions(t) + templateText := ` +securityContext: + supplementalGroups: + - 666 +` + integrationSpec := v1.IntegrationSpec{} + err := resolvePodTemplate(context.TODO(), templateText, &integrationSpec) + assert.Nil(t, err) + assert.NotNil(t, integrationSpec.PodTemplate) + assert.NotNil(t, integrationSpec.PodTemplate.Spec) + assert.NotNil(t, integrationSpec.PodTemplate.Spec.SecurityContext) + assert.NotNil(t, integrationSpec.PodTemplate.Spec.SecurityContext.SupplementalGroups) + assert.Equal(t, 1, len(integrationSpec.PodTemplate.Spec.SecurityContext.SupplementalGroups)) + assert.Contains(t, integrationSpec.PodTemplate.Spec.SecurityContext.SupplementalGroups, int64(666)) +} + +func TestResolveJsonPodTemplateWithSupplementalGroups(t *testing.T) { + //_, rootCmd, _ := initializeRunCmdOptions(t) + minifiedYamlTemplate := `{"securityContext":{"supplementalGroups":[666]}}` + + integrationSpec := v1.IntegrationSpec{} + err := resolvePodTemplate(context.TODO(), minifiedYamlTemplate, &integrationSpec) + assert.Nil(t, err) + assert.NotNil(t, integrationSpec.PodTemplate) + assert.NotNil(t, integrationSpec.PodTemplate.Spec) + assert.NotNil(t, integrationSpec.PodTemplate.Spec.SecurityContext) + assert.NotNil(t, integrationSpec.PodTemplate.Spec.SecurityContext.SupplementalGroups) + assert.Equal(t, 1, len(integrationSpec.PodTemplate.Spec.SecurityContext.SupplementalGroups)) + assert.Contains(t, integrationSpec.PodTemplate.Spec.SecurityContext.SupplementalGroups, int64(666)) +} diff --git a/pkg/controller/integration/integration_controller.go b/pkg/controller/integration/integration_controller.go index bc65c06dd..fb2dd202c 100644 --- a/pkg/controller/integration/integration_controller.go +++ b/pkg/controller/integration/integration_controller.go @@ -252,7 +252,7 @@ type reconcileIntegration struct { recorder record.EventRecorder } -// Reconcile reads that state of the cluster for a Integration object and makes changes based on the state read +// Reconcile reads that state of the cluster for an Integration object and makes changes based on the state read // and what is in the Integration.Spec // Note: // The Controller will requeue the Request to be processed again if the returned error is non-nil or diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go index f41e8aa04..a4b5ea1bb 100644 --- a/pkg/resources/resources.go +++ b/pkg/resources/resources.go @@ -145,16 +145,16 @@ var assets = func() http.FileSystem { "/crd/bases/camel.apache.org_integrations.yaml": &vfsgen۰CompressedFileInfo{ name: "camel.apache.org_integrations.yaml", modTime: time.Time{}, - uncompressedSize: 367518, + uncompressedSize: 378439, - compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xbd\xfb\x73\x1b\x37\x96\x30\xfa\x7b\xfe\x8a\x53\x4e\xea\x93\xb4\x11\x29\x3b\x99\x9d\xbb\xe3\x3b\xf5\xa5\x34\x92\x9c\xd5\x8d\x2d\xab\x2c\x25\xf9\x52\x4e\x36\x0b\x76\x83\x24\x56\xdd\x40\x2f\x80\xa6\xcc\xbd\xbe\xff\xfb\x2d\x1c\x00\xfd\xe0\xab\x81\x16\xe9\x38\x53\x8d\xa9\x9a\x98\x14\xfb\x34\x1e\xe7\x7d\x0e\xce\xf9\x12\x46\xfb\x1b\x5f\x7c\x09\xaf\x59\x42\xb9\xa2\x29\x68\x01\x7a\x4e\xe1\xbc\x20\xc9\x9c\xc2\x9d\x98\xea\x [...] + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xbd\xfb\x73\x1b\x37\x96\x30\xfa\x7b\xfe\x8a\x53\x4e\xea\x93\xb4\x11\x29\x3b\x99\x9d\xbb\xe3\x3b\xf5\xa5\x34\x92\x9c\xd5\x8d\x2d\xab\x2c\x25\xf9\x52\x4e\x36\x0b\x76\x83\x24\x56\xdd\x40\x2f\x80\xa6\xcc\xbd\xbe\xff\xfb\x2d\x1c\x00\xfd\xe0\xab\x81\x16\xe9\x38\x53\x8d\xa9\x9a\x98\x14\xfb\x34\x1e\xe7\x7d\x0e\xce\xf9\x12\x46\xfb\x1b\x5f\x7c\x09\xaf\x59\x42\xb9\xa2\x29\x68\x01\x7a\x4e\xe1\xbc\x20\xc9\x9c\xc2\x9d\x98\xea\x [...] }, "/crd/bases/camel.apache.org_kameletbindings.yaml": &vfsgen۰CompressedFileInfo{ name: "camel.apache.org_kameletbindings.yaml", modTime: time.Time{}, - uncompressedSize: 432689, + uncompressedSize: 444426, - compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xbd\x7b\x73\x1c\x37\x96\x2f\xf8\xbf\x3f\xc5\x09\xca\x71\x49\x8e\x59\x45\xc9\xdd\xd3\x3b\xad\xed\xb8\x0e\x36\x45\xb9\xb9\x96\xa8\x0a\x91\x96\xaf\x43\xf6\x78\x50\x99\xa8\x2a\x0c\x33\x81\x1c\x00\x59\x64\xcd\x6a\xbf\xfb\x06\x0e\x80\x7c\xd4\x8b\x40\x16\x8b\xa6\xa7\x13\x13\x31\x6d\x52\xcc\x93\x48\x3c\xce\xeb\x77\x1e\x2f\x60\xf0\x78\xe3\xab\x17\xf0\x8e\x25\x94\x2b\x9a\x82\x16\xa0\x67\x14\xce\x0a\x92\xcc\x28\x5c\x8b\x89\x [...] + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xbd\x7b\x73\x1c\x37\x96\x2f\xf8\xbf\x3f\xc5\x09\xca\x71\x49\x8e\x59\x45\xc9\xdd\xd3\x3b\xad\xed\xb8\x0e\x36\x45\xb9\xb9\x96\xa8\x0a\x91\x96\xaf\x43\xf6\x78\x50\x99\xa8\x2a\x0c\x33\x81\x1c\x00\x59\x64\xcd\x6a\xbf\xfb\x06\x0e\x80\x7c\xd4\x8b\x40\x16\x8b\xa6\xa7\x13\x13\x31\x6d\x52\xcc\x93\x48\x3c\xce\xeb\x77\x1e\x2f\x60\xf0\x78\xe3\xab\x17\xf0\x8e\x25\x94\x2b\x9a\x82\x16\xa0\x67\x14\xce\x0a\x92\xcc\x28\x5c\x8b\x89\x [...] }, "/crd/bases/camel.apache.org_kamelets.yaml": &vfsgen۰CompressedFileInfo{ name: "camel.apache.org_kamelets.yaml", @@ -530,9 +530,9 @@ var assets = func() http.FileSystem { "/templates/xml.tmpl": &vfsgen۰CompressedFileInfo{ name: "xml.tmpl", modTime: time.Time{}, - uncompressedSize: 597, + uncompressedSize: 598, - compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x92\x4f\x4b\xf4\x30\x10\xc6\xcf\x6f\x3f\xc5\xbc\xe1\x3d\xbe\x69\xba\x7a\x91\x92\x76\x41\x41\x14\xd7\x93\x8a\x5e\x43\x3b\xdb\x06\xf3\xa7\x24\xa9\xcd\x22\x7e\x77\x69\xba\xae\x2b\x5e\x74\x4e\x2d\x33\xbf\xe7\x99\x79\x08\x5f\x47\xad\xe0\x05\x9d\x97\xd6\x54\x64\x95\x17\x04\xd0\x34\xb6\x95\xa6\xab\xc8\xc3\xfd\x25\x3d\x23\xeb\x3a\xe3\x7f\x29\x85\x46\x68\x54\xf4\xb9\x04\x25\x4c\x37\x8a\x0e\xab\x99\xa5\xb4\xce\x32\xee\xec\x [...] + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x92\x4f\x4f\xe3\x30\x10\xc5\xcf\x9b\x4f\x31\x6b\xed\x71\x1d\xa7\xbb\x17\x14\x39\xa9\x04\x12\x02\x51\x4e\x80\xe0\x6a\x25\xd3\xc4\xc2\x7f\x22\xdb\x21\xae\x10\xdf\x1d\xc5\x29\xa5\xa8\x07\x98\x53\xa2\x99\xdf\x7b\x33\x4f\xe6\xeb\xa8\x15\xbc\xa0\xf3\xd2\x9a\x8a\xac\xf2\x82\x00\x9a\xc6\xb6\xd2\x74\x15\x79\xb8\xbf\xa4\x67\x64\x5d\x67\xfc\x37\xa5\xd0\x08\x8d\x8a\x3e\x97\xa0\x84\xe9\x46\xd1\x61\x35\xb3\x94\xd6\x59\xc6\x9d\x [...] }, "/templates/yaml.tmpl": &vfsgen۰CompressedFileInfo{ name: "yaml.tmpl", diff --git a/pkg/trait/pod_test.go b/pkg/trait/pod_test.go index 3df6ae2b0..e55e38821 100755 --- a/pkg/trait/pod_test.go +++ b/pkg/trait/pod_test.go @@ -22,7 +22,7 @@ import ( "github.com/stretchr/testify/assert" - "gopkg.in/yaml.v2" + "k8s.io/apimachinery/pkg/util/yaml" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -87,6 +87,18 @@ func TestChangeEnvVariables(t *testing.T) { assert.Equal(t, containsEnvVariables(templateSpec, "integration", "CAMEL_K_DIGEST"), "new_value") } +func TestSupplementalGroup(t *testing.T) { + templateString := "{containers: [], securityContext: {supplementalGroups: [666]}}}" + + templateSpec := testPodTemplateSpec(t, templateString) + + // Check if securityContext was added + assert.NotNil(t, templateSpec.Spec) + assert.NotNil(t, templateSpec.Spec.SecurityContext) + assert.NotNil(t, templateSpec.Spec.SecurityContext.SupplementalGroups) + assert.Contains(t, templateSpec.Spec.SecurityContext.SupplementalGroups, int64(666)) +} + // nolint: unparam func createPodTest(podSpecTemplate string) (*podTrait, *Environment, *appsv1.Deployment) { trait, _ := newPodTrait().(*podTrait)