diff --git a/apis/datadoghq/common/const.go b/apis/datadoghq/common/const.go index 217c045a5..175120340 100644 --- a/apis/datadoghq/common/const.go +++ b/apis/datadoghq/common/const.go @@ -132,6 +132,10 @@ const ( CgroupsHostPath = "/sys/fs/cgroup" CgroupsMountPath = "/host/sys/fs/cgroup" + SystemProbeOSReleaseDirVolumeName = "host-osrelease" + SystemProbeOSReleaseDirVolumePath = "/etc/os-release" + SystemProbeOSReleaseDirMountPath = "/host/etc/os-release" + SystemProbeSocketVolumeName = "sysprobe-socket-dir" SystemProbeSocketVolumePath = "/var/run/sysprobe" @@ -139,6 +143,10 @@ const ( // same path on host and container DebugfsPath = "/sys/kernel/debug" + SecurityfsVolumeName = "securityfs" + SecurityfsVolumePath = "/sys/kernel/security" + SecurityfsMountPath = "/host/sys/kernel/security" + ModulesVolumeName = "modules" // same path on host and container ModulesVolumePath = "/lib/modules" @@ -150,34 +158,38 @@ const ( AgentCustomConfigVolumePath = "/etc/datadog-agent/datadog.yaml" SystemProbeConfigVolumePath = "/etc/datadog-agent/system-probe.yaml" - LogDatadogVolumeName = "logdatadog" - LogDatadogVolumePath = "/var/log/datadog" - TmpVolumeName = "tmp" - TmpVolumePath = "/tmp" - CertificatesVolumeName = "certificates" - CertificatesVolumePath = "/etc/datadog-agent/certificates" - AuthVolumeName = "datadog-agent-auth" - AuthVolumePath = "/etc/datadog-agent/auth" - InstallInfoVolumeName = "installinfo" - InstallInfoVolumeSubPath = "install_info" - InstallInfoVolumePath = "/etc/datadog-agent/install_info" - InstallInfoVolumeReadOnly = true - PointerVolumeName = "pointerdir" - PointerVolumePath = "/opt/datadog-agent/run" - LogTempStoragePath = "/var/lib/datadog-agent/logs" - PodLogVolumeName = "logpodpath" - PodLogVolumePath = "/var/log/pods" - ContainerLogVolumeName = "logcontainerpath" - ContainerLogVolumePath = "/var/lib/docker/containers" - SymlinkContainerVolumeName = "symlinkcontainerpath" - SymlinkContainerVolumePath = "/var/log/containers" - DogstatsdHostPortName = "dogstatsdport" - DogstatsdHostPortHostPort = 8125 - DogstatsdUDSSocketName = "dsdsocket" - DogstatsdUDSHostFilepathV1 = "/var/run/datadog/statsd.sock" - DogstatsdUDSHostFilepathV2 = "/var/run/datadog/dsd.socket" - DogstatsdSocketVolumeName = "dsdsocket" - DogstatsdSocketVolumePath = "/var/run/datadog/statsd" + LogDatadogVolumeName = "logdatadog" + LogDatadogVolumePath = "/var/log/datadog" + TmpVolumeName = "tmp" + TmpVolumePath = "/tmp" + CertificatesVolumeName = "certificates" + CertificatesVolumePath = "/etc/datadog-agent/certificates" + AuthVolumeName = "datadog-agent-auth" + AuthVolumePath = "/etc/datadog-agent/auth" + InstallInfoVolumeName = "installinfo" + InstallInfoVolumeSubPath = "install_info" + InstallInfoVolumePath = "/etc/datadog-agent/install_info" + InstallInfoVolumeReadOnly = true + PointerVolumeName = "pointerdir" + PointerVolumePath = "/opt/datadog-agent/run" + LogTempStoragePath = "/var/lib/datadog-agent/logs" + PodLogVolumeName = "logpodpath" + PodLogVolumePath = "/var/log/pods" + ContainerLogVolumeName = "logcontainerpath" + ContainerLogVolumePath = "/var/lib/docker/containers" + SymlinkContainerVolumeName = "symlinkcontainerpath" + SymlinkContainerVolumePath = "/var/log/containers" + DogstatsdHostPortName = "dogstatsdport" + DogstatsdHostPortHostPort = 8125 + DogstatsdUDSSocketName = "dsdsocket" + DogstatsdUDSHostFilepathV1 = "/var/run/datadog/statsd.sock" + DogstatsdUDSHostFilepathV2 = "/var/run/datadog/dsd.socket" + DogstatsdSocketVolumeName = "dsdsocket" + DogstatsdSocketVolumePath = "/var/run/datadog/statsd" + SecurityAgentRuntimeCustomPoliciesVolumeName = "customruntimepolicies" + SecurityAgentRuntimeCustomPoliciesVolumePath = "/etc/datadog-agent-runtime-policies" + SecurityAgentRuntimePoliciesDirVolumeName = "runtimepoliciesdir" + SecurityAgentRuntimePoliciesDirVolumePath = "/etc/datadog-agent/runtime-security.d" ) const ( diff --git a/controllers/datadogagent/controller.go b/controllers/datadogagent/controller.go index 042254c8e..ff17f8010 100644 --- a/controllers/datadogagent/controller.go +++ b/controllers/datadogagent/controller.go @@ -34,6 +34,7 @@ import ( // Use to register features _ "github.com/DataDog/datadog-operator/controllers/datadogagent/feature/clusterchecks" _ "github.com/DataDog/datadog-operator/controllers/datadogagent/feature/cspm" + _ "github.com/DataDog/datadog-operator/controllers/datadogagent/feature/cws" _ "github.com/DataDog/datadog-operator/controllers/datadogagent/feature/dogstatsd" _ "github.com/DataDog/datadog-operator/controllers/datadogagent/feature/dummy" _ "github.com/DataDog/datadog-operator/controllers/datadogagent/feature/enabledefault" diff --git a/controllers/datadogagent/feature/cws/feature.go b/controllers/datadogagent/feature/cws/feature.go new file mode 100644 index 000000000..7cc958867 --- /dev/null +++ b/controllers/datadogagent/feature/cws/feature.go @@ -0,0 +1,237 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2016-present Datadog, Inc. + +package cws + +import ( + "path/filepath" + + corev1 "k8s.io/api/core/v1" + + "github.com/DataDog/datadog-operator/apis/datadoghq/v1alpha1" + "github.com/DataDog/datadog-operator/apis/datadoghq/v2alpha1" + apiutils "github.com/DataDog/datadog-operator/apis/utils" + + apicommon "github.com/DataDog/datadog-operator/apis/datadoghq/common" + apicommonv1 "github.com/DataDog/datadog-operator/apis/datadoghq/common/v1" + "github.com/DataDog/datadog-operator/controllers/datadogagent/feature" + "github.com/DataDog/datadog-operator/controllers/datadogagent/object/volume" +) + +func init() { + err := feature.Register(feature.CWSIDType, buildCWSFeature) + if err != nil { + panic(err) + } +} + +func buildCWSFeature(options *feature.Options) feature.Feature { + cwsFeat := &cwsFeature{} + + return cwsFeat +} + +type cwsFeature struct { + configMapConfig *apicommonv1.ConfigMapConfig + syscallMonitorEnabled bool +} + +// Configure is used to configure the feature from a v2alpha1.DatadogAgent instance. +func (f *cwsFeature) Configure(dda *v2alpha1.DatadogAgent) (reqComp feature.RequiredComponents) { + if dda.Spec.Features != nil && dda.Spec.Features.CWS != nil && apiutils.BoolValue(dda.Spec.Features.CWS.Enabled) { + cws := dda.Spec.Features.CWS + + f.syscallMonitorEnabled = apiutils.BoolValue(cws.SyscallMonitorEnabled) + + if cws.CustomPolicies != nil && cws.CustomPolicies.Name != "" { + f.configMapConfig = cws.CustomPolicies + } + + reqComp = feature.RequiredComponents{ + Agent: feature.RequiredComponent{ + IsRequired: apiutils.NewBoolPointer(true), + Containers: []apicommonv1.AgentContainerName{ + apicommonv1.SecurityAgentContainerName, + apicommonv1.SystemProbeContainerName, + }, + }, + } + } + + return reqComp +} + +// ConfigureV1 use to configure the feature from a v1alpha1.DatadogAgent instance. +func (f *cwsFeature) ConfigureV1(dda *v1alpha1.DatadogAgent) (reqComp feature.RequiredComponents) { + if dda.Spec.Agent.Security != nil && *dda.Spec.Agent.Security.Runtime.Enabled { + runtime := dda.Spec.Agent.Security.Runtime + + if runtime.SyscallMonitor != nil && apiutils.BoolValue(runtime.SyscallMonitor.Enabled) { + f.syscallMonitorEnabled = true + } + + if runtime.PoliciesDir != nil && runtime.PoliciesDir.ConfigMapName != "" { + f.configMapConfig = v1alpha1.ConvertConfigDirSpec(runtime.PoliciesDir).ConfigMap + } + + reqComp = feature.RequiredComponents{ + Agent: feature.RequiredComponent{ + IsRequired: apiutils.NewBoolPointer(true), + Containers: []apicommonv1.AgentContainerName{ + apicommonv1.SecurityAgentContainerName, + apicommonv1.SystemProbeContainerName, + }, + }, + } + } + + return reqComp +} + +// ManageDependencies allows a feature to manage its dependencies. +// Feature's dependencies should be added in the store. +func (f *cwsFeature) ManageDependencies(managers feature.ResourceManagers, components feature.RequiredComponents) error { + return nil +} + +// ManageClusterAgent allows a feature to configure the ClusterAgent's corev1.PodTemplateSpec +// It should do nothing if the feature doesn't need to configure it. +func (f *cwsFeature) ManageClusterAgent(managers feature.PodTemplateManagers) error { + return nil +} + +// ManageNodeAgent allows a feature to configure the Node Agent's corev1.PodTemplateSpec +// It should do nothing if the feature doesn't need to configure it. +func (f *cwsFeature) ManageNodeAgent(managers feature.PodTemplateManagers) error { + // annotations + managers.Annotation().AddAnnotation(apicommon.SystemProbeAppArmorAnnotationKey, apicommon.SystemProbeAppArmorAnnotationValue) + + // security context capabilities + capabilities := []corev1.Capability{ + "SYS_ADMIN", + "SYS_RESOURCE", + "SYS_PTRACE", + "NET_ADMIN", + "NET_BROADCAST", + "NET_RAW", + "IPC_LOCK", + "CHOWN", + } + managers.SecurityContext().AddCapabilitiesToContainer(capabilities, apicommonv1.SystemProbeContainerName) + + // envvars + enabledEnvVar := &corev1.EnvVar{ + Name: apicommon.DDRuntimeSecurityConfigEnabled, + Value: "true", + } + managers.EnvVar().AddEnvVarToContainer(apicommonv1.SecurityAgentContainerName, enabledEnvVar) + managers.EnvVar().AddEnvVarToContainer(apicommonv1.SystemProbeContainerName, enabledEnvVar) + + runtimeSocketEnvVar := &corev1.EnvVar{ + Name: apicommon.DDRuntimeSecurityConfigSocket, + Value: filepath.Join(apicommon.SystemProbeSocketVolumePath, "runtime-security.sock"), + } + managers.EnvVar().AddEnvVarToContainer(apicommonv1.SecurityAgentContainerName, runtimeSocketEnvVar) + managers.EnvVar().AddEnvVarToContainer(apicommonv1.SystemProbeContainerName, runtimeSocketEnvVar) + + if f.syscallMonitorEnabled { + monitorEnvVar := &corev1.EnvVar{ + Name: apicommon.DDRuntimeSecurityConfigSyscallMonitorEnabled, + Value: "true", + } + managers.EnvVar().AddEnvVarToContainer(apicommonv1.SecurityAgentContainerName, monitorEnvVar) + managers.EnvVar().AddEnvVarToContainer(apicommonv1.SystemProbeContainerName, monitorEnvVar) + } + + policiesDirEnvVar := &corev1.EnvVar{ + Name: apicommon.DDRuntimeSecurityConfigPoliciesDir, + Value: apicommon.SecurityAgentRuntimePoliciesDirVolumePath, + } + managers.EnvVar().AddEnvVarToContainer(apicommonv1.SystemProbeContainerName, policiesDirEnvVar) + + authTokenPathEnvVar := &corev1.EnvVar{ + Name: apicommon.DDAuthTokenFilePath, + Value: filepath.Join(apicommon.AuthVolumePath, "token"), + } + managers.EnvVar().AddEnvVarToContainer(apicommonv1.SystemProbeContainerName, authTokenPathEnvVar) + + hostRootEnvVar := &corev1.EnvVar{ + Name: apicommon.DDHostRootEnvVar, + Value: apicommon.HostRootMountPath, + } + managers.EnvVar().AddEnvVarToContainer(apicommonv1.SecurityAgentContainerName, hostRootEnvVar) + + volMountMgr := managers.VolumeMount() + volMgr := managers.Volume() + + // debugfs volume mount + debugfsVol, debugfsVolMount := volume.GetVolumes(apicommon.DebugfsVolumeName, apicommon.DebugfsPath, apicommon.DebugfsPath, false) + volMountMgr.AddVolumeMountToContainer(&debugfsVolMount, apicommonv1.SystemProbeContainerName) + volMgr.AddVolume(&debugfsVol) + + // securityfs volume mount + securityfsVol, securityfsVolMount := volume.GetVolumes(apicommon.SecurityfsVolumeName, apicommon.SecurityfsVolumePath, apicommon.SecurityfsMountPath, true) + volMountMgr.AddVolumeMountToContainer(&securityfsVolMount, apicommonv1.SystemProbeContainerName) + volMgr.AddVolume(&securityfsVol) + + // socket volume mount (needs write perms for the system probe container but not the others) + socketVol, socketVolMount := volume.GetVolumesEmptyDir(apicommon.SystemProbeSocketVolumeName, apicommon.SystemProbeSocketVolumePath, false) + volMountMgr.AddVolumeMountToContainer(&socketVolMount, apicommonv1.SystemProbeContainerName) + + _, socketVolMountReadOnly := volume.GetVolumesEmptyDir(apicommon.SystemProbeSocketVolumeName, apicommon.SystemProbeSocketVolumePath, true) + managers.VolumeMount().AddVolumeMountToContainer(&socketVolMountReadOnly, apicommonv1.SecurityAgentContainerName) + volMgr.AddVolume(&socketVol) + + // procdir volume mount + procdirVol, procdirVolMount := volume.GetVolumes(apicommon.ProcdirVolumeName, apicommon.ProcdirHostPath, apicommon.ProcdirMountPath, true) + volMountMgr.AddVolumeMountToContainer(&procdirVolMount, apicommonv1.SystemProbeContainerName) + volMgr.AddVolume(&procdirVol) + + // passwd volume mount + passwdVol, passwdVolMount := volume.GetVolumes(apicommon.PasswdVolumeName, apicommon.PasswdHostPath, apicommon.PasswdMountPath, true) + volMountMgr.AddVolumeMountToContainer(&passwdVolMount, apicommonv1.SystemProbeContainerName) + volMgr.AddVolume(&passwdVol) + + // group volume mount + groupVol, groupVolMount := volume.GetVolumes(apicommon.GroupVolumeName, apicommon.GroupHostPath, apicommon.GroupMountPath, true) + volMountMgr.AddVolumeMountToContainer(&groupVolMount, apicommonv1.SystemProbeContainerName) + volMgr.AddVolume(&groupVol) + + // osRelease volume mount + osReleaseVol, osReleaseVolMount := volume.GetVolumes(apicommon.SystemProbeOSReleaseDirVolumeName, apicommon.SystemProbeOSReleaseDirVolumePath, apicommon.SystemProbeOSReleaseDirMountPath, true) + volMountMgr.AddVolumeMountToContainer(&osReleaseVolMount, apicommonv1.SystemProbeContainerName) + volMgr.AddVolume(&osReleaseVol) + + // hostroot volume mount + hostrootVol, hostrootVolMount := volume.GetVolumes(apicommon.HostRootVolumeName, apicommon.HostRootHostPath, apicommon.HostRootMountPath, true) + volMountMgr.AddVolumeMountToContainer(&hostrootVolMount, apicommonv1.SecurityAgentContainerName) + volMgr.AddVolume(&hostrootVol) + + // custom runtime policies + if f.configMapConfig != nil { + cmVol, cmVolMount := volume.GetConfigMapVolumes( + f.configMapConfig, + f.configMapConfig.Name, + apicommon.SecurityAgentRuntimeCustomPoliciesVolumeName, + apicommon.SecurityAgentRuntimeCustomPoliciesVolumePath, + ) + volMountMgr.AddVolumeMountToContainers(&cmVolMount, []apicommonv1.AgentContainerName{apicommonv1.SecurityAgentContainerName, apicommonv1.SystemProbeContainerName}) + volMgr.AddVolume(&cmVol) + + managers.EnvVar().AddEnvVarToContainer(apicommonv1.SecurityAgentContainerName, policiesDirEnvVar) + + policiesVol, policiesVolMount := volume.GetVolumesEmptyDir(apicommon.SecurityAgentRuntimePoliciesDirVolumeName, apicommon.SecurityAgentRuntimePoliciesDirVolumePath, true) + volMountMgr.AddVolumeMountToContainers(&policiesVolMount, []apicommonv1.AgentContainerName{apicommonv1.SecurityAgentContainerName, apicommonv1.SystemProbeContainerName}) + volMgr.AddVolume(&policiesVol) + } + + return nil +} + +// ManageClusterChecksRunner allows a feature to configure the ClusterChecksRunner's corev1.PodTemplateSpec +// It should do nothing if the feature doesn't need to configure it. +func (f *cwsFeature) ManageClusterChecksRunner(managers feature.PodTemplateManagers) error { + return nil +} diff --git a/controllers/datadogagent/feature/cws/feature_test.go b/controllers/datadogagent/feature/cws/feature_test.go new file mode 100644 index 000000000..77f9957a1 --- /dev/null +++ b/controllers/datadogagent/feature/cws/feature_test.go @@ -0,0 +1,341 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2016-present Datadog, Inc. + +package cws + +import ( + "testing" + + corev1 "k8s.io/api/core/v1" + + apicommon "github.com/DataDog/datadog-operator/apis/datadoghq/common" + apicommonv1 "github.com/DataDog/datadog-operator/apis/datadoghq/common/v1" + "github.com/DataDog/datadog-operator/apis/datadoghq/v1alpha1" + "github.com/DataDog/datadog-operator/apis/datadoghq/v2alpha1" + apiutils "github.com/DataDog/datadog-operator/apis/utils" + "github.com/DataDog/datadog-operator/controllers/datadogagent/feature" + "github.com/DataDog/datadog-operator/controllers/datadogagent/feature/fake" + "github.com/DataDog/datadog-operator/controllers/datadogagent/feature/test" + "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/assert" +) + +func Test_cwsFeature_Configure(t *testing.T) { + ddav1CWSDisabled := v1alpha1.DatadogAgent{ + Spec: v1alpha1.DatadogAgentSpec{ + Agent: v1alpha1.DatadogAgentSpecAgentSpec{ + Security: &v1alpha1.SecuritySpec{ + Runtime: v1alpha1.RuntimeSecuritySpec{ + Enabled: apiutils.NewBoolPointer(false), + }, + }, + }, + }, + } + + ddav1CWSEnabled := ddav1CWSDisabled.DeepCopy() + { + ddav1CWSEnabled.Spec.Agent.Security.Runtime.Enabled = apiutils.NewBoolPointer(true) + ddav1CWSEnabled.Spec.Agent.Security.Runtime.PoliciesDir = &v1alpha1.ConfigDirSpec{ + ConfigMapName: "custom_test", + Items: []corev1.KeyToPath{ + { + Key: "key1", + Path: "some/path", + }, + }, + } + ddav1CWSEnabled.Spec.Agent.Security.Runtime.SyscallMonitor = &v1alpha1.SyscallMonitorSpec{ + Enabled: apiutils.NewBoolPointer(true), + } + } + + ddav2CWSDisabled := v2alpha1.DatadogAgent{ + Spec: v2alpha1.DatadogAgentSpec{ + Features: &v2alpha1.DatadogFeatures{ + CWS: &v2alpha1.CWSFeatureConfig{ + Enabled: apiutils.NewBoolPointer(false), + }, + }, + }, + } + ddav2CWSEnabled := ddav2CWSDisabled.DeepCopy() + { + ddav2CWSEnabled.Spec.Features.CWS.Enabled = apiutils.NewBoolPointer(true) + ddav2CWSEnabled.Spec.Features.CWS.CustomPolicies = &apicommonv1.ConfigMapConfig{ + Name: "custom_test", + Items: []corev1.KeyToPath{ + { + Key: "key1", + Path: "some/path", + }, + }, + } + ddav2CWSEnabled.Spec.Features.CWS.SyscallMonitorEnabled = apiutils.NewBoolPointer(true) + } + + cwsAgentNodeWantFunc := func(t testing.TB, mgrInterface feature.PodTemplateManagers) { + mgr := mgrInterface.(*fake.PodTemplateManagers) + + // check security context capabilities + wantCapabilities := []corev1.Capability{ + "SYS_ADMIN", + "SYS_RESOURCE", + "SYS_PTRACE", + "NET_ADMIN", + "NET_BROADCAST", + "NET_RAW", + "IPC_LOCK", + "CHOWN", + } + sysProbeCapabilities := mgr.SecurityContextMgr.CapabilitiesByC[apicommonv1.SystemProbeContainerName] + assert.True(t, apiutils.IsEqualStruct(sysProbeCapabilities, wantCapabilities), "System Probe security context capabilities \ndiff = %s", cmp.Diff(sysProbeCapabilities, wantCapabilities)) + + securityWant := []*corev1.EnvVar{ + { + Name: apicommon.DDRuntimeSecurityConfigEnabled, + Value: "true", + }, + { + Name: apicommon.DDRuntimeSecurityConfigSocket, + Value: "/var/run/sysprobe/runtime-security.sock", + }, + { + Name: apicommon.DDRuntimeSecurityConfigSyscallMonitorEnabled, + Value: "true", + }, + { + Name: apicommon.DDHostRootEnvVar, + Value: apicommon.HostRootMountPath, + }, + { + Name: apicommon.DDRuntimeSecurityConfigPoliciesDir, + Value: apicommon.SecurityAgentRuntimePoliciesDirVolumePath, + }, + } + sysProbeWant := []*corev1.EnvVar{ + { + Name: apicommon.DDRuntimeSecurityConfigEnabled, + Value: "true", + }, + { + Name: apicommon.DDRuntimeSecurityConfigSocket, + Value: "/var/run/sysprobe/runtime-security.sock", + }, + { + Name: apicommon.DDRuntimeSecurityConfigSyscallMonitorEnabled, + Value: "true", + }, + { + Name: apicommon.DDRuntimeSecurityConfigPoliciesDir, + Value: apicommon.SecurityAgentRuntimePoliciesDirVolumePath, + }, + { + Name: apicommon.DDAuthTokenFilePath, + Value: "/etc/datadog-agent/auth/token", + }, + } + securityAgentEnvVars := mgr.EnvVarMgr.EnvVarsByC[apicommonv1.SecurityAgentContainerName] + assert.True(t, apiutils.IsEqualStruct(securityAgentEnvVars, securityWant), "Security agent envvars \ndiff = %s", cmp.Diff(securityAgentEnvVars, securityWant)) + sysProbeEnvVars := mgr.EnvVarMgr.EnvVarsByC[apicommonv1.SystemProbeContainerName] + assert.True(t, apiutils.IsEqualStruct(sysProbeEnvVars, sysProbeWant), "System probe envvars \ndiff = %s", cmp.Diff(sysProbeEnvVars, sysProbeWant)) + + // check volume mounts + securityWantVolumeMount := []corev1.VolumeMount{ + { + Name: apicommon.SystemProbeSocketVolumeName, + MountPath: apicommon.SystemProbeSocketVolumePath, + ReadOnly: true, + }, + { + Name: apicommon.HostRootVolumeName, + MountPath: apicommon.HostRootMountPath, + ReadOnly: true, + }, + { + Name: apicommon.SecurityAgentRuntimeCustomPoliciesVolumeName, + MountPath: apicommon.SecurityAgentRuntimeCustomPoliciesVolumePath, + SubPath: "some/path", + ReadOnly: true, + }, + { + Name: apicommon.SecurityAgentRuntimePoliciesDirVolumeName, + MountPath: apicommon.SecurityAgentRuntimePoliciesDirVolumePath, + ReadOnly: true, + }, + } + sysprobeWantVolumeMount := []corev1.VolumeMount{ + { + Name: apicommon.DebugfsVolumeName, + MountPath: apicommon.DebugfsPath, + ReadOnly: false, + }, + { + Name: apicommon.SecurityfsVolumeName, + MountPath: apicommon.SecurityfsMountPath, + ReadOnly: true, + }, + { + Name: apicommon.SystemProbeSocketVolumeName, + MountPath: apicommon.SystemProbeSocketVolumePath, + ReadOnly: false, + }, + { + Name: apicommon.ProcdirVolumeName, + MountPath: apicommon.ProcdirMountPath, + ReadOnly: true, + }, + { + Name: apicommon.PasswdVolumeName, + MountPath: apicommon.PasswdMountPath, + ReadOnly: true, + }, + { + Name: apicommon.GroupVolumeName, + MountPath: apicommon.GroupMountPath, + ReadOnly: true, + }, + { + Name: apicommon.SystemProbeOSReleaseDirVolumeName, + MountPath: apicommon.SystemProbeOSReleaseDirMountPath, + ReadOnly: true, + }, + { + Name: apicommon.SecurityAgentRuntimeCustomPoliciesVolumeName, + MountPath: apicommon.SecurityAgentRuntimeCustomPoliciesVolumePath, + SubPath: "some/path", + ReadOnly: true, + }, + { + Name: apicommon.SecurityAgentRuntimePoliciesDirVolumeName, + MountPath: apicommon.SecurityAgentRuntimePoliciesDirVolumePath, + ReadOnly: true, + }, + } + + securityAgentVolumeMounts := mgr.VolumeMountMgr.VolumeMountsByC[apicommonv1.SecurityAgentContainerName] + assert.True(t, apiutils.IsEqualStruct(securityAgentVolumeMounts, securityWantVolumeMount), "Security Agent volume mounts \ndiff = %s", cmp.Diff(securityAgentVolumeMounts, securityWantVolumeMount)) + sysProbeVolumeMounts := mgr.VolumeMountMgr.VolumeMountsByC[apicommonv1.SystemProbeContainerName] + assert.True(t, apiutils.IsEqualStruct(sysProbeVolumeMounts, sysprobeWantVolumeMount), "System probe volume mounts \ndiff = %s", cmp.Diff(sysProbeVolumeMounts, sysprobeWantVolumeMount)) + + // check volumes + wantVolumes := []corev1.Volume{ + { + Name: apicommon.DebugfsVolumeName, + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: apicommon.DebugfsPath, + }, + }, + }, + { + Name: apicommon.SecurityfsVolumeName, + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: apicommon.SecurityfsVolumePath, + }, + }, + }, + { + Name: apicommon.SystemProbeSocketVolumeName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + { + Name: apicommon.ProcdirVolumeName, + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: apicommon.ProcdirHostPath, + }, + }, + }, + { + Name: apicommon.PasswdVolumeName, + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: apicommon.PasswdHostPath, + }, + }, + }, + { + Name: apicommon.GroupVolumeName, + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: apicommon.GroupHostPath, + }, + }, + }, + { + Name: apicommon.SystemProbeOSReleaseDirVolumeName, + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: apicommon.SystemProbeOSReleaseDirVolumePath, + }, + }, + }, + { + Name: apicommon.HostRootVolumeName, + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: apicommon.HostRootHostPath, + }, + }, + }, + { + Name: apicommon.SecurityAgentRuntimeCustomPoliciesVolumeName, + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "custom_test", + }, + }, + }, + }, + { + Name: apicommon.SecurityAgentRuntimePoliciesDirVolumeName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + } + + volumes := mgr.VolumeMgr.Volumes + assert.True(t, apiutils.IsEqualStruct(volumes, wantVolumes), "Volumes \ndiff = %s", cmp.Diff(volumes, wantVolumes)) + } + + tests := test.FeatureTestSuite{ + ////////////////////////// + // v1Alpha1.DatadogAgent + ////////////////////////// + { + Name: "v1alpha1 CWS not enabled", + DDAv1: ddav1CWSDisabled.DeepCopy(), + WantConfigure: false, + }, + { + Name: "v1alpha1 CWS enabled", + DDAv1: ddav1CWSEnabled, + WantConfigure: true, + Agent: test.NewDefaultComponentTest().WithWantFunc(cwsAgentNodeWantFunc), + }, + ////////////////////////// + // v2Alpha1.DatadogAgent + ////////////////////////// + { + Name: "v2alpha1 CWS not enabled", + DDAv2: ddav2CWSDisabled.DeepCopy(), + WantConfigure: false, + }, + { + Name: "v2alpha1 CWS enabled", + DDAv2: ddav2CWSEnabled, + WantConfigure: true, + Agent: test.NewDefaultComponentTest().WithWantFunc(cwsAgentNodeWantFunc), + }, + } + + tests.Run(t, buildCWSFeature) +} diff --git a/controllers/datadogagent/feature/ids.go b/controllers/datadogagent/feature/ids.go index 500bcc322..fd1d38583 100644 --- a/controllers/datadogagent/feature/ids.go +++ b/controllers/datadogagent/feature/ids.go @@ -25,6 +25,8 @@ const ( NPMIDType // CSPMIDType CSPM feature. CSPMIDType + // CWSIDType CWS feature. + CWSIDType // USMIDType USM feature. USMIDType // OOMKillIDType OOM Kill check feature diff --git a/controllers/datadogagent/feature/npm/feature_test.go b/controllers/datadogagent/feature/npm/feature_test.go index 3de76680e..3ce43838b 100644 --- a/controllers/datadogagent/feature/npm/feature_test.go +++ b/controllers/datadogagent/feature/npm/feature_test.go @@ -106,10 +106,10 @@ func Test_npmFeature_Configure(t *testing.T) { }) processAgentMounts := mgr.VolumeMountMgr.VolumeMountsByC[apicommonv1.ProcessAgentContainerName] - assert.True(t, apiutils.IsEqualStruct(processAgentMounts, wantProcessAgentVolMounts), "Process Agent volume mounts \ndiff = %s", cmp.Diff(processAgentMounts, wantVolumeMounts)) + assert.True(t, apiutils.IsEqualStruct(processAgentMounts, wantProcessAgentVolMounts), "Process Agent volume mounts \ndiff = %s", cmp.Diff(processAgentMounts, wantProcessAgentVolMounts)) sysProbeAgentMounts := mgr.VolumeMountMgr.VolumeMountsByC[apicommonv1.SystemProbeContainerName] - assert.True(t, apiutils.IsEqualStruct(sysProbeAgentMounts, wantSystemProbeAgentVolMounts), "System Probe volume mounts \ndiff = %s", cmp.Diff(sysProbeAgentMounts, wantVolumeMounts)) + assert.True(t, apiutils.IsEqualStruct(sysProbeAgentMounts, wantSystemProbeAgentVolMounts), "System Probe volume mounts \ndiff = %s", cmp.Diff(sysProbeAgentMounts, wantSystemProbeAgentVolMounts)) coreWantVolumeMounts := []corev1.VolumeMount{ { diff --git a/controllers/datadogagent_controller_v2_test.go b/controllers/datadogagent_controller_v2_test.go index 0f91b7f3a..3367a6223 100644 --- a/controllers/datadogagent_controller_v2_test.go +++ b/controllers/datadogagent_controller_v2_test.go @@ -94,6 +94,22 @@ var _ = Describe("V2 Controller - DatadogAgent Deployment", func() { }) }) + Context("with CWS enabled", func() { + BeforeEach(func() { + name = "with-cws" + agent = testutils.NewDatadogAgentWithCWS(namespace, name) + createAgent(&agent) + }) + + AfterEach(func() { + deleteAgent(&agent) + }) + + It("should deploy successfully", func() { + checkAgentDeployment(namespace, name) + }) + }) + Context("with Dogstatsd enabled", func() { BeforeEach(func() { name = "with-dogstatsd" diff --git a/controllers/testutils/agent.go b/controllers/testutils/agent.go index 0c16b4e27..e34476291 100644 --- a/controllers/testutils/agent.go +++ b/controllers/testutils/agent.go @@ -57,6 +57,20 @@ func NewDatadogAgentWithCSPM(namespace string, name string) v2alpha1.DatadogAgen ) } +// NewDatadogAgentWithCWS returns an agent with CWS enabled +func NewDatadogAgentWithCWS(namespace string, name string) v2alpha1.DatadogAgent { + return newDatadogAgentWithFeatures( + namespace, + name, + &v2alpha1.DatadogFeatures{ + CWS: &v2alpha1.CWSFeatureConfig{ + Enabled: apiutils.NewBoolPointer(true), + SyscallMonitorEnabled: apiutils.NewBoolPointer(true), + }, + }, + ) +} + // NewDatadogAgentWithDogstatsd returns an agent with Dogstatsd enabled func NewDatadogAgentWithDogstatsd(namespace string, name string) v2alpha1.DatadogAgent { return newDatadogAgentWithFeatures(