diff --git a/apis/datadoghq/common/const.go b/apis/datadoghq/common/const.go index 9a94e39fc..6f1cbd5d1 100644 --- a/apis/datadoghq/common/const.go +++ b/apis/datadoghq/common/const.go @@ -62,6 +62,10 @@ const ( DefaultOrchestratorExplorerConf string = "orchestrator-explorer-config" // DefaultSystemProbeSocketPath default System Probe socket path DefaultSystemProbeSocketPath string = "/var/run/sysprobe/sysprobe.sock" + // DefaultCSPMConf default CSPM ConfigMap name + DefaultCSPMConf string = "cspm-config" + // DefaultCWSConf default CWS ConfigMap name + DefaultCWSConf string = "cws-config" // Liveness probe default config DefaultLivenessProbeInitialDelaySeconds int32 = 15 @@ -163,54 +167,57 @@ 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 - DogstatsdSocketVolumeName = "dsdsocket" - DogstatsdSocketVolumePath = "/var/run/datadog/statsd" - SecurityAgentRuntimeCustomPoliciesVolumeName = "customruntimepolicies" - SecurityAgentRuntimeCustomPoliciesVolumePath = "/etc/datadog-agent-runtime-policies" - SecurityAgentRuntimePoliciesDirVolumeName = "runtimepoliciesdir" - SecurityAgentRuntimePoliciesDirVolumePath = "/etc/datadog-agent/runtime-security.d" - HostCriSocketPathPrefix = "/host" - CriSocketVolumeName = "runtimesocketdir" - RuntimeDirVolumePath = "/var/run" - KubeletAgentCAPath = "/var/run/host-kubelet-ca.crt" - KubeletCAVolumeName = "kubelet-ca" - APMHostPortName = "traceport" - APMHostPortHostPort = 8126 - APMSocketVolumeName = "apmsocket" - APMSocketVolumePath = "/var/run/datadog/apm" - AdmissionControllerPortName = "admissioncontrollerport" - OTLPGRPCPortName = "otlpgrpcport" - OTLPHTTPPortName = "otlphttpport" + 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 + DogstatsdSocketVolumeName = "dsdsocket" + DogstatsdSocketVolumePath = "/var/run/datadog/statsd" + SecurityAgentComplianceCustomConfigDirVolumeName = "customcompliancebenchmarks" + SecurityAgentComplianceConfigDirVolumeName = "compliancedir" + SecurityAgentComplianceConfigDirVolumePath = "/etc/datadog-agent/compliance.d" + SecurityAgentRuntimeCustomPoliciesVolumeName = "customruntimepolicies" + SecurityAgentRuntimeCustomPoliciesVolumePath = "/etc/datadog-agent-runtime-policies" + SecurityAgentRuntimePoliciesDirVolumeName = "runtimepoliciesdir" + SecurityAgentRuntimePoliciesDirVolumePath = "/etc/datadog-agent/runtime-security.d" + HostCriSocketPathPrefix = "/host" + CriSocketVolumeName = "runtimesocketdir" + RuntimeDirVolumePath = "/var/run" + KubeletAgentCAPath = "/var/run/host-kubelet-ca.crt" + KubeletCAVolumeName = "kubelet-ca" + APMHostPortName = "traceport" + APMHostPortHostPort = 8126 + APMSocketVolumeName = "apmsocket" + APMSocketVolumePath = "/var/run/datadog/apm" + AdmissionControllerPortName = "admissioncontrollerport" + OTLPGRPCPortName = "otlpgrpcport" + OTLPHTTPPortName = "otlphttpport" AppArmorAnnotationKey = "container.apparmor.security.beta.kubernetes.io" AgentCustomConfigVolumeName = "custom-datadog-yaml" AgentCustomConfigVolumeSubPath = "datadog.yaml" - ClusterAgentCustomConfigVolumeName = "custom-datadog-yaml" + ClusterAgentCustomConfigVolumeName = "custom-cluster-agent-yaml" ClusterAgentCustomConfigVolumePath = "/etc/datadog-agent/datadog-cluster.yaml" ClusterAgentCustomConfigVolumeSubPath = "datadog-cluster.yaml" ) diff --git a/apis/datadoghq/common/v1/types.go b/apis/datadoghq/common/v1/types.go index 46eb70510..8dcb28233 100644 --- a/apis/datadoghq/common/v1/types.go +++ b/apis/datadoghq/common/v1/types.go @@ -68,6 +68,9 @@ type KubeletConfig struct { type AgentContainerName string const ( + // InitVolumeContainerName is the name of the Init Volume init container + InitVolumeContainerName AgentContainerName = "init-volume" + // CoreAgentContainerName is the name of the Core Agent container CoreAgentContainerName AgentContainerName = "agent" // TraceAgentContainerName is the name of the Trace Agent container diff --git a/apis/datadoghq/v1alpha1/const.go b/apis/datadoghq/v1alpha1/const.go index 973895f2a..9db43b4d7 100644 --- a/apis/datadoghq/v1alpha1/const.go +++ b/apis/datadoghq/v1alpha1/const.go @@ -51,13 +51,6 @@ const ( SystemProbeUsrSrcVolumePath = "/usr/src" OrchestratorExplorerConfigVolumeName = "orchestrator-explorer-config" - SecurityAgentRuntimeCustomPoliciesVolumeName = "customruntimepolicies" - SecurityAgentRuntimePoliciesDirVolumeName = "runtimepoliciesdir" - SecurityAgentRuntimePoliciesDirVolumePath = "/etc/datadog-agent/runtime-security.d" - SecurityAgentComplianceCustomConfigDirVolumeName = "customcompliancebenchmarks" - SecurityAgentComplianceConfigDirVolumeName = "compliancedir" - SecurityAgentComplianceConfigDirVolumePath = "/etc/datadog-agent/compliance.d" - SysteProbeAppArmorAnnotationKey = "container.apparmor.security.beta.kubernetes.io/system-probe" SysteProbeSeccompAnnotationKey = "container.seccomp.security.alpha.kubernetes.io/system-probe" SystemProbeOSReleaseDirVolumeName = "host-osrelease" diff --git a/apis/datadoghq/v1alpha1/datadogagent_conversion.go b/apis/datadoghq/v1alpha1/datadogagent_conversion.go index 590c418e8..10c0e6cb6 100644 --- a/apis/datadoghq/v1alpha1/datadogagent_conversion.go +++ b/apis/datadoghq/v1alpha1/datadogagent_conversion.go @@ -203,6 +203,20 @@ func ConvertConfigDirSpec(src *ConfigDirSpec) *v2alpha1.MultiCustomConfig { } } +// ConvertConfigDirSpecToCustomConfig converts v1alpha1.ConfigDirSpec to v2alpha1.CustomConfig +func ConvertConfigDirSpecToCustomConfig(src *ConfigDirSpec) *commonv1.CustomConfig { + if src == nil { + return nil + } + + return &commonv1.CustomConfig{ + ConfigMap: &commonv1.ConfigMapConfig{ + Name: src.ConfigMapName, + Items: src.Items, + }, + } +} + // Accessors func getV2GlobalConfig(dst *v2alpha1.DatadogAgent) *v2alpha1.GlobalConfig { if dst.Spec.Global == nil { diff --git a/apis/datadoghq/v1alpha1/datadogagent_conversion_agent.go b/apis/datadoghq/v1alpha1/datadogagent_conversion_agent.go index 7df7b5fb2..bfdd05d47 100644 --- a/apis/datadoghq/v1alpha1/datadogagent_conversion_agent.go +++ b/apis/datadoghq/v1alpha1/datadogagent_conversion_agent.go @@ -416,9 +416,11 @@ func convertSecurityAgentSpec(src *SecuritySpec, dst *v2alpha1.DatadogAgent) { features.CSPM.Enabled = src.Compliance.Enabled features.CSPM.CheckInterval = src.Compliance.CheckInterval if features.CSPM.CustomBenchmarks != nil { - features.CSPM.CustomBenchmarks = &commonv1.ConfigMapConfig{ - Name: src.Compliance.ConfigDir.ConfigMapName, - Items: src.Compliance.ConfigDir.Items, + features.CSPM.CustomBenchmarks = &v2alpha1.CustomConfig{ + ConfigMap: &commonv1.ConfigMapConfig{ + Name: src.Compliance.ConfigDir.ConfigMapName, + Items: src.Compliance.ConfigDir.Items, + }, } } @@ -427,9 +429,11 @@ func convertSecurityAgentSpec(src *SecuritySpec, dst *v2alpha1.DatadogAgent) { features.CWS.SyscallMonitorEnabled = src.Runtime.SyscallMonitor.Enabled } if features.CWS.CustomPolicies != nil { - features.CWS.CustomPolicies = &commonv1.ConfigMapConfig{ - Name: src.Runtime.PoliciesDir.ConfigMapName, - Items: src.Runtime.PoliciesDir.Items, + features.CWS.CustomPolicies = &v2alpha1.CustomConfig{ + ConfigMap: &commonv1.ConfigMapConfig{ + Name: src.Runtime.PoliciesDir.ConfigMapName, + Items: src.Runtime.PoliciesDir.Items, + }, } } diff --git a/apis/datadoghq/v2alpha1/datadogagent_types.go b/apis/datadoghq/v2alpha1/datadogagent_types.go index 06786f15f..534c69d47 100644 --- a/apis/datadoghq/v2alpha1/datadogagent_types.go +++ b/apis/datadoghq/v2alpha1/datadogagent_types.go @@ -221,11 +221,11 @@ type CSPMFeatureConfig struct { // +optional CheckInterval *metav1.Duration `json:"checkInterval,omitempty"` - // ConfigMap contains CSPM benchmarks. + // CustomBenchmarks contains CSPM benchmarks. // The content of the ConfigMap will be merged with the benchmarks bundled with the agent. // Any benchmarks with the same name as those existing in the agent will take precedence. // +optional - CustomBenchmarks *commonv1.ConfigMapConfig `json:"customBenchmarks,omitempty"` + CustomBenchmarks *CustomConfig `json:"customBenchmarks,omitempty"` } // CWSFeatureConfig contains CWS (Cloud Workload Security) configuration. @@ -241,11 +241,11 @@ type CWSFeatureConfig struct { // +optional SyscallMonitorEnabled *bool `json:"syscallMonitorEnabled,omitempty"` - // ConfigMap contains security policies. + // CustomPolicies contains security policies. // The content of the ConfigMap will be merged with the policies bundled with the agent. // Any policies with the same name as those existing in the agent will take precedence. // +optional - CustomPolicies *commonv1.ConfigMapConfig `json:"customPolicies,omitempty"` + CustomPolicies *CustomConfig `json:"customPolicies,omitempty"` } // NPMFeatureConfig contains NPM (Network Performance Monitoring) feature configuration. diff --git a/apis/datadoghq/v2alpha1/zz_generated.deepcopy.go b/apis/datadoghq/v2alpha1/zz_generated.deepcopy.go index 1473fdc45..c3ab7a68e 100644 --- a/apis/datadoghq/v2alpha1/zz_generated.deepcopy.go +++ b/apis/datadoghq/v2alpha1/zz_generated.deepcopy.go @@ -97,7 +97,7 @@ func (in *CSPMFeatureConfig) DeepCopyInto(out *CSPMFeatureConfig) { } if in.CustomBenchmarks != nil { in, out := &in.CustomBenchmarks, &out.CustomBenchmarks - *out = new(commonv1.ConfigMapConfig) + *out = new(CustomConfig) (*in).DeepCopyInto(*out) } } @@ -127,7 +127,7 @@ func (in *CWSFeatureConfig) DeepCopyInto(out *CWSFeatureConfig) { } if in.CustomPolicies != nil { in, out := &in.CustomPolicies, &out.CustomPolicies - *out = new(commonv1.ConfigMapConfig) + *out = new(CustomConfig) (*in).DeepCopyInto(*out) } } diff --git a/config/crd/bases/v1/datadoghq.com_datadogagents.yaml b/config/crd/bases/v1/datadoghq.com_datadogagents.yaml index b7b658353..ab95d21ea 100644 --- a/config/crd/bases/v1/datadoghq.com_datadogagents.yaml +++ b/config/crd/bases/v1/datadoghq.com_datadogagents.yaml @@ -12816,49 +12816,60 @@ spec: description: CheckInterval defines the check interval. type: string customBenchmarks: - description: ConfigMap contains CSPM benchmarks. The content - of the ConfigMap will be merged with the benchmarks bundled - with the agent. Any benchmarks with the same name as those - existing in the agent will take precedence. + description: CustomBenchmarks contains CSPM benchmarks. The + content of the ConfigMap will be merged with the benchmarks + bundled with the agent. Any benchmarks with the same name + as those existing in the agent will take precedence. properties: - items: - description: Items maps a ConfigMap data key to a file - path mount. - items: - description: Maps a string key to a path within a volume. - properties: - key: - description: The key to project. - type: string - mode: - description: 'Optional: mode bits used to set permissions - on this file. Must be an octal value between 0000 - and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON - requires decimal values for mode bits. If not - specified, the volume defaultMode will be used. - This might be in conflict with other options that - affect the file mode, like fsGroup, and the result - can be other mode bits set.' - format: int32 - type: integer - path: - description: The relative path of the file to map - the key to. May not be an absolute path. May not - contain the path element '..'. May not start with - the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-map-keys: - - key - x-kubernetes-list-type: map - name: - description: Name is the name of the ConfigMap. + configData: + description: ConfigData corresponds to the configuration + file content. type: string + configMap: + description: ConfigMap references an existing ConfigMap + with the configuration file content. + properties: + items: + description: Items maps a ConfigMap data key to a + file path mount. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: The key to project. + type: string + mode: + description: 'Optional: mode bits used to set + permissions on this file. Must be an octal + value between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal + values for mode bits. If not specified, the + volume defaultMode will be used. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: The relative path of the file to + map the key to. May not be an absolute path. + May not contain the path element '..'. May + not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-map-keys: + - key + x-kubernetes-list-type: map + name: + description: Name is the name of the ConfigMap. + type: string + type: object type: object enabled: description: 'Enabled enables Cloud Security Posture Management. @@ -12869,49 +12880,60 @@ spec: description: CWS (Cloud Workload Security) configuration. properties: customPolicies: - description: ConfigMap contains security policies. The content - of the ConfigMap will be merged with the policies bundled - with the agent. Any policies with the same name as those - existing in the agent will take precedence. + description: CustomPolicies contains security policies. The + content of the ConfigMap will be merged with the policies + bundled with the agent. Any policies with the same name + as those existing in the agent will take precedence. properties: - items: - description: Items maps a ConfigMap data key to a file - path mount. - items: - description: Maps a string key to a path within a volume. - properties: - key: - description: The key to project. - type: string - mode: - description: 'Optional: mode bits used to set permissions - on this file. Must be an octal value between 0000 - and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON - requires decimal values for mode bits. If not - specified, the volume defaultMode will be used. - This might be in conflict with other options that - affect the file mode, like fsGroup, and the result - can be other mode bits set.' - format: int32 - type: integer - path: - description: The relative path of the file to map - the key to. May not be an absolute path. May not - contain the path element '..'. May not start with - the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-map-keys: - - key - x-kubernetes-list-type: map - name: - description: Name is the name of the ConfigMap. + configData: + description: ConfigData corresponds to the configuration + file content. type: string + configMap: + description: ConfigMap references an existing ConfigMap + with the configuration file content. + properties: + items: + description: Items maps a ConfigMap data key to a + file path mount. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: The key to project. + type: string + mode: + description: 'Optional: mode bits used to set + permissions on this file. Must be an octal + value between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal + values for mode bits. If not specified, the + volume defaultMode will be used. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: The relative path of the file to + map the key to. May not be an absolute path. + May not contain the path element '..'. May + not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-map-keys: + - key + x-kubernetes-list-type: map + name: + description: Name is the name of the ConfigMap. + type: string + type: object type: object enabled: description: 'Enabled enables Cloud Workload Security. Default: diff --git a/config/crd/bases/v1beta1/datadoghq.com_datadogagents.yaml b/config/crd/bases/v1beta1/datadoghq.com_datadogagents.yaml index 4266e2ee8..20220e498 100644 --- a/config/crd/bases/v1beta1/datadoghq.com_datadogagents.yaml +++ b/config/crd/bases/v1beta1/datadoghq.com_datadogagents.yaml @@ -25760,49 +25760,60 @@ spec: description: CheckInterval defines the check interval. type: string customBenchmarks: - description: ConfigMap contains CSPM benchmarks. The content - of the ConfigMap will be merged with the benchmarks bundled - with the agent. Any benchmarks with the same name as those - existing in the agent will take precedence. + description: CustomBenchmarks contains CSPM benchmarks. The + content of the ConfigMap will be merged with the benchmarks + bundled with the agent. Any benchmarks with the same name + as those existing in the agent will take precedence. properties: - items: - description: Items maps a ConfigMap data key to a file - path mount. - items: - description: Maps a string key to a path within a volume. - properties: - key: - description: The key to project. - type: string - mode: - description: 'Optional: mode bits used to set permissions - on this file. Must be an octal value between 0000 - and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON - requires decimal values for mode bits. If not - specified, the volume defaultMode will be used. - This might be in conflict with other options that - affect the file mode, like fsGroup, and the result - can be other mode bits set.' - format: int32 - type: integer - path: - description: The relative path of the file to map - the key to. May not be an absolute path. May not - contain the path element '..'. May not start with - the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-map-keys: - - key - x-kubernetes-list-type: map - name: - description: Name is the name of the ConfigMap. + configData: + description: ConfigData corresponds to the configuration + file content. type: string + configMap: + description: ConfigMap references an existing ConfigMap + with the configuration file content. + properties: + items: + description: Items maps a ConfigMap data key to a + file path mount. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: The key to project. + type: string + mode: + description: 'Optional: mode bits used to set + permissions on this file. Must be an octal + value between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal + values for mode bits. If not specified, the + volume defaultMode will be used. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: The relative path of the file to + map the key to. May not be an absolute path. + May not contain the path element '..'. May + not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-map-keys: + - key + x-kubernetes-list-type: map + name: + description: Name is the name of the ConfigMap. + type: string + type: object type: object enabled: description: 'Enabled enables Cloud Security Posture Management. @@ -25813,49 +25824,60 @@ spec: description: CWS (Cloud Workload Security) configuration. properties: customPolicies: - description: ConfigMap contains security policies. The content - of the ConfigMap will be merged with the policies bundled - with the agent. Any policies with the same name as those - existing in the agent will take precedence. + description: CustomPolicies contains security policies. The + content of the ConfigMap will be merged with the policies + bundled with the agent. Any policies with the same name + as those existing in the agent will take precedence. properties: - items: - description: Items maps a ConfigMap data key to a file - path mount. - items: - description: Maps a string key to a path within a volume. - properties: - key: - description: The key to project. - type: string - mode: - description: 'Optional: mode bits used to set permissions - on this file. Must be an octal value between 0000 - and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON - requires decimal values for mode bits. If not - specified, the volume defaultMode will be used. - This might be in conflict with other options that - affect the file mode, like fsGroup, and the result - can be other mode bits set.' - format: int32 - type: integer - path: - description: The relative path of the file to map - the key to. May not be an absolute path. May not - contain the path element '..'. May not start with - the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-map-keys: - - key - x-kubernetes-list-type: map - name: - description: Name is the name of the ConfigMap. + configData: + description: ConfigData corresponds to the configuration + file content. type: string + configMap: + description: ConfigMap references an existing ConfigMap + with the configuration file content. + properties: + items: + description: Items maps a ConfigMap data key to a + file path mount. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: The key to project. + type: string + mode: + description: 'Optional: mode bits used to set + permissions on this file. Must be an octal + value between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal + values for mode bits. If not specified, the + volume defaultMode will be used. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: The relative path of the file to + map the key to. May not be an absolute path. + May not contain the path element '..'. May + not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-map-keys: + - key + x-kubernetes-list-type: map + name: + description: Name is the name of the ConfigMap. + type: string + type: object type: object enabled: description: 'Enabled enables Cloud Workload Security. Default: diff --git a/controllers/datadogagent/agent_test.go b/controllers/datadogagent/agent_test.go index 7c31f0c4a..bc4cd1554 100644 --- a/controllers/datadogagent/agent_test.go +++ b/controllers/datadogagent/agent_test.go @@ -369,7 +369,7 @@ func complianceSecurityAgentVolumes() []corev1.Volume { }, }, { - Name: datadoghqv1alpha1.SecurityAgentComplianceConfigDirVolumeName, + Name: apicommon.SecurityAgentComplianceConfigDirVolumeName, VolumeSource: corev1.VolumeSource{ EmptyDir: &corev1.EmptyDirVolumeSource{}, }, @@ -572,7 +572,7 @@ func runtimeSecurityAgentVolumes() []corev1.Volume { }, }, { - Name: datadoghqv1alpha1.SecurityAgentRuntimeCustomPoliciesVolumeName, + Name: apicommon.SecurityAgentRuntimeCustomPoliciesVolumeName, VolumeSource: corev1.VolumeSource{ ConfigMap: &corev1.ConfigMapVolumeSource{ LocalObjectReference: corev1.LocalObjectReference{ @@ -582,7 +582,7 @@ func runtimeSecurityAgentVolumes() []corev1.Volume { }, }, { - Name: datadoghqv1alpha1.SecurityAgentRuntimePoliciesDirVolumeName, + Name: apicommon.SecurityAgentRuntimePoliciesDirVolumeName, VolumeSource: corev1.VolumeSource{ EmptyDir: &corev1.EmptyDirVolumeSource{}, }, @@ -1639,16 +1639,16 @@ func runtimeSecurityAgentPodSpec(extraEnv map[string]string, extraDir string) co command = []string{"cp -vnr /etc/datadog-agent /opt;cp -v /etc/datadog-agent-runtime-policies/* /opt/datadog-agent/runtime-security.d/"} volumeMountsBuilder.Add(&corev1.VolumeMount{ - Name: datadoghqv1alpha1.SecurityAgentRuntimePoliciesDirVolumeName, + Name: apicommon.SecurityAgentRuntimePoliciesDirVolumeName, MountPath: "/opt/datadog-agent/runtime-security.d", }) volumeMountsBuilder.Add(&corev1.VolumeMount{ - Name: datadoghqv1alpha1.SecurityAgentRuntimeCustomPoliciesVolumeName, + Name: apicommon.SecurityAgentRuntimeCustomPoliciesVolumeName, MountPath: "/etc/datadog-agent-runtime-policies", }) volumesBuilder.Add(&corev1.Volume{ - Name: datadoghqv1alpha1.SecurityAgentRuntimeCustomPoliciesVolumeName, + Name: apicommon.SecurityAgentRuntimeCustomPoliciesVolumeName, VolumeSource: corev1.VolumeSource{ ConfigMap: &corev1.ConfigMapVolumeSource{ LocalObjectReference: corev1.LocalObjectReference{ @@ -1659,7 +1659,7 @@ func runtimeSecurityAgentPodSpec(extraEnv map[string]string, extraDir string) co }) volumesBuilder.Add(&corev1.Volume{ - Name: datadoghqv1alpha1.SecurityAgentRuntimePoliciesDirVolumeName, + Name: apicommon.SecurityAgentRuntimePoliciesDirVolumeName, VolumeSource: corev1.VolumeSource{ EmptyDir: &corev1.EmptyDirVolumeSource{}, }, @@ -2390,7 +2390,12 @@ func Test_newExtendedDaemonSetFromInstance_CustomConfigMaps(t *testing.T) { } func Test_newExtendedDaemonSetFromInstance_CustomDatadogYaml(t *testing.T) { - customConfigMapCustomDatadogYaml := test.NewDefaultedDatadogAgent("bar", "foo", &test.NewDatadogAgentOptions{UseEDS: true, ClusterAgentEnabled: true, APMEnabled: true, CustomConfig: "foo: bar\nbar: foo"}) + customConfigMapCustomDatadogYaml := test.NewDefaultedDatadogAgent( + "bar", "foo", + &test.NewDatadogAgentOptions{ + UseEDS: true, ClusterAgentEnabled: true, APMEnabled: true, CustomConfig: "foo: bar\nbar: foo", + }, + ) customConfigMapCustomDatadogYamlSpec := defaultPodSpec(customConfigMapCustomDatadogYaml) appendDefaultAPMAgentContainer(&customConfigMapCustomDatadogYamlSpec) @@ -2458,11 +2463,11 @@ func Test_newExtendedDaemonSetFromInstance_CustomDatadogYaml(t *testing.T) { }, }, { - Name: apicommon.AgentCustomConfigVolumeName, + Name: "foo-datadog-yaml", VolumeSource: corev1.VolumeSource{ ConfigMap: &corev1.ConfigMapVolumeSource{ LocalObjectReference: corev1.LocalObjectReference{ - Name: "foo-datadog-yaml", + Name: "custom-datadog-yaml", }, }, }, @@ -3440,14 +3445,14 @@ func Test_newExtendedDaemonSetFromInstance_SecurityAgent_Runtime(t *testing.T) { }...) securityAgentPodSpec.Containers[1].VolumeMounts = append(securityAgentPodSpec.Containers[1].VolumeMounts, []corev1.VolumeMount{ { - Name: datadoghqv1alpha1.SecurityAgentRuntimePoliciesDirVolumeName, + Name: apicommon.SecurityAgentRuntimePoliciesDirVolumeName, MountPath: "/etc/datadog-agent/runtime-security.d", ReadOnly: true, }, }...) securityAgentPodSpec.Containers[2].VolumeMounts = append(securityAgentPodSpec.Containers[2].VolumeMounts, []corev1.VolumeMount{ { - Name: datadoghqv1alpha1.SecurityAgentRuntimePoliciesDirVolumeName, + Name: apicommon.SecurityAgentRuntimePoliciesDirVolumeName, MountPath: "/etc/datadog-agent/runtime-security.d", ReadOnly: true, }, diff --git a/controllers/datadogagent/clusteragent.go b/controllers/datadogagent/clusteragent.go index 91580fcdc..6ded12787 100644 --- a/controllers/datadogagent/clusteragent.go +++ b/controllers/datadogagent/clusteragent.go @@ -338,7 +338,7 @@ func newClusterAgentPodTemplate(logger logr.Logger, dda *datadoghqv1alpha1.Datad if isComplianceEnabled(&dda.Spec) { if dda.Spec.Agent.Security.Compliance.ConfigDir != nil { volumes = append(volumes, corev1.Volume{ - Name: datadoghqv1alpha1.SecurityAgentComplianceConfigDirVolumeName, + Name: apicommon.SecurityAgentComplianceConfigDirVolumeName, VolumeSource: corev1.VolumeSource{ ConfigMap: &corev1.ConfigMapVolumeSource{ LocalObjectReference: corev1.LocalObjectReference{ @@ -348,8 +348,8 @@ func newClusterAgentPodTemplate(logger logr.Logger, dda *datadoghqv1alpha1.Datad }, }) volumeMounts = append(volumeMounts, corev1.VolumeMount{ - Name: datadoghqv1alpha1.SecurityAgentComplianceConfigDirVolumeName, - MountPath: datadoghqv1alpha1.SecurityAgentComplianceConfigDirVolumePath, + Name: apicommon.SecurityAgentComplianceConfigDirVolumeName, + MountPath: apicommon.SecurityAgentComplianceConfigDirVolumePath, ReadOnly: true, }) } @@ -561,7 +561,7 @@ func getEnvVarsForClusterAgent(logger logr.Logger, dda *datadoghqv1alpha1.Datado if dda.Spec.Agent.Security.Compliance.ConfigDir != nil { envVars = append(envVars, corev1.EnvVar{ Name: apicommon.DDComplianceConfigDir, - Value: datadoghqv1alpha1.SecurityAgentComplianceConfigDirVolumePath, + Value: apicommon.SecurityAgentComplianceConfigDirVolumePath, }) } } diff --git a/controllers/datadogagent/clusteragent_test.go b/controllers/datadogagent/clusteragent_test.go index 75ce2951e..61893cd83 100644 --- a/controllers/datadogagent/clusteragent_test.go +++ b/controllers/datadogagent/clusteragent_test.go @@ -484,7 +484,7 @@ func Test_newClusterAgentDeploymentMountKSMCore(t *testing.T) { Enabled: &enabledFeature, Conf: &datadoghqv1alpha1.CustomConfigSpec{ ConfigMap: &datadoghqv1alpha1.ConfigFileConfigMapSpec{ - Name: "bla", + Name: "foo", FileKey: "ksm_core.yaml", }, }, @@ -495,8 +495,9 @@ func Test_newClusterAgentDeploymentMountKSMCore(t *testing.T) { VolumeSource: v1.VolumeSource{ ConfigMap: &v1.ConfigMapVolumeSource{ LocalObjectReference: v1.LocalObjectReference{ - Name: "bla", + Name: "foo", }, + Items: []v1.KeyToPath{{Key: "ksm_core.yaml", Path: "ksm_core.yaml"}}, }, }, }, @@ -505,7 +506,6 @@ func Test_newClusterAgentDeploymentMountKSMCore(t *testing.T) { { Name: "ksm-core-config", MountPath: "/etc/datadog-agent/conf.d/kubernetes_state_core.d", - SubPath: "ksm_core.yaml", ReadOnly: true, }, } @@ -519,7 +519,7 @@ func Test_newClusterAgentDeploymentMountKSMCore(t *testing.T) { }, { Name: apicommon.DDKubeStateMetricsCoreConfigMap, - Value: "bla", + Value: "foo", }, { Name: orchestrator.DDOrchestratorExplorerEnabled, diff --git a/controllers/datadogagent/common_configmap.go b/controllers/datadogagent/common_configmap.go index 47ba96cd6..f71780582 100644 --- a/controllers/datadogagent/common_configmap.go +++ b/controllers/datadogagent/common_configmap.go @@ -141,5 +141,5 @@ func buildConfigurationConfigMap(owner metav1.Object, cfcm *commonv1.CustomConfi return nil, nil } - return configmap.BuildConfiguration(owner.GetNamespace(), cfcm.ConfigData, configMapName, subPath) + return configmap.BuildConfigMapConfigData(owner.GetNamespace(), cfcm.ConfigData, configMapName, subPath) } diff --git a/controllers/datadogagent/controller_reconcile_v2.go b/controllers/datadogagent/controller_reconcile_v2.go index 2b41ef3ed..586a88373 100644 --- a/controllers/datadogagent/controller_reconcile_v2.go +++ b/controllers/datadogagent/controller_reconcile_v2.go @@ -114,7 +114,7 @@ func (r *Reconciler) reconcileInstanceV2(ctx context.Context, logger logr.Logger } // Examine user configuration to override any external dependencies (e.g. RBACs) - errs = append(errs, override.Dependencies(logger, resourceManagers, instance.Spec.Override, instance.Namespace)...) + errs = append(errs, override.Dependencies(logger, resourceManagers, instance.Spec.Override, instance.Name, instance.Namespace)...) userSpecifiedClusterAgentToken := instance.Spec.Global.ClusterAgentToken != nil || instance.Spec.Global.ClusterAgentTokenSecret != nil if !userSpecifiedClusterAgentToken { diff --git a/controllers/datadogagent/feature/cspm/const.go b/controllers/datadogagent/feature/cspm/const.go index 4c6753ac1..1a8595e1c 100644 --- a/controllers/datadogagent/feature/cspm/const.go +++ b/controllers/datadogagent/feature/cspm/const.go @@ -14,7 +14,7 @@ import ( const ( cspmRBACPrefix = "cspm" cspmConfigVolumeName = "complianceconfigdir" - cspmConfigVolumePath = "/etc/datadog-agent/compliance.d" + cspmConfFileName = "compliance.yaml" ) func getSCCName(owner metav1.Object) string { diff --git a/controllers/datadogagent/feature/cspm/feature.go b/controllers/datadogagent/feature/cspm/feature.go index d14381841..40f659a86 100644 --- a/controllers/datadogagent/feature/cspm/feature.go +++ b/controllers/datadogagent/feature/cspm/feature.go @@ -14,6 +14,8 @@ import ( "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/object/configmap" + "github.com/DataDog/datadog-operator/pkg/kubernetes" apicommon "github.com/DataDog/datadog-operator/apis/datadoghq/common" apicommonv1 "github.com/DataDog/datadog-operator/apis/datadoghq/common/v1" @@ -38,7 +40,7 @@ type cspmFeature struct { enable bool serviceAccountName string checkInterval string - configMapConfig *apicommonv1.ConfigMapConfig + customConfig *apicommonv1.CustomConfig configMapName string createSCC bool createPSP bool @@ -64,11 +66,11 @@ func (f *cspmFeature) Configure(dda *v2alpha1.DatadogAgent) (reqComp feature.Req } if dda.Spec.Features.CSPM.CustomBenchmarks != nil { - f.configMapName = dda.Spec.Features.CSPM.CustomBenchmarks.Name - f.configMapConfig = dda.Spec.Features.CSPM.CustomBenchmarks + f.customConfig = v2alpha1.ConvertCustomConfig(dda.Spec.Features.CSPM.CustomBenchmarks) } + f.configMapName = apicommonv1.GetConfName(dda, f.customConfig, apicommon.DefaultCSPMConf) - // TODO add settings to configure f.createSCC and f.createPSP + // CELENE TODO add settings to configure f.createSCC and f.createPSP reqComp = feature.RequiredComponents{ ClusterAgent: feature.RequiredComponent{IsRequired: apiutils.NewBoolPointer(true)}, @@ -98,7 +100,7 @@ func (f *cspmFeature) ConfigureV1(dda *v1alpha1.DatadogAgent) (reqComp feature.R if dda.Spec.Agent.Security.Compliance.ConfigDir != nil { f.configMapName = dda.Spec.Agent.Security.Compliance.ConfigDir.ConfigMapName - f.configMapConfig = v1alpha1.ConvertConfigDirSpec(dda.Spec.Agent.Security.Compliance.ConfigDir).ConfigMap + f.customConfig = v1alpha1.ConvertConfigDirSpecToCustomConfig(dda.Spec.Agent.Security.Compliance.ConfigDir) } reqComp = feature.RequiredComponents{ @@ -118,6 +120,19 @@ func (f *cspmFeature) ConfigureV1(dda *v1alpha1.DatadogAgent) (reqComp feature.R // ManageDependencies allows a feature to manage its dependencies. // Feature's dependencies should be added in the store. func (f *cspmFeature) ManageDependencies(managers feature.ResourceManagers, components feature.RequiredComponents) error { + // Create configMap if one does not already exist and ConfigData is defined + if f.customConfig != nil && f.customConfig.ConfigMap == nil && f.customConfig.ConfigData != nil { + cm, err := configmap.BuildConfigMapConfigData(f.owner.GetNamespace(), f.customConfig.ConfigData, f.configMapName, cspmConfFileName) + if err != nil { + return err + } + if cm != nil { + if err := managers.Store().AddOrUpdate(kubernetes.ConfigMapKind, cm); err != nil { + return err + } + } + } + if f.createSCC { // Manage SecurityContextConstraints sccName := getSCCName(f.owner) @@ -149,15 +164,39 @@ func (f *cspmFeature) ManageDependencies(managers feature.ResourceManagers, comp // 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 *cspmFeature) ManageClusterAgent(managers feature.PodTemplateManagers) error { - if f.configMapConfig != nil && f.configMapName != "" { - cmVol, cmVolMount := volume.GetConfigMapVolumes( - f.configMapConfig, - f.configMapName, - cspmConfigVolumeName, - cspmConfigVolumePath, - ) - managers.VolumeMount().AddVolumeMountToContainer(&cmVolMount, apicommonv1.ClusterAgentContainerName) - managers.Volume().AddVolume(&cmVol) + if f.customConfig != nil { + var vol corev1.Volume + var volMount corev1.VolumeMount + if f.customConfig.ConfigMap != nil { + // Custom config is referenced via ConfigMap + // Cannot use standard GetVolumesFromConfigMap because security features are not under /conf.d + vol = volume.GetVolumeFromConfigMap(f.customConfig.ConfigMap, f.configMapName, cspmConfigVolumeName) + + // Need to use subpaths so that existing configurations are not overwritten + for _, item := range f.customConfig.ConfigMap.Items { + volMount = corev1.VolumeMount{ + Name: cspmConfigVolumeName, + MountPath: apicommon.SecurityAgentComplianceConfigDirVolumePath + "/" + item.Path, + SubPath: item.Path, + ReadOnly: true, + } + + managers.VolumeMount().AddVolumeMountToContainer(&volMount, apicommonv1.ClusterAgentContainerName) + } + } else { + // Custom config is referenced via ConfigData (and configMap is created in ManageDependencies) + vol = volume.GetBasicVolume(f.configMapName, cspmConfigVolumeName) + + // Need to use subpaths so that existing configurations are not overwritten + volMount = volume.GetVolumeMountWithSubPath( + cspmConfigVolumeName, + apicommon.SecurityAgentComplianceConfigDirVolumePath+"/"+cspmConfFileName, + cspmConfFileName, + ) + managers.VolumeMount().AddVolumeMountToContainer(&volMount, apicommonv1.ClusterAgentContainerName) + } + // Mount custom policies to cluster agent container. + managers.Volume().AddVolume(&vol) } enabledEnvVar := &corev1.EnvVar{ @@ -190,16 +229,54 @@ func (f *cspmFeature) ManageNodeAgent(managers feature.PodTemplateManagers) erro volMountMgr := managers.VolumeMount() VolMgr := managers.Volume() - // configmap volume mount - if f.configMapConfig != nil && f.configMapName != "" { - cmVol, cmVolMount := volume.GetConfigMapVolumes( - f.configMapConfig, - f.configMapName, - cspmConfigVolumeName, - cspmConfigVolumePath, - ) - volMountMgr.AddVolumeMountToContainer(&cmVolMount, apicommonv1.SecurityAgentContainerName) - VolMgr.AddVolume(&cmVol) + // Custom policies are copied and merged with default policies via a workaround in the init-volume container. + if f.customConfig != nil { + var vol corev1.Volume + var volMount corev1.VolumeMount + if f.customConfig.ConfigMap != nil { + // Custom config is referenced via ConfigMap + // Cannot use typical GetVolumesFromConfigMap because security features are not under /conf.d + vol = volume.GetVolumeFromConfigMap(f.customConfig.ConfigMap, f.configMapName, cspmConfigVolumeName) + volMount = corev1.VolumeMount{ + Name: cspmConfigVolumeName, + MountPath: "/etc/datadog-agent-compliance-benchmarks", + ReadOnly: true, + } + } else { + // Custom config is referenced via ConfigData (and configMap is created in ManageDependencies) + vol = volume.GetBasicVolume(f.configMapName, cspmConfigVolumeName) + + volMount = corev1.VolumeMount{ + Name: cspmConfigVolumeName, + MountPath: "/etc/datadog-agent-compliance-benchmarks", + ReadOnly: true, + } + } + // Mount custom policies to init-volume container. + managers.VolumeMount().AddVolumeMountToInitContainer(&volMount, apicommonv1.InitVolumeContainerName) + managers.Volume().AddVolume(&vol) + + // Add workaround command to init-volume container + for id, container := range managers.PodTemplateSpec().Spec.InitContainers { + if container.Name == "init-volume" { + managers.PodTemplateSpec().Spec.InitContainers[id].Args = []string{ + managers.PodTemplateSpec().Spec.InitContainers[id].Args[0] + ";cp -v /etc/datadog-agent-compliance-benchmarks/* /opt/datadog-agent/compliance.d/", + } + } + } + + // Add empty volume to Security Agent + benchmarksVol, benchmarksVolMount := volume.GetVolumesEmptyDir(apicommon.SecurityAgentComplianceConfigDirVolumeName, apicommon.SecurityAgentComplianceConfigDirVolumePath, true) + managers.Volume().AddVolume(&benchmarksVol) + managers.VolumeMount().AddVolumeMountToContainer(&benchmarksVolMount, apicommonv1.SecurityAgentContainerName) + + // Add compliance.d volume mount to init-volume container at different path + benchmarkVolMountInitVol := corev1.VolumeMount{ + Name: apicommon.SecurityAgentComplianceConfigDirVolumeName, + MountPath: "/opt/datadog-agent/compliance.d", + ReadOnly: false, + } + volMountMgr.AddVolumeMountToInitContainer(&benchmarkVolMountInitVol, apicommonv1.InitVolumeContainerName) } // cgroups volume mount diff --git a/controllers/datadogagent/feature/cspm/feature_test.go b/controllers/datadogagent/feature/cspm/feature_test.go index a0ca3bc1f..beced665f 100644 --- a/controllers/datadogagent/feature/cspm/feature_test.go +++ b/controllers/datadogagent/feature/cspm/feature_test.go @@ -64,12 +64,14 @@ func Test_cspmFeature_Configure(t *testing.T) { ddav2CSPMEnabled := ddav2CSPMDisabled.DeepCopy() { ddav2CSPMEnabled.Spec.Features.CSPM.Enabled = apiutils.NewBoolPointer(true) - ddav2CSPMEnabled.Spec.Features.CSPM.CustomBenchmarks = &apicommonv1.ConfigMapConfig{ - Name: "custom_test", - Items: []corev1.KeyToPath{ - { - Key: "key1", - Path: "some/path", + ddav2CSPMEnabled.Spec.Features.CSPM.CustomBenchmarks = &v2alpha1.CustomConfig{ + ConfigMap: &apicommonv1.ConfigMapConfig{ + Name: "custom_test", + Items: []corev1.KeyToPath{ + { + Key: "key1", + Path: "some/path", + }, }, }, } @@ -95,7 +97,7 @@ func Test_cspmFeature_Configure(t *testing.T) { wantVolumeMounts := []corev1.VolumeMount{ { Name: cspmConfigVolumeName, - MountPath: cspmConfigVolumePath, + MountPath: "/etc/datadog-agent/compliance.d/some/path", SubPath: "some/path", ReadOnly: true, }, @@ -112,6 +114,7 @@ func Test_cspmFeature_Configure(t *testing.T) { LocalObjectReference: corev1.LocalObjectReference{ Name: "custom_test", }, + Items: []corev1.KeyToPath{{Key: "key1", Path: "some/path"}}, }, }, }, @@ -143,9 +146,8 @@ func Test_cspmFeature_Configure(t *testing.T) { // check volume mounts wantVolumeMounts := []corev1.VolumeMount{ { - Name: cspmConfigVolumeName, - MountPath: cspmConfigVolumePath, - SubPath: "some/path", + Name: apicommon.SecurityAgentComplianceConfigDirVolumeName, + MountPath: "/etc/datadog-agent/compliance.d", ReadOnly: true, }, { @@ -187,9 +189,16 @@ func Test_cspmFeature_Configure(t *testing.T) { LocalObjectReference: corev1.LocalObjectReference{ Name: "custom_test", }, + Items: []corev1.KeyToPath{{Key: "key1", Path: "some/path"}}, }, }, }, + { + Name: apicommon.SecurityAgentComplianceConfigDirVolumeName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, { Name: apicommon.CgroupsVolumeName, VolumeSource: corev1.VolumeSource{ diff --git a/controllers/datadogagent/feature/cws/const.go b/controllers/datadogagent/feature/cws/const.go new file mode 100644 index 000000000..0ec194d74 --- /dev/null +++ b/controllers/datadogagent/feature/cws/const.go @@ -0,0 +1,11 @@ +// 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 + +const ( + cwsConfigVolumeName = "customruntimepoliciesdir" + cwsConfFileName = "runtime-security.yaml" +) diff --git a/controllers/datadogagent/feature/cws/feature.go b/controllers/datadogagent/feature/cws/feature.go index 8e77ca8f4..d0f7f0e69 100644 --- a/controllers/datadogagent/feature/cws/feature.go +++ b/controllers/datadogagent/feature/cws/feature.go @@ -8,12 +8,15 @@ package cws import ( "path/filepath" - "github.com/DataDog/datadog-operator/controllers/datadogagent/component/agent" corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/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/component/agent" + "github.com/DataDog/datadog-operator/controllers/datadogagent/object/configmap" + "github.com/DataDog/datadog-operator/pkg/kubernetes" apicommon "github.com/DataDog/datadog-operator/apis/datadoghq/common" apicommonv1 "github.com/DataDog/datadog-operator/apis/datadoghq/common/v1" @@ -35,8 +38,10 @@ func buildCWSFeature(options *feature.Options) feature.Feature { } type cwsFeature struct { - configMapConfig *apicommonv1.ConfigMapConfig syscallMonitorEnabled bool + customConfig *apicommonv1.CustomConfig + configMapName string + owner metav1.Object } // ID returns the ID of the Feature @@ -46,14 +51,17 @@ func (f *cwsFeature) ID() feature.IDType { // Configure is used to configure the feature from a v2alpha1.DatadogAgent instance. func (f *cwsFeature) Configure(dda *v2alpha1.DatadogAgent) (reqComp feature.RequiredComponents) { + f.owner = dda + 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 + if cws.CustomPolicies != nil { + f.customConfig = v2alpha1.ConvertCustomConfig(cws.CustomPolicies) } + f.configMapName = apicommonv1.GetConfName(dda, f.customConfig, apicommon.DefaultCWSConf) reqComp = feature.RequiredComponents{ Agent: feature.RequiredComponent{ @@ -79,7 +87,8 @@ func (f *cwsFeature) ConfigureV1(dda *v1alpha1.DatadogAgent) (reqComp feature.Re } if runtime.PoliciesDir != nil && runtime.PoliciesDir.ConfigMapName != "" { - f.configMapConfig = v1alpha1.ConvertConfigDirSpec(runtime.PoliciesDir).ConfigMap + f.configMapName = runtime.PoliciesDir.ConfigMapName + f.customConfig = v1alpha1.ConvertConfigDirSpecToCustomConfig(runtime.PoliciesDir) } reqComp = feature.RequiredComponents{ @@ -99,6 +108,18 @@ func (f *cwsFeature) ConfigureV1(dda *v1alpha1.DatadogAgent) (reqComp feature.Re // 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 { + // Create configMap if one does not already exist and ConfigData is defined + if f.customConfig != nil && f.customConfig.ConfigMap == nil && f.customConfig.ConfigData != nil { + cm, err := configmap.BuildConfigMapConfigData(f.owner.GetNamespace(), f.customConfig.ConfigData, f.configMapName, cwsConfFileName) + if err != nil { + return err + } + if cm != nil { + if err := managers.Store().AddOrUpdate(kubernetes.ConfigMapKind, cm); err != nil { + return err + } + } + } return nil } @@ -199,22 +220,56 @@ func (f *cwsFeature) ManageNodeAgent(managers feature.PodTemplateManagers) error 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) + // Custom policies are copied and merged with default policies via a workaround in the init-volume container. + if f.customConfig != nil { + var vol corev1.Volume + var volMount corev1.VolumeMount + if f.customConfig.ConfigMap != nil { + // Custom config is referenced via ConfigMap + // Cannot use standard GetVolumesFromConfigMap because security features are not under /conf.d + vol = volume.GetVolumeFromConfigMap(f.customConfig.ConfigMap, f.configMapName, cwsConfigVolumeName) + volMount = corev1.VolumeMount{ + Name: cwsConfigVolumeName, + MountPath: apicommon.SecurityAgentRuntimeCustomPoliciesVolumePath, + ReadOnly: true, + } + } else { + // Custom config is referenced via ConfigData (and configMap is created in ManageDependencies) + vol = volume.GetBasicVolume(f.configMapName, cwsConfigVolumeName) + + volMount = corev1.VolumeMount{ + Name: cwsConfigVolumeName, + MountPath: apicommon.SecurityAgentRuntimeCustomPoliciesVolumePath, + ReadOnly: true, + } + } + // Mount custom policies to init-volume container. + managers.VolumeMount().AddVolumeMountToInitContainer(&volMount, apicommonv1.InitVolumeContainerName) + managers.Volume().AddVolume(&vol) + + // Add workaround command to init-volume container + for id, container := range managers.PodTemplateSpec().Spec.InitContainers { + if container.Name == "init-volume" { + managers.PodTemplateSpec().Spec.InitContainers[id].Args = []string{ + managers.PodTemplateSpec().Spec.InitContainers[id].Args[0] + ";cp -v /etc/datadog-agent-runtime-policies/* /opt/datadog-agent/runtime-security.d/", + } + } + } + // Add policies directory envvar to Security Agent, and empty volume to System Probe and Security Agent. 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) + volMountMgr.AddVolumeMountToContainers(&policiesVolMount, []apicommonv1.AgentContainerName{apicommonv1.SecurityAgentContainerName, apicommonv1.SystemProbeContainerName}) + + // Add runtime-security.d volume mount to init-volume container at different path + policiesVolMountInitVol := corev1.VolumeMount{ + Name: apicommon.SecurityAgentRuntimePoliciesDirVolumeName, + MountPath: "/opt/datadog-agent/runtime-security.d", + ReadOnly: false, + } + volMountMgr.AddVolumeMountToInitContainer(&policiesVolMountInitVol, apicommonv1.InitVolumeContainerName) } return nil diff --git a/controllers/datadogagent/feature/cws/feature_test.go b/controllers/datadogagent/feature/cws/feature_test.go index 5561705ae..978b85701 100644 --- a/controllers/datadogagent/feature/cws/feature_test.go +++ b/controllers/datadogagent/feature/cws/feature_test.go @@ -65,12 +65,14 @@ func Test_cwsFeature_Configure(t *testing.T) { 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.CustomPolicies = &v2alpha1.CustomConfig{ + ConfigMap: &apicommonv1.ConfigMapConfig{ + Name: "custom_test", + Items: []corev1.KeyToPath{ + { + Key: "key1", + Path: "some/path", + }, }, }, } @@ -141,12 +143,6 @@ func Test_cwsFeature_Configure(t *testing.T) { MountPath: apicommon.HostRootMountPath, ReadOnly: true, }, - { - Name: apicommon.SecurityAgentRuntimeCustomPoliciesVolumeName, - MountPath: apicommon.SecurityAgentRuntimeCustomPoliciesVolumePath, - SubPath: "some/path", - ReadOnly: true, - }, { Name: apicommon.SecurityAgentRuntimePoliciesDirVolumeName, MountPath: apicommon.SecurityAgentRuntimePoliciesDirVolumePath, @@ -189,12 +185,6 @@ func Test_cwsFeature_Configure(t *testing.T) { MountPath: apicommon.SystemProbeOSReleaseDirMountPath, ReadOnly: true, }, - { - Name: apicommon.SecurityAgentRuntimeCustomPoliciesVolumeName, - MountPath: apicommon.SecurityAgentRuntimeCustomPoliciesVolumePath, - SubPath: "some/path", - ReadOnly: true, - }, { Name: apicommon.SecurityAgentRuntimePoliciesDirVolumeName, MountPath: apicommon.SecurityAgentRuntimePoliciesDirVolumePath, @@ -272,12 +262,13 @@ func Test_cwsFeature_Configure(t *testing.T) { }, }, { - Name: apicommon.SecurityAgentRuntimeCustomPoliciesVolumeName, + Name: cwsConfigVolumeName, VolumeSource: corev1.VolumeSource{ ConfigMap: &corev1.ConfigMapVolumeSource{ LocalObjectReference: corev1.LocalObjectReference{ Name: "custom_test", }, + Items: []corev1.KeyToPath{{Key: "key1", Path: "some/path"}}, }, }, }, diff --git a/controllers/datadogagent/feature/kubernetesstatecore/configmap.go b/controllers/datadogagent/feature/kubernetesstatecore/configmap.go index 402fd36e4..f81c0a838 100644 --- a/controllers/datadogagent/feature/kubernetesstatecore/configmap.go +++ b/controllers/datadogagent/feature/kubernetesstatecore/configmap.go @@ -19,7 +19,7 @@ func (f *ksmFeature) buildKSMCoreConfigMap() (*corev1.ConfigMap, error) { return nil, nil } if f.customConfig != nil && f.customConfig.ConfigData != nil { - return configmap.BuildConfiguration(f.owner.GetNamespace(), f.customConfig.ConfigData, f.configConfigMapName, ksmCoreCheckName) + return configmap.BuildConfigMapConfigData(f.owner.GetNamespace(), f.customConfig.ConfigData, f.configConfigMapName, ksmCoreCheckName) } configMap := buildDefaultConfigMap(f.owner.GetNamespace(), f.configConfigMapName, ksmCheckConfig(f.runInClusterChecksRunner)) diff --git a/controllers/datadogagent/feature/kubernetesstatecore/feature.go b/controllers/datadogagent/feature/kubernetesstatecore/feature.go index 9a28e6cb7..bfa5386fd 100644 --- a/controllers/datadogagent/feature/kubernetesstatecore/feature.go +++ b/controllers/datadogagent/feature/kubernetesstatecore/feature.go @@ -6,6 +6,8 @@ package kubernetesstatecore import ( + "fmt" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -121,7 +123,8 @@ func (f *ksmFeature) ConfigureV1(dda *v1alpha1.DatadogAgent) feature.RequiredCom // ManageDependencies allows a feature to manage its dependencies. // Feature's dependencies should be added in the store. func (f *ksmFeature) ManageDependencies(managers feature.ResourceManagers, components feature.RequiredComponents) error { - // Manage the Check Configuration in a configmap + // Create a configMap if CustomConfig.ConfigData is provided and CustomConfig.ConfigMap == nil, + // OR if the default configMap is needed. configCM, err := f.buildKSMCoreConfigMap() if err != nil { return err @@ -132,7 +135,7 @@ func (f *ksmFeature) ManageDependencies(managers feature.ResourceManagers, compo } } - // Manager RBAC permission + // Manage RBAC permission rbacName := GetKubeStateMetricsRBACResourceName(f.owner, f.rbacSuffix) return managers.RBACManager().AddClusterPolicyRules(f.owner.GetNamespace(), rbacName, f.serviceAccountName, getRBACPolicyRules()) @@ -142,13 +145,25 @@ func (f *ksmFeature) ManageDependencies(managers feature.ResourceManagers, compo // It should do nothing if the feature doesn't need to configure it. func (f *ksmFeature) ManageClusterAgent(managers feature.PodTemplateManagers) error { // Manage KSM config in configmap - vol, volMount := volume.GetCustomConfigSpecVolumes( - f.customConfig, - apicommon.KubeStateMetricCoreVolumeName, - f.configConfigMapName, - ksmCoreCheckFolderName, - ) - + var vol corev1.Volume + var volMount corev1.VolumeMount + if f.customConfig != nil && f.customConfig.ConfigMap != nil { + // Custom config is referenced via ConfigMap + vol, volMount = volume.GetVolumesFromConfigMap( + f.customConfig.ConfigMap, + apicommon.KubeStateMetricCoreVolumeName, + f.configConfigMapName, + ksmCoreCheckFolderName, + ) + } else { + // Otherwise, configMap was created in ManageDependencies (whether from CustomConfig.ConfigData or using defaults, so mount default volume) + vol = volume.GetBasicVolume(f.configConfigMapName, apicommon.KubeStateMetricCoreVolumeName) + volMount = corev1.VolumeMount{ + Name: apicommon.KubeStateMetricCoreVolumeName, + MountPath: fmt.Sprintf("%s%s/%s", apicommon.ConfigVolumePath, apicommon.ConfdVolumePath, ksmCoreCheckFolderName), + ReadOnly: true, + } + } managers.VolumeMount().AddVolumeMountToContainer(&volMount, apicommonv1.ClusterAgentContainerName) managers.Volume().AddVolume(&vol) diff --git a/controllers/datadogagent/feature/orchestratorexplorer/configmap.go b/controllers/datadogagent/feature/orchestratorexplorer/configmap.go index 3cee366d2..cfdc84c50 100644 --- a/controllers/datadogagent/feature/orchestratorexplorer/configmap.go +++ b/controllers/datadogagent/feature/orchestratorexplorer/configmap.go @@ -19,7 +19,7 @@ func (f *orchestratorExplorerFeature) buildOrchestratorExplorerConfigMap() (*cor return nil, nil } if f.customConfig != nil && f.customConfig.ConfigData != nil { - return configmap.BuildConfiguration(f.owner.GetNamespace(), f.customConfig.ConfigData, f.configConfigMapName, orchestratorExplorerCheckName) + return configmap.BuildConfigMapConfigData(f.owner.GetNamespace(), f.customConfig.ConfigData, f.configConfigMapName, orchestratorExplorerConfFileName) } configMap := buildDefaultConfigMap(f.owner.GetNamespace(), f.configConfigMapName, orchestratorExplorerCheckConfig(f.clusterChecksEnabled)) @@ -33,7 +33,7 @@ func buildDefaultConfigMap(namespace, cmName string, content string) *corev1.Con Namespace: namespace, }, Data: map[string]string{ - orchestratorExplorerCheckName: content, + orchestratorExplorerConfFileName: content, }, } return configMap diff --git a/controllers/datadogagent/feature/orchestratorexplorer/const.go b/controllers/datadogagent/feature/orchestratorexplorer/const.go index d35186776..c9ec0699a 100644 --- a/controllers/datadogagent/feature/orchestratorexplorer/const.go +++ b/controllers/datadogagent/feature/orchestratorexplorer/const.go @@ -12,9 +12,9 @@ import ( ) const ( - orchestratorExplorerRBACPrefix = "orch-exp" - orchestratorExplorerCheckName = "orchestrator.yaml" - orchestratorExplorerCheckFolderName = "orchestrator.d" + orchestratorExplorerRBACPrefix = "orch-exp" + orchestratorExplorerConfFileName = "orchestrator.yaml" + orchestratorExplorerFolderName = "orchestrator.d" ) // GetOrchestratorExplorerRBACResourceName returns the RBAC resources name diff --git a/controllers/datadogagent/feature/orchestratorexplorer/feature.go b/controllers/datadogagent/feature/orchestratorexplorer/feature.go index 7b3cb5f2a..d3386397d 100644 --- a/controllers/datadogagent/feature/orchestratorexplorer/feature.go +++ b/controllers/datadogagent/feature/orchestratorexplorer/feature.go @@ -6,6 +6,9 @@ package orchestratorexplorer import ( + "fmt" + + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/DataDog/datadog-operator/apis/datadoghq/v1alpha1" @@ -135,7 +138,8 @@ func (f *orchestratorExplorerFeature) ConfigureV1(dda *v1alpha1.DatadogAgent) (r // ManageDependencies allows a feature to manage its dependencies. // Feature's dependencies should be added in the store. func (f *orchestratorExplorerFeature) ManageDependencies(managers feature.ResourceManagers, components feature.RequiredComponents) error { - // Manage the Check Configuration in a configmap + // Create a configMap if CustomConfig.ConfigData is provided and CustomConfig.ConfigMap == nil, + // OR if the default configMap is needed. configCM, err := f.buildOrchestratorExplorerConfigMap() if err != nil { return err @@ -146,7 +150,7 @@ func (f *orchestratorExplorerFeature) ManageDependencies(managers feature.Resour } } - // Manager RBAC permission + // Manage RBAC permission rbacName := GetOrchestratorExplorerRBACResourceName(f.owner, f.rbacSuffix) return managers.RBACManager().AddClusterPolicyRules(f.owner.GetNamespace(), rbacName, f.serviceAccountName, getRBACPolicyRules()) @@ -156,12 +160,26 @@ func (f *orchestratorExplorerFeature) ManageDependencies(managers feature.Resour // It should do nothing if the feature doesn't need to configure it. func (f *orchestratorExplorerFeature) ManageClusterAgent(managers feature.PodTemplateManagers) error { // Manage orchestrator config in configmap - vol, volMount := volume.GetCustomConfigSpecVolumes( - f.customConfig, - apicommon.OrchestratorExplorerVolumeName, - f.configConfigMapName, - orchestratorExplorerCheckFolderName, - ) + var vol corev1.Volume + var volMount corev1.VolumeMount + if f.customConfig != nil && f.customConfig.ConfigMap != nil { + // Custom config is referenced via ConfigMap + vol, volMount = volume.GetVolumesFromConfigMap( + f.customConfig.ConfigMap, + apicommon.OrchestratorExplorerVolumeName, + f.configConfigMapName, + orchestratorExplorerFolderName, + ) + } else { + // Otherwise, configMap was created in ManageDependencies (whether from CustomConfig.ConfigData or using defaults, so mount default volume) + vol = volume.GetBasicVolume(f.configConfigMapName, apicommon.OrchestratorExplorerVolumeName) + + volMount = corev1.VolumeMount{ + Name: apicommon.OrchestratorExplorerVolumeName, + MountPath: fmt.Sprintf("%s%s/%s", apicommon.ConfigVolumePath, apicommon.ConfdVolumePath, orchestratorExplorerFolderName), + ReadOnly: true, + } + } managers.VolumeMount().AddVolumeMountToContainer(&volMount, apicommonv1.ClusterAgentContainerName) managers.Volume().AddVolume(&vol) diff --git a/controllers/datadogagent/finalizer.go b/controllers/datadogagent/finalizer.go index 6360024ea..9f870e58a 100644 --- a/controllers/datadogagent/finalizer.go +++ b/controllers/datadogagent/finalizer.go @@ -115,7 +115,7 @@ func (r *Reconciler) finalizeDadV2(reqLogger logr.Logger, obj client.Object) { } // Examine user configuration to override any external dependencies (e.g. RBACs) - errs = append(errs, override.Dependencies(reqLogger, resourceManagers, dda.Spec.Override, dda.Namespace)...) + errs = append(errs, override.Dependencies(reqLogger, resourceManagers, dda.Spec.Override, dda.Name, dda.Namespace)...) if len(errs) > 0 { reqLogger.Info("Errors calculating dependencies while finalizing the DatadogAgent", "errors", errs) diff --git a/controllers/datadogagent/merger/fake/volume_mount_manager.go b/controllers/datadogagent/merger/fake/volume_mount_manager.go index 40c70e0c5..4ada80764 100644 --- a/controllers/datadogagent/merger/fake/volume_mount_manager.go +++ b/controllers/datadogagent/merger/fake/volume_mount_manager.go @@ -26,6 +26,11 @@ func (_m *VolumeMountManager) AddVolumeMountToContainer(volumeMount *v1.VolumeMo _m.VolumeMountsByC[containerName] = append(_m.VolumeMountsByC[containerName], volumeMount) } +// AddVolumeMountToInitContainer provides a mock function with given fields: volumeMount, containerName +func (_m *VolumeMountManager) AddVolumeMountToInitContainer(volumeMount *v1.VolumeMount, containerName commonv1.AgentContainerName) { + _m.VolumeMountsByC[containerName] = append(_m.VolumeMountsByC[containerName], volumeMount) +} + // AddVolumeMountToContainers provides a mock function with given fields: volume, volumeMount, containerNames func (_m *VolumeMountManager) AddVolumeMountToContainers(volumeMount *v1.VolumeMount, containerNames []commonv1.AgentContainerName) { for _, c := range containerNames { diff --git a/controllers/datadogagent/merger/volume_mount.go b/controllers/datadogagent/merger/volume_mount.go index 421fd21da..66b766a28 100644 --- a/controllers/datadogagent/merger/volume_mount.go +++ b/controllers/datadogagent/merger/volume_mount.go @@ -16,6 +16,8 @@ type VolumeMountManager interface { AddVolumeMount(volumeMount *corev1.VolumeMount) // Add the volumeMount to one container of the PodTemplate. AddVolumeMountToContainer(volumeMount *corev1.VolumeMount, containerName commonv1.AgentContainerName) + // Add the volumeMount to an init container pfo the PodTemplate. + AddVolumeMountToInitContainer(volumeMount *corev1.VolumeMount, containerName commonv1.AgentContainerName) // Add the volumeMount to a list of containers in the PodTemplate. AddVolumeMountToContainers(volumeMount *corev1.VolumeMount, containerNames []commonv1.AgentContainerName) // Add the volumeMount to the container matching the containerName. @@ -46,6 +48,14 @@ func (impl *volumeMountManagerImpl) AddVolumeMountToContainer(volumeMount *corev } } +func (impl *volumeMountManagerImpl) AddVolumeMountToInitContainer(volumeMount *corev1.VolumeMount, containerName commonv1.AgentContainerName) { + for id, container := range impl.podTmpl.Spec.InitContainers { + if container.Name == string(containerName) { + _, _ = AddVolumeMountToContainerWithMergeFunc(&impl.podTmpl.Spec.InitContainers[id], volumeMount, DefaultVolumeMountMergeFunction) + } + } +} + func (impl *volumeMountManagerImpl) AddVolumeMountToContainers(volumeMount *corev1.VolumeMount, containerNames []commonv1.AgentContainerName) { for _, containerName := range containerNames { impl.AddVolumeMountToContainer(volumeMount, containerName) @@ -54,8 +64,9 @@ func (impl *volumeMountManagerImpl) AddVolumeMountToContainers(volumeMount *core func (impl *volumeMountManagerImpl) AddVolumeMountWithMergeFunc(volumeMount *corev1.VolumeMount, volumeMountMergeFunc VolumeMountMergeFunction) error { for id := range impl.podTmpl.Spec.Containers { - _, err := AddVolumeMountToContainerWithMergeFunc(&impl.podTmpl.Spec.Containers[id], volumeMount, volumeMountMergeFunc) - return err + if _, err := AddVolumeMountToContainerWithMergeFunc(&impl.podTmpl.Spec.Containers[id], volumeMount, volumeMountMergeFunc); err != nil { + return err + } } return nil } diff --git a/controllers/datadogagent/object/configmap/configmap.go b/controllers/datadogagent/object/configmap/configmap.go index 7b56a11cd..87e7daff6 100644 --- a/controllers/datadogagent/object/configmap/configmap.go +++ b/controllers/datadogagent/object/configmap/configmap.go @@ -15,8 +15,8 @@ import ( "k8s.io/apimachinery/pkg/util/errors" ) -// BuildConfiguration use to generate a configmap containing a configuration file in yaml. -func BuildConfiguration(namespace string, configDataPointer *string, configMapName, subPath string) (*corev1.ConfigMap, error) { +// BuildConfigMapConfigData use to generate a configmap containing a configuration file in yaml. +func BuildConfigMapConfigData(namespace string, configDataPointer *string, configMapName, subPath string) (*corev1.ConfigMap, error) { if configDataPointer == nil { return nil, nil } diff --git a/controllers/datadogagent/object/volume/volumes.go b/controllers/datadogagent/object/volume/volumes.go index 468c96bef..ef4220b4a 100644 --- a/controllers/datadogagent/object/volume/volumes.go +++ b/controllers/datadogagent/object/volume/volumes.go @@ -7,11 +7,14 @@ package volume import ( "fmt" + "sort" + "gopkg.in/yaml.v2" 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/v2alpha1" ) // GetVolumes creates a corev1.Volume and corev1.VolumeMount corresponding to a host path. @@ -56,54 +59,74 @@ func GetVolumesEmptyDir(volumeName, mountPath string, readOnly bool) (corev1.Vol return volume, volumeMount } -// GetCustomConfigSpecVolumes use to generate the corev1.Volume and corev1.VolumeMount corresponding to a CustomConfig. -func GetCustomConfigSpecVolumes(customConfig *apicommonv1.CustomConfig, volumeName, defaultCMName, configFolder string) (corev1.Volume, corev1.VolumeMount) { - var volume corev1.Volume - var volumeMount corev1.VolumeMount - if customConfig != nil { - volume = GetVolumeFromCustomConfigSpec( - customConfig, - defaultCMName, - volumeName, - ) - // subpath only updated to Filekey if config uses configMap, default to ksmCoreCheckName for configData. - volumeMount = GetVolumeMountFromCustomConfigSpec( - customConfig, - volumeName, - fmt.Sprintf("%s%s/%s", apicommon.ConfigVolumePath, apicommon.ConfdVolumePath, configFolder), - "", - ) - } else { - volume = corev1.Volume{ - Name: volumeName, - VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: defaultCMName, - }, - }, - }, - } - volumeMount = corev1.VolumeMount{ - Name: volumeName, - MountPath: fmt.Sprintf("%s%s/%s", apicommon.ConfigVolumePath, apicommon.ConfdVolumePath, configFolder), - ReadOnly: true, - } +// common ConfigMapConfig + +// GetVolumesFromConfigMap returns a Volume and VolumeMount from a ConfigMapConfig. It is only used in the features that are within the conf.d/ file path +func GetVolumesFromConfigMap(configMap *apicommonv1.ConfigMapConfig, volumeName, defaultCMName, configFolder string) (corev1.Volume, corev1.VolumeMount) { + volume := GetVolumeFromConfigMap( + configMap, + defaultCMName, + volumeName, + ) + + volumeMount := corev1.VolumeMount{ + Name: volumeName, + MountPath: fmt.Sprintf("%s%s/%s", apicommon.ConfigVolumePath, apicommon.ConfdVolumePath, configFolder), + ReadOnly: true, } return volume, volumeMount } -// GetVolumeFromCustomConfigSpec return a corev1.Volume corresponding to a CustomConfig. -func GetVolumeFromCustomConfigSpec(cfcm *apicommonv1.CustomConfig, defaultConfigMapName, volumeName string) corev1.Volume { - confdVolumeSource := *buildVolumeSourceFromCustomConfigSpec(cfcm, defaultConfigMapName) +// GetVolumeFromConfigMap returns a Volume from a common ConfigMapConfig. +func GetVolumeFromConfigMap(configMap *apicommonv1.ConfigMapConfig, defaultConfigMapName, volumeName string) corev1.Volume { + cmName := defaultConfigMapName + if configMap != nil && len(configMap.Name) > 0 { + cmName = configMap.Name + } + + cmSource := &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: cmName, + }, + } + + if len(configMap.Items) > 0 { + cmSource.Items = configMap.Items + } return corev1.Volume{ - Name: volumeName, - VolumeSource: confdVolumeSource, + Name: volumeName, + VolumeSource: corev1.VolumeSource{ + ConfigMap: cmSource, + }, } } -// GetVolumeMountFromCustomConfigSpec return a corev1.Volume corresponding to a CustomConfig. +// common CustomConfig + +// GetVolumeFromCustomConfigSpec return a corev1.Volume corresponding to a CustomConfig. This is only used in v1alpha1. +func GetVolumeFromCustomConfigSpec(customConfig *apicommonv1.CustomConfig, volumeName, defaultConfigMapName string) corev1.Volume { + configMap := customConfig.ConfigMap + cmName := defaultConfigMapName + if configMap != nil && len(configMap.Name) > 0 { + cmName = configMap.Name + } + + cmSource := &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: cmName, + }, + } + + return corev1.Volume{ + Name: volumeName, + VolumeSource: corev1.VolumeSource{ + ConfigMap: cmSource, + }, + } +} + +// GetVolumeMountFromCustomConfigSpec return a corev1.Volume corresponding to a common CustomConfig. It is only used in v1alpha1. func GetVolumeMountFromCustomConfigSpec(cfcm *apicommonv1.CustomConfig, volumeName, volumePath, defaultSubPath string) corev1.VolumeMount { subPath := defaultSubPath if cfcm.ConfigMap != nil && len(cfcm.ConfigMap.Items) > 0 { @@ -118,52 +141,84 @@ func GetVolumeMountFromCustomConfigSpec(cfcm *apicommonv1.CustomConfig, volumeNa } } -func buildVolumeSourceFromCustomConfigSpec(configDir *apicommonv1.CustomConfig, defaultConfigMapName string) *corev1.VolumeSource { - if configDir == nil { - return nil - } - - // TODO configDir.ConfigData is ignored; should it be? +// v2alpha1 CustomConfig, MultiCustomConfig, and others - return buildVolumeSourceFromConfigMapConfig(configDir.ConfigMap, defaultConfigMapName) +// GetVolumeFromCustomConfig returns a Volume from a v2alpha1 CustomConfig. It is used for agent-level configuration overrides in v2alpha1. +func GetVolumeFromCustomConfig(customConfig v2alpha1.CustomConfig, defaultConfigMapName, volumeName string) corev1.Volume { + var vol corev1.Volume + if customConfig.ConfigMap != nil { + vol = GetVolumeFromConfigMap( + customConfig.ConfigMap, + defaultConfigMapName, + volumeName, + ) + } else if customConfig.ConfigData != nil { + vol = GetBasicVolume(defaultConfigMapName, volumeName) + } + return vol } -// GetConfigMapVolumes is used to generate the corev1.Volume and corev1.VolumeMount corresponding to a ConfigMapConfig. -func GetConfigMapVolumes(configMap *apicommonv1.ConfigMapConfig, defaultCMName, volumeName, volumePath string) (corev1.Volume, corev1.VolumeMount) { - var volume corev1.Volume - var volumeMount corev1.VolumeMount - volume = GetVolumeFromConfigMapConfig( - configMap, - defaultCMName, - volumeName, - ) - - volumeMount = GetVolumeMountFromConfigMapConfig( - configMap, - volumeName, - volumePath, - "", - ) - return volume, volumeMount +// GetVolumeFromMultiCustomConfig returns a Volume from a v2alpha1 MultiCustomConfig. It is used for Extra Checksd and Extra Confd. +func GetVolumeFromMultiCustomConfig(multiCustomConfig *v2alpha1.MultiCustomConfig, volumeName, configMapName string) corev1.Volume { + var vol corev1.Volume + if multiCustomConfig.ConfigMap != nil { + vol = corev1.Volume{ + Name: volumeName, + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: multiCustomConfig.ConfigMap.Name, + }, + Items: multiCustomConfig.ConfigMap.Items, + }, + }, + } + } else if multiCustomConfig.ConfigDataMap != nil { + // Sort map so that order is consistent between reconcile loops + sortedKeys := sortKeys(multiCustomConfig.ConfigDataMap) + keysToPaths := []corev1.KeyToPath{} + for _, filename := range sortedKeys { + configData := multiCustomConfig.ConfigDataMap[filename] + // Validate that user input is valid YAML + m := make(map[interface{}]interface{}) + if yaml.Unmarshal([]byte(configData), m) != nil { + continue + } + keysToPaths = append(keysToPaths, corev1.KeyToPath{Key: filename, Path: filename}) + } + vol = corev1.Volume{ + Name: volumeName, + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: configMapName, + }, + Items: keysToPaths, + }, + }, + } + } + return vol } -// GetVolumeFromConfigMapConfig returns a corev1.Volume corresponding to a ConfigMapConfig. -func GetVolumeFromConfigMapConfig(configMap *apicommonv1.ConfigMapConfig, defaultConfigMapName, volumeName string) corev1.Volume { - confdVolumeSource := *buildVolumeSourceFromConfigMapConfig(configMap, defaultConfigMapName) - +// GetBasicVolume returns a basic Volume from a config map name and volume name. It is used in features and overrides. +func GetBasicVolume(configMapName, volumeName string) corev1.Volume { return corev1.Volume{ - Name: volumeName, - VolumeSource: confdVolumeSource, + Name: volumeName, + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: configMapName, + }, + }, + }, } } -// GetVolumeMountFromConfigMapConfig returns a corev1.Volume corresponding to a ConfigMapConfig. -func GetVolumeMountFromConfigMapConfig(configMap *apicommonv1.ConfigMapConfig, volumeName, volumePath, defaultSubPath string) corev1.VolumeMount { - subPath := defaultSubPath - if configMap != nil && len(configMap.Items) > 0 { - subPath = configMap.Items[0].Path - } - +// GetVolumeMountWithSubPath return a corev1.VolumeMount with a subPath. The subPath is needed +// in situations when a specific file needs to be mounted without affecting the rest of the directory. +// This is used in features and overrides. +func GetVolumeMountWithSubPath(volumeName, volumePath, subPath string) corev1.VolumeMount { return corev1.VolumeMount{ Name: volumeName, MountPath: volumePath, @@ -172,19 +227,13 @@ func GetVolumeMountFromConfigMapConfig(configMap *apicommonv1.ConfigMapConfig, v } } -func buildVolumeSourceFromConfigMapConfig(configMap *apicommonv1.ConfigMapConfig, defaultConfigMapName string) *corev1.VolumeSource { - cmName := defaultConfigMapName - if configMap != nil && len(configMap.Name) > 0 { - cmName = configMap.Name - } - - cmSource := &corev1.ConfigMapVolumeSource{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: cmName, - }, - } - - return &corev1.VolumeSource{ - ConfigMap: cmSource, +func sortKeys(keysMap map[string]string) []string { + sortedKeys := make([]string, 0, len(keysMap)) + for key := range keysMap { + sortedKeys = append(sortedKeys, key) } + sort.Slice(sortedKeys, func(i, j int) bool { + return sortedKeys[i] < sortedKeys[j] + }) + return sortedKeys } diff --git a/controllers/datadogagent/override/dependencies.go b/controllers/datadogagent/override/dependencies.go index 4680bf4e5..4bad93f30 100644 --- a/controllers/datadogagent/override/dependencies.go +++ b/controllers/datadogagent/override/dependencies.go @@ -17,13 +17,16 @@ import ( ) // Dependencies is used to override any resource/dependency settings with a v2alpha1.DatadogAgentComponentOverride. -func Dependencies(logger logr.Logger, manager feature.ResourceManagers, overrides map[v2alpha1.ComponentName]*v2alpha1.DatadogAgentComponentOverride, namespace string) (errs []error) { +func Dependencies(logger logr.Logger, manager feature.ResourceManagers, overrides map[v2alpha1.ComponentName]*v2alpha1.DatadogAgentComponentOverride, ddaName, namespace string) (errs []error) { for component, override := range overrides { err := overrideRBAC(logger, manager, override, component, namespace) if err != nil { errs = append(errs, err) } + // Handle custom agent configurations (datadog.yaml, cluster-agent.yaml, etc.) + errs = append(errs, overrideCustomConfigs(manager, override.CustomConfigurations, ddaName, namespace)...) + // Handle custom check configurations errs = append(errs, overrideExtraConfigs(manager, override.ExtraConfd, namespace, v2alpha1.ExtraConfdConfigMapName, true)...) @@ -46,6 +49,27 @@ func overrideRBAC(logger logr.Logger, manager feature.ResourceManagers, override return errors.NewAggregate(errs) } +func overrideCustomConfigs(manager feature.ResourceManagers, customConfigMap map[v2alpha1.AgentConfigFileName]v2alpha1.CustomConfig, ddaName, namespace string) (errs []error) { + for fileName, customConfig := range customConfigMap { + // Favor ConfigMap setting; if it is specified, then move on + if customConfig.ConfigMap != nil { + continue + } else if customConfig.ConfigData != nil { + configMapName := getDefaultConfigMapName(ddaName, string(fileName)) + cm, err := configmap.BuildConfigMapConfigData(namespace, customConfig.ConfigData, configMapName, string(fileName)) + if err != nil { + errs = append(errs, err) + } + if cm != nil { + if err := manager.Store().AddOrUpdate(kubernetes.ConfigMapKind, cm); err != nil { + errs = append(errs, err) + } + } + } + } + return errs +} + func overrideExtraConfigs(manager feature.ResourceManagers, multiCustomConfig *v2alpha1.MultiCustomConfig, namespace, configMapName string, isYaml bool) (errs []error) { if multiCustomConfig != nil && multiCustomConfig.ConfigMap == nil && len(multiCustomConfig.ConfigDataMap) > 0 { cm, err := configmap.BuildConfigMapMulti(namespace, multiCustomConfig.ConfigDataMap, configMapName, isYaml) diff --git a/controllers/datadogagent/override/dependencies_test.go b/controllers/datadogagent/override/dependencies_test.go index 2b3c353c7..a6b3d3de9 100644 --- a/controllers/datadogagent/override/dependencies_test.go +++ b/controllers/datadogagent/override/dependencies_test.go @@ -133,7 +133,7 @@ func TestDependencies(t *testing.T) { store := dependencies.NewStore(&test.dda, storeOptions) manager := feature.NewResourceManagers(store) - errs := Dependencies(testLogger, manager, test.dda.Spec.Override, namespace) + errs := Dependencies(testLogger, manager, test.dda.Spec.Override, "dd", namespace) if test.expectsErrors { assert.NotEmpty(t, errs) diff --git a/controllers/datadogagent/override/podtemplatespec.go b/controllers/datadogagent/override/podtemplatespec.go index 805a0a2d1..eb93ed43a 100644 --- a/controllers/datadogagent/override/podtemplatespec.go +++ b/controllers/datadogagent/override/podtemplatespec.go @@ -6,12 +6,9 @@ package override import ( - "fmt" "sort" "strings" - "gopkg.in/yaml.v2" - apicommon "github.com/DataDog/datadog-operator/apis/datadoghq/common" "github.com/DataDog/datadog-operator/apis/datadoghq/common/v1" "github.com/DataDog/datadog-operator/apis/datadoghq/v2alpha1" @@ -39,11 +36,11 @@ func PodTemplateSpec(manager feature.PodTemplateManagers, override *v2alpha1.Dat if override.Image != nil { for i, container := range manager.PodTemplateSpec().Spec.Containers { - manager.PodTemplateSpec().Spec.Containers[i].Image = overriddenImage(container.Image, override.Image) + manager.PodTemplateSpec().Spec.Containers[i].Image = overrideImage(container.Image, override.Image) } for i, initContainer := range manager.PodTemplateSpec().Spec.InitContainers { - manager.PodTemplateSpec().Spec.InitContainers[i].Image = overriddenImage(initContainer.Image, override.Image) + manager.PodTemplateSpec().Spec.InitContainers[i].Image = overrideImage(initContainer.Image, override.Image) } } @@ -54,89 +51,22 @@ func PodTemplateSpec(manager feature.PodTemplateManagers, override *v2alpha1.Dat }) } - overrideCustomConfigs(manager, override.CustomConfigurations, componentName, ddaName) + // Override agent configurations such as datadog.yaml, system-probe.yaml, etc. + overrideCustomConfigVolumes(manager, override.CustomConfigurations, componentName, ddaName) // For ExtraConfd and ExtraChecksd, the ConfigMap contents to an init container. This allows use of // the workaround to merge existing config and check files with custom ones. The VolumeMount is already // defined in the init container; just overwrite the Volume to mount the ConfigMap instead of an EmptyDir. // If both ConfigMap and ConfigData exist, ConfigMap has higher priority. if override.ExtraConfd != nil { - if override.ExtraConfd.ConfigMap != nil { - vol := corev1.Volume{ - Name: apicommon.ConfdVolumeName, - VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: override.ExtraConfd.ConfigMap.Name, - }, - Items: override.ExtraConfd.ConfigMap.Items, - }, - }, - } - manager.Volume().AddVolume(&vol) - } else if override.ExtraConfd.ConfigDataMap != nil { - // Sort map so that order is consistent between reconcile loops - sortedKeys := sortKeys(override.ExtraConfd.ConfigDataMap) - keysToPaths := []corev1.KeyToPath{} - for _, filename := range sortedKeys { - configData := override.ExtraConfd.ConfigDataMap[filename] - // Validate that user input is valid YAML - m := make(map[interface{}]interface{}) - if yaml.Unmarshal([]byte(configData), m) != nil { - continue - } - keysToPaths = append(keysToPaths, corev1.KeyToPath{Key: filename, Path: filename}) - } - vol := corev1.Volume{ - Name: apicommon.ConfdVolumeName, - VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: v2alpha1.ExtraConfdConfigMapName, - }, - Items: keysToPaths, - }, - }, - } - manager.Volume().AddVolume(&vol) - } + vol := volume.GetVolumeFromMultiCustomConfig(override.ExtraConfd, apicommon.ConfdVolumeName, v2alpha1.ExtraConfdConfigMapName) + manager.Volume().AddVolume(&vol) } // If both ConfigMap and ConfigData exist, ConfigMap has higher priority. if override.ExtraChecksd != nil { - if override.ExtraChecksd.ConfigMap != nil { - vol := corev1.Volume{ - Name: apicommon.ChecksdVolumeName, - VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: override.ExtraChecksd.ConfigMap.Name, - }, - Items: override.ExtraChecksd.ConfigMap.Items, - }, - }, - } - manager.Volume().AddVolume(&vol) - } else if override.ExtraChecksd.ConfigDataMap != nil { - // Sort map so that order is consistent between reconcile loops - sortedKeys := sortKeys(override.ExtraChecksd.ConfigDataMap) - keysToPaths := []corev1.KeyToPath{} - for _, filename := range sortedKeys { - keysToPaths = append(keysToPaths, corev1.KeyToPath{Key: filename, Path: filename}) - } - vol := corev1.Volume{ - Name: apicommon.ChecksdVolumeName, - VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: v2alpha1.ExtraChecksdConfigMapName, - }, - Items: keysToPaths, - }, - }, - } - manager.Volume().AddVolume(&vol) - } + vol := volume.GetVolumeFromMultiCustomConfig(override.ExtraChecksd, apicommon.ChecksdVolumeName, v2alpha1.ExtraChecksdConfigMapName) + manager.Volume().AddVolume(&vol) } for agentContainerName, containerOverride := range override.Containers { @@ -187,57 +117,43 @@ func PodTemplateSpec(manager feature.PodTemplateManagers, override *v2alpha1.Dat } } -func overrideCustomConfigs(manager feature.PodTemplateManagers, customConfs map[v2alpha1.AgentConfigFileName]v2alpha1.CustomConfig, componentName v2alpha1.ComponentName, ddaName string) { - for _, customConfig := range customConfs { - if customConfig.ConfigMap != nil { - switch componentName { - case v2alpha1.NodeAgentComponentName, v2alpha1.ClusterChecksRunnerComponentName: - vol := volume.GetVolumeFromCustomConfigSpec( - v2alpha1.ConvertCustomConfig(&customConfig), - getAgentCustomConfConfigMapName(ddaName), - apicommon.AgentCustomConfigVolumeName, - ) - manager.Volume().AddVolume(&vol) +func overrideCustomConfigVolumes(manager feature.PodTemplateManagers, customConfs map[v2alpha1.AgentConfigFileName]v2alpha1.CustomConfig, componentName v2alpha1.ComponentName, ddaName string) { + sortedKeys := sortKeys(customConfs) + for _, fileName := range sortedKeys { + customConfig := customConfs[fileName] + switch componentName { + case v2alpha1.NodeAgentComponentName, v2alpha1.ClusterChecksRunnerComponentName: + // For the NodeAgent, there are a few possible config files and each need their own volume. + // Use a volumeName that matches the defaultConfigMapName. + defaultConfigMapName := getDefaultConfigMapName(ddaName, string(fileName)) + volumeName := defaultConfigMapName + vol := volume.GetVolumeFromCustomConfig(customConfig, defaultConfigMapName, volumeName) + manager.Volume().AddVolume(&vol) - volumeMount := volume.GetVolumeMountFromCustomConfigSpec( - v2alpha1.ConvertCustomConfig(&customConfig), - apicommon.AgentCustomConfigVolumeName, - apicommon.AgentCustomConfigVolumePath, - apicommon.AgentCustomConfigVolumeSubPath, - ) - manager.VolumeMount().AddVolumeMount(&volumeMount) - case v2alpha1.ClusterAgentComponentName: - vol := volume.GetVolumeFromCustomConfigSpec( - v2alpha1.ConvertCustomConfig(&customConfig), - getClusterAgentCustomConfConfigMapName(ddaName), - apicommon.ClusterAgentCustomConfigVolumeName, - ) - manager.Volume().AddVolume(&vol) + volumeMount := volume.GetVolumeMountWithSubPath( + volumeName, + "/etc/datadog-agent/"+string(fileName), + string(fileName), + ) + manager.VolumeMount().AddVolumeMount(&volumeMount) + case v2alpha1.ClusterAgentComponentName: + // For the Cluster Agent, there is only one possible config file so can use a simple volume name. + volumeName := apicommon.ClusterAgentCustomConfigVolumeName + defaultConfigMapName := getDefaultConfigMapName(ddaName, string(fileName)) + vol := volume.GetVolumeFromCustomConfig(customConfig, defaultConfigMapName, volumeName) + manager.Volume().AddVolume(&vol) - volumeMount := volume.GetVolumeMountFromCustomConfigSpec( - v2alpha1.ConvertCustomConfig(&customConfig), - apicommon.ClusterAgentCustomConfigVolumeName, - apicommon.ClusterAgentCustomConfigVolumePath, - apicommon.ClusterAgentCustomConfigVolumeSubPath, - ) - manager.VolumeMount().AddVolumeMount(&volumeMount) - } + volumeMount := volume.GetVolumeMountWithSubPath( + volumeName, + "/etc/datadog-agent/"+string(fileName), + string(fileName), + ) + manager.VolumeMount().AddVolumeMount(&volumeMount) } } } -func sortKeys(keysMap map[string]string) []string { - sortedKeys := make([]string, 0, len(keysMap)) - for key := range keysMap { - sortedKeys = append(sortedKeys, key) - } - sort.Slice(sortedKeys, func(i, j int) bool { - return sortedKeys[i] < sortedKeys[j] - }) - return sortedKeys -} - -func overriddenImage(currentImg string, overrideImg *common.AgentImageConfig) string { +func overrideImage(currentImg string, overrideImg *common.AgentImageConfig) string { splitImg := strings.Split(currentImg, "/") registry := "" if len(splitImg) > 2 { @@ -247,10 +163,13 @@ func overriddenImage(currentImg string, overrideImg *common.AgentImageConfig) st return apicommon.GetImage(overrideImg, ®istry) } -func getAgentCustomConfConfigMapName(ddaName string) string { - return fmt.Sprintf("%s-datadog-yaml", ddaName) -} - -func getClusterAgentCustomConfConfigMapName(ddaName string) string { - return fmt.Sprintf("%s-cluster-datadog-yaml", ddaName) +func sortKeys(keysMap map[v2alpha1.AgentConfigFileName]v2alpha1.CustomConfig) []v2alpha1.AgentConfigFileName { + sortedKeys := make([]v2alpha1.AgentConfigFileName, 0, len(keysMap)) + for key := range keysMap { + sortedKeys = append(sortedKeys, key) + } + sort.Slice(sortedKeys, func(i, j int) bool { + return sortedKeys[i] < sortedKeys[j] + }) + return sortedKeys } diff --git a/controllers/datadogagent/override/podtemplatespec_test.go b/controllers/datadogagent/override/podtemplatespec_test.go index 4cde90c4e..d02357235 100644 --- a/controllers/datadogagent/override/podtemplatespec_test.go +++ b/controllers/datadogagent/override/podtemplatespec_test.go @@ -130,7 +130,7 @@ func TestPodTemplateSpec(t *testing.T) { validateManager: func(t *testing.T, manager *fake.PodTemplateManagers) { found := false for _, vol := range manager.VolumeMgr.Volumes { - if vol.Name == common.AgentCustomConfigVolumeName { + if vol.Name == getDefaultConfigMapName("datadog-agent", string(v2alpha1.AgentGeneralConfigFile)) { found = true break } diff --git a/controllers/datadogagent/override/utils.go b/controllers/datadogagent/override/utils.go new file mode 100644 index 000000000..686dcf34c --- /dev/null +++ b/controllers/datadogagent/override/utils.go @@ -0,0 +1,15 @@ +// 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 override + +import ( + "fmt" + "strings" +) + +func getDefaultConfigMapName(ddaName, fileName string) string { + return fmt.Sprintf("%s-%s-yaml", ddaName, strings.Split(fileName, ".")[0]) +} diff --git a/controllers/datadogagent/utils.go b/controllers/datadogagent/utils.go index 05c22121b..56dbec11c 100644 --- a/controllers/datadogagent/utils.go +++ b/controllers/datadogagent/utils.go @@ -520,11 +520,11 @@ func getConfigInitContainers(spec *datadoghqv1alpha1.DatadogAgentSpec, volumeMou configVolumeMounts = append( configVolumeMounts, corev1.VolumeMount{ - Name: datadoghqv1alpha1.SecurityAgentComplianceCustomConfigDirVolumeName, + Name: apicommon.SecurityAgentComplianceCustomConfigDirVolumeName, MountPath: "/etc/datadog-agent-compliance-benchmarks", }, corev1.VolumeMount{ - Name: datadoghqv1alpha1.SecurityAgentComplianceConfigDirVolumeName, + Name: apicommon.SecurityAgentComplianceConfigDirVolumeName, MountPath: "/opt/datadog-agent/compliance.d", }, ) @@ -535,11 +535,11 @@ func getConfigInitContainers(spec *datadoghqv1alpha1.DatadogAgentSpec, volumeMou configVolumeMounts = append( configVolumeMounts, corev1.VolumeMount{ - Name: datadoghqv1alpha1.SecurityAgentRuntimeCustomPoliciesVolumeName, + Name: apicommon.SecurityAgentRuntimeCustomPoliciesVolumeName, MountPath: "/etc/datadog-agent-runtime-policies", }, corev1.VolumeMount{ - Name: datadoghqv1alpha1.SecurityAgentRuntimePoliciesDirVolumeName, + Name: apicommon.SecurityAgentRuntimePoliciesDirVolumeName, MountPath: "/opt/datadog-agent/runtime-security.d", }, ) @@ -681,7 +681,7 @@ func getEnvVarsForSystemProbe(dda *datadoghqv1alpha1.DatadogAgent) ([]corev1.Env }, corev1.EnvVar{ Name: apicommon.DDRuntimeSecurityConfigPoliciesDir, - Value: datadoghqv1alpha1.SecurityAgentRuntimePoliciesDirVolumePath, + Value: apicommon.SecurityAgentRuntimePoliciesDirVolumePath, }, corev1.EnvVar{ Name: apicommon.DDAuthTokenFilePath, @@ -964,7 +964,7 @@ func getEnvVarsForSecurityAgent(dda *datadoghqv1alpha1.DatadogAgent) ([]corev1.E if dda.Spec.Agent.Security.Compliance.ConfigDir != nil { envVars = append(envVars, corev1.EnvVar{ Name: apicommon.DDComplianceConfigDir, - Value: datadoghqv1alpha1.SecurityAgentComplianceConfigDirVolumePath, + Value: apicommon.SecurityAgentComplianceConfigDirVolumePath, }) } } @@ -978,7 +978,7 @@ func getEnvVarsForSecurityAgent(dda *datadoghqv1alpha1.DatadogAgent) ([]corev1.E if dda.Spec.Agent.Security.Runtime.PoliciesDir != nil { envVars = append(envVars, corev1.EnvVar{ Name: apicommon.DDRuntimeSecurityConfigPoliciesDir, - Value: datadoghqv1alpha1.SecurityAgentRuntimePoliciesDirVolumePath, + Value: apicommon.SecurityAgentRuntimePoliciesDirVolumePath, }) } envVars = append(envVars, []corev1.EnvVar{ @@ -1294,26 +1294,26 @@ func getVolumesForAgent(dda *datadoghqv1alpha1.DatadogAgent) []corev1.Volume { if isComplianceEnabled(&dda.Spec) { volumes = append(volumes, corev1.Volume{ - Name: datadoghqv1alpha1.SecurityAgentComplianceConfigDirVolumeName, + Name: apicommon.SecurityAgentComplianceConfigDirVolumeName, VolumeSource: corev1.VolumeSource{ EmptyDir: &corev1.EmptyDirVolumeSource{}, }, }) if dda.Spec.Agent.Security.Compliance.ConfigDir != nil { - volumes = append(volumes, getVolumeFromConfigDirSpec(datadoghqv1alpha1.SecurityAgentComplianceCustomConfigDirVolumeName, dda.Spec.Agent.Security.Compliance.ConfigDir)) + volumes = append(volumes, getVolumeFromConfigDirSpec(apicommon.SecurityAgentComplianceCustomConfigDirVolumeName, dda.Spec.Agent.Security.Compliance.ConfigDir)) } } if isRuntimeSecurityEnabled(&dda.Spec) && dda.Spec.Agent.Security.Runtime.PoliciesDir != nil { volumes = append(volumes, corev1.Volume{ - Name: datadoghqv1alpha1.SecurityAgentRuntimePoliciesDirVolumeName, + Name: apicommon.SecurityAgentRuntimePoliciesDirVolumeName, VolumeSource: corev1.VolumeSource{ EmptyDir: &corev1.EmptyDirVolumeSource{}, }, }, - getVolumeFromConfigDirSpec(datadoghqv1alpha1.SecurityAgentRuntimeCustomPoliciesVolumeName, dda.Spec.Agent.Security.Runtime.PoliciesDir), + getVolumeFromConfigDirSpec(apicommon.SecurityAgentRuntimeCustomPoliciesVolumeName, dda.Spec.Agent.Security.Runtime.PoliciesDir), ) } @@ -1707,8 +1707,8 @@ func getVolumeMountsForSystemProbe(dda *datadoghqv1alpha1.DatadogAgent) []corev1 if isRuntimeSecurityEnabled(&dda.Spec) && dda.Spec.Agent.Security.Runtime.PoliciesDir != nil { volumeMounts = append(volumeMounts, corev1.VolumeMount{ - Name: datadoghqv1alpha1.SecurityAgentRuntimePoliciesDirVolumeName, - MountPath: datadoghqv1alpha1.SecurityAgentRuntimePoliciesDirVolumePath, + Name: apicommon.SecurityAgentRuntimePoliciesDirVolumeName, + MountPath: apicommon.SecurityAgentRuntimePoliciesDirVolumePath, ReadOnly: true, }) } @@ -1766,8 +1766,8 @@ func getVolumeMountsForSecurityAgent(dda *datadoghqv1alpha1.DatadogAgent) []core if runtimeEnabled && dda.Spec.Agent.Security.Runtime.PoliciesDir != nil { volumeMounts = append(volumeMounts, corev1.VolumeMount{ - Name: datadoghqv1alpha1.SecurityAgentRuntimePoliciesDirVolumeName, - MountPath: datadoghqv1alpha1.SecurityAgentRuntimePoliciesDirVolumePath, + Name: apicommon.SecurityAgentRuntimePoliciesDirVolumeName, + MountPath: apicommon.SecurityAgentRuntimePoliciesDirVolumePath, ReadOnly: true, }) } @@ -1804,8 +1804,8 @@ func getVolumeMountsForSecurityAgent(dda *datadoghqv1alpha1.DatadogAgent) []core if complianceEnabled && dda.Spec.Agent.Security.Compliance.ConfigDir != nil { volumeMounts = append(volumeMounts, corev1.VolumeMount{ - Name: datadoghqv1alpha1.SecurityAgentComplianceConfigDirVolumeName, - MountPath: datadoghqv1alpha1.SecurityAgentComplianceConfigDirVolumePath, + Name: apicommon.SecurityAgentComplianceConfigDirVolumeName, + MountPath: apicommon.SecurityAgentComplianceConfigDirVolumePath, ReadOnly: true, }) } diff --git a/docs/configuration.v2alpha1.md b/docs/configuration.v2alpha1.md index ef6ad061c..10d42d2c1 100644 --- a/docs/configuration.v2alpha1.md +++ b/docs/configuration.v2alpha1.md @@ -46,11 +46,13 @@ spec: | features.clusterChecks.enabled | Enables Cluster Checks scheduling in the Cluster Agent. Default: true | | features.clusterChecks.useClusterChecksRunners | Enabled enables Cluster Checks Runners to run all Cluster Checks. Default: false | | features.cspm.checkInterval | CheckInterval defines the check interval. | -| features.cspm.customBenchmarks.items | Items maps a ConfigMap data key to a file path mount. | -| features.cspm.customBenchmarks.name | Name is the name of the ConfigMap. | +| features.cspm.customBenchmarks.configData | ConfigData corresponds to the configuration file content. | +| features.cspm.customBenchmarks.configMap.items | Items maps a ConfigMap data key to a file path mount. | +| features.cspm.customBenchmarks.configMap.name | Name is the name of the ConfigMap. | | features.cspm.enabled | Enabled enables Cloud Security Posture Management. Default: false | -| features.cws.customPolicies.items | Items maps a ConfigMap data key to a file path mount. | -| features.cws.customPolicies.name | Name is the name of the ConfigMap. | +| features.cws.customPolicies.configData | ConfigData corresponds to the configuration file content. | +| features.cws.customPolicies.configMap.items | Items maps a ConfigMap data key to a file path mount. | +| features.cws.customPolicies.configMap.name | Name is the name of the ConfigMap. | | features.cws.enabled | Enabled enables Cloud Workload Security. Default: false | | features.cws.syscallMonitorEnabled | SyscallMonitorEnabled enables Syscall Monitoring (recommended for troubleshooting only). Default: false | | features.datadogMonitor.enabled | Enabled enables Datadog Monitors. Default: false |