From b5acd86d12bdd0d0935cbf328608f71591fa9fa8 Mon Sep 17 00:00:00 2001 From: Endre Karlson Date: Fri, 12 Nov 2021 17:50:58 +0100 Subject: [PATCH] Add support for podSecurity --- apis/v1alpha1/opentelemetrycollector_types.go | 2 + ...ntelemetry.io_opentelemetrycollectors.yaml | 157 ++++++++++++++++++ ...ntelemetry.io_opentelemetrycollectors.yaml | 157 ++++++++++++++++++ pkg/collector/daemonset.go | 1 + pkg/collector/daemonset_test.go | 28 ++++ pkg/collector/deployment.go | 1 + pkg/collector/deployment_test.go | 27 +++ pkg/collector/statefulset.go | 1 + pkg/collector/statefulset_test.go | 28 ++++ 9 files changed, 402 insertions(+) diff --git a/apis/v1alpha1/opentelemetrycollector_types.go b/apis/v1alpha1/opentelemetrycollector_types.go index 05c557f345..b4b8a63803 100644 --- a/apis/v1alpha1/opentelemetrycollector_types.go +++ b/apis/v1alpha1/opentelemetrycollector_types.go @@ -66,6 +66,8 @@ type OpenTelemetryCollectorSpec struct { // +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors=true SecurityContext *v1.SecurityContext `json:"securityContext,omitempty"` + PodSecurityContext *v1.PodSecurityContext `json:"podSecurityContext,omitempty"` + // HostNetwork indicates if the pod should run in the host networking namespace. // +optional // +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors=true diff --git a/bundle/manifests/opentelemetry.io_opentelemetrycollectors.yaml b/bundle/manifests/opentelemetry.io_opentelemetrycollectors.yaml index 4b8793621b..e475e4928a 100644 --- a/bundle/manifests/opentelemetry.io_opentelemetrycollectors.yaml +++ b/bundle/manifests/opentelemetry.io_opentelemetrycollectors.yaml @@ -231,6 +231,163 @@ spec: description: PodAnnotations is the set of annotations that will be attached to Collector and Target Allocator pods. type: object + podSecurityContext: + 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 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 ports: description: Ports allows a set of ports to be exposed by the underlying v1.Service. By default, the operator will attempt to infer the required diff --git a/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml b/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml index 6f91cf34e5..ce55cbdc73 100644 --- a/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml +++ b/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml @@ -232,6 +232,163 @@ spec: description: PodAnnotations is the set of annotations that will be attached to Collector and Target Allocator pods. type: object + podSecurityContext: + 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 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 ports: description: Ports allows a set of ports to be exposed by the underlying v1.Service. By default, the operator will attempt to infer the required diff --git a/pkg/collector/daemonset.go b/pkg/collector/daemonset.go index d84a3cf86f..97780df128 100644 --- a/pkg/collector/daemonset.go +++ b/pkg/collector/daemonset.go @@ -54,6 +54,7 @@ func DaemonSet(cfg config.Config, logger logr.Logger, otelcol v1alpha1.OpenTelem Volumes: Volumes(cfg, otelcol), Tolerations: otelcol.Spec.Tolerations, HostNetwork: otelcol.Spec.HostNetwork, + SecurityContext: otelcol.Spec.PodSecurityContext, }, }, }, diff --git a/pkg/collector/daemonset_test.go b/pkg/collector/daemonset_test.go index 60ec91a758..9d84abfe3c 100644 --- a/pkg/collector/daemonset_test.go +++ b/pkg/collector/daemonset_test.go @@ -18,6 +18,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" @@ -93,3 +94,30 @@ func TestDaemonsetPodAnnotations(t *testing.T) { assert.Equal(t, "my-instance-collector", ds.Name) assert.Equal(t, testPodAnnotationValues, ds.Spec.Template.Annotations) } + +func TestDaemonstPodSecurityContext(t *testing.T) { + runAsNonRoot := true + runAsUser := int64(1337) + runasGroup := int64(1338) + + otelcol := v1alpha1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-instance", + }, + Spec: v1alpha1.OpenTelemetryCollectorSpec{ + PodSecurityContext: &v1.PodSecurityContext{ + RunAsNonRoot: &runAsNonRoot, + RunAsUser: &runAsUser, + RunAsGroup: &runasGroup, + }, + }, + } + + cfg := config.New() + + d := DaemonSet(cfg, logger, otelcol) + + assert.Equal(t, &runAsNonRoot, d.Spec.Template.Spec.SecurityContext.RunAsNonRoot) + assert.Equal(t, &runAsUser, d.Spec.Template.Spec.SecurityContext.RunAsUser) + assert.Equal(t, &runasGroup, d.Spec.Template.Spec.SecurityContext.RunAsGroup) +} diff --git a/pkg/collector/deployment.go b/pkg/collector/deployment.go index 64b688a013..9e027d4f80 100644 --- a/pkg/collector/deployment.go +++ b/pkg/collector/deployment.go @@ -54,6 +54,7 @@ func Deployment(cfg config.Config, logger logr.Logger, otelcol v1alpha1.OpenTele Containers: []corev1.Container{Container(cfg, logger, otelcol)}, Volumes: Volumes(cfg, otelcol), Tolerations: otelcol.Spec.Tolerations, + SecurityContext: otelcol.Spec.PodSecurityContext, }, }, }, diff --git a/pkg/collector/deployment_test.go b/pkg/collector/deployment_test.go index d89d39c4ef..fb119e4414 100644 --- a/pkg/collector/deployment_test.go +++ b/pkg/collector/deployment_test.go @@ -86,3 +86,30 @@ func TestDeploymentPodAnnotations(t *testing.T) { assert.Equal(t, "my-instance-collector", d.Name) assert.Equal(t, testPodAnnotationValues, d.Spec.Template.Annotations) } + +func TestDeploymenttPodSecurityContext(t *testing.T) { + runAsNonRoot := true + runAsUser := int64(1337) + runasGroup := int64(1338) + + otelcol := v1alpha1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-instance", + }, + Spec: v1alpha1.OpenTelemetryCollectorSpec{ + PodSecurityContext: &v1.PodSecurityContext{ + RunAsNonRoot: &runAsNonRoot, + RunAsUser: &runAsUser, + RunAsGroup: &runasGroup, + }, + }, + } + + cfg := config.New() + + d := Deployment(cfg, logger, otelcol) + + assert.Equal(t, &runAsNonRoot, d.Spec.Template.Spec.SecurityContext.RunAsNonRoot) + assert.Equal(t, &runAsUser, d.Spec.Template.Spec.SecurityContext.RunAsUser) + assert.Equal(t, &runasGroup, d.Spec.Template.Spec.SecurityContext.RunAsGroup) +} diff --git a/pkg/collector/statefulset.go b/pkg/collector/statefulset.go index 8b02501c6a..d8ee3b7200 100644 --- a/pkg/collector/statefulset.go +++ b/pkg/collector/statefulset.go @@ -54,6 +54,7 @@ func StatefulSet(cfg config.Config, logger logr.Logger, otelcol v1alpha1.OpenTel Containers: []corev1.Container{Container(cfg, logger, otelcol)}, Volumes: Volumes(cfg, otelcol), Tolerations: otelcol.Spec.Tolerations, + SecurityContext: otelcol.Spec.PodSecurityContext, }, }, Replicas: otelcol.Spec.Replicas, diff --git a/pkg/collector/statefulset_test.go b/pkg/collector/statefulset_test.go index eba62de74e..8cc4e9d3f8 100644 --- a/pkg/collector/statefulset_test.go +++ b/pkg/collector/statefulset_test.go @@ -20,6 +20,7 @@ import ( "github.com/stretchr/testify/assert" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -144,3 +145,30 @@ func TestStatefulSetPodAnnotations(t *testing.T) { assert.Equal(t, "my-instance-collector", ss.Name) assert.Equal(t, testPodAnnotationValues, ss.Spec.Template.Annotations) } + +func TestStatefulSetPodSecurityContext(t *testing.T) { + runAsNonRoot := true + runAsUser := int64(1337) + runasGroup := int64(1338) + + otelcol := v1alpha1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-instance", + }, + Spec: v1alpha1.OpenTelemetryCollectorSpec{ + PodSecurityContext: &v1.PodSecurityContext{ + RunAsNonRoot: &runAsNonRoot, + RunAsUser: &runAsUser, + RunAsGroup: &runasGroup, + }, + }, + } + + cfg := config.New() + + d := StatefulSet(cfg, logger, otelcol) + + assert.Equal(t, &runAsNonRoot, d.Spec.Template.Spec.SecurityContext.RunAsNonRoot) + assert.Equal(t, &runAsUser, d.Spec.Template.Spec.SecurityContext.RunAsUser) + assert.Equal(t, &runasGroup, d.Spec.Template.Spec.SecurityContext.RunAsGroup) +}