Allow enabling CWS and CSPM
MODIFY
attributes/default.rb
attributes/default.rb
@@ -360,6 +360,10 @@ default['datadog']['process_agent']['rtprocess_interval'] = nil
default['datadog']['process_agent']['container_interval'] = nil
default['datadog']['process_agent']['rtcontainer_interval'] = nil
+# Cloud Workload Security functionality settings
+default['datadog']['security_agent']['cws']['enabled'] = false
+default['datadog']['security_agent']['cspm']['enabled'] = false
+
# System probe functionality settings
# Whether this cookbook should write system-probe.yaml or not.

MODIFY
recipes/dd-agent.rb
recipes/dd-agent.rb
@@ -166,6 +166,9 @@ system_probe_supported = (agent_version_greater_than_6_11 && !is_windows) || (ag
# system-probe is a dependency of the agent on Linux or Windows
include_recipe '::system-probe' if system_probe_managed && system_probe_supported
+# security-agent is a dependency of the agent on Linux or Windows
+include_recipe '::security-agent' unless is_windows
+
# Installation metadata to let know the agent about installation method and its version
include_recipe '::install_info'

ADD
recipes/security-agent.rb
+#
+# Cookbook:: datadog
+# Recipe:: security-agent
+#
+# Copyright:: 2011-2022, Datadog
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+is_windows = platform_family?('windows')
+
+# Set the correct agent startup action
+security_agent_enabled = !is_windows && node['datadog']['security_agent']['cws']['enabled'] || node['datadog']['security_agent']['cspm']['enabled']
+
+#
+# Configures security-agent agent
+security_agent_config_file = '/etc/datadog-agent/security-agent.yaml'
+security_agent_config_file_exists = ::File.exist?(security_agent_config_file)
+
+template security_agent_config_file do
+ runtime_security_extra_config = {}
+ if node['datadog']['extra_config'] && node['datadog']['extra_config']['security_agent'] && node['datadog']['extra_config']['security_agent']['runtime_security_config']
+ node['datadog']['extra_config']['security_agent']['runtime_security_config'].each do |k, v|
+ next if v.nil?
+ runtime_security_extra_config[k] = v
+ end
+ end
+
+ compliance_extra_config = {}
+ if node['datadog']['extra_config'] && node['datadog']['extra_config']['security_agent'] && node['datadog']['extra_config']['security_agent']['compliance_config']
+ node['datadog']['extra_config']['security_agent']['compliance_config'].each do |k, v|
+ next if v.nil?
+ compliance_extra_config[k] = v
+ end
+ end
+
+ source 'security-agent.yaml.erb'
+ variables(
+ runtime_security_enabled: node['datadog']['security_agent']['cws']['enabled'],
+ runtime_security_extra_config: runtime_security_extra_config,
+ compliance_enabled: node['datadog']['security_agent']['cspm']['enabled'],
+ compliance_extra_config: compliance_extra_config
+ )
+
+ owner 'root'
+ group 'dd-agent'
+ mode '640'
+
+ notifies :restart, 'service[datadog-agent-security]', :delayed if security_agent_enabled
+
+ # Security agent is not enabled and the file doesn't exists, don't create it
+ not_if { !security_agent_enabled && !security_agent_config_file_exists }
+end
+
+# Common configuration
+service_provider = Chef::Datadog.service_provider(node)
+
+service_name = 'datadog-agent-security'
+
+if security_agent_enabled
+ service 'datadog-agent-security' do
+ service_name service_name
+ action :start
+ provider service_provider unless service_provider.nil?
+ supports :restart => true, :status => true, :start => true, :stop => true
+ subscribes :restart, "template[#{security_agent_config_file}]", :delayed
+ end
+end
\ No newline at end of file

MODIFY
recipes/system-probe.rb
recipes/system-probe.rb
is_windows = platform_family?('windows')
# Set the correct agent startup action
+cws_enabled = node['datadog']['security_agent']['cws']['enabled']
sysprobe_enabled = if is_windows
node['datadog']['system_probe']['network_enabled']
else
- node['datadog']['system_probe']['enabled'] || node['datadog']['system_probe']['network_enabled']
+ node['datadog']['system_probe']['enabled'] || node['datadog']['system_probe']['network_enabled'] || cws_enabled
end
sysprobe_agent_start = sysprobe_enabled ? :start : :stop
@@ -47,6 +48,14 @@ template system_probe_config_file do
end
end
+ runtime_security_extra_config = {}
+ if node['datadog']['extra_config'] && node['datadog']['extra_config']['security_agent'] && node['datadog']['extra_config']['security_agent']['runtime_security_config']
+ node['datadog']['extra_config']['security_agent']['runtime_security_config'].each do |k, v|
+ next if v.nil?
+ runtime_security_extra_config[k] = v
+ end
+ end
+
source 'system_probe.yaml.erb'
variables(
enabled: node['datadog']['system_probe']['enabled'],
@@ -54,7 +63,9 @@ template system_probe_config_file do
debug_port: node['datadog']['system_probe']['debug_port'],
bpf_debug: node['datadog']['system_probe']['bpf_debug'],
enable_conntrack: node['datadog']['system_probe']['enable_conntrack'],
- extra_config: extra_config
+ system_probe_extra_config: extra_config,
+ runtime_security_enabled: cws_enabled,
+ runtime_security_extra_config: runtime_security_extra_config
)
if is_windows
@@ -70,6 +81,7 @@ template system_probe_config_file do
notifies :restart, 'service[datadog-agent-sysprobe]', :delayed if sysprobe_enabled
# since process-agent collects network info through system-probe, enabling system-probe should also restart process-agent
notifies :restart, 'service[datadog-agent]', :delayed if sysprobe_enabled
+ notifies :restart, 'service[datadog-agent-security]', :delayed if cws_enabled
# System probe is not enabled and the file doesn't exists, don't create it
not_if { !sysprobe_enabled && !system_probe_config_file_exists }

ADD
spec/security-agent_spec.rb
+require 'spec_helper'
+
+describe 'datadog::security-agent' do
+ context 'with CWS enabled' do
+ cached(:solo) do
+ ChefSpec::SoloRunner.new(
+ platform: 'ubuntu',
+ version: '16.04'
+ ) do |node|
+ node.name 'chef-nodename' # expected to be used as the hostname in `datadog.yaml`
+ node.normal['datadog'] = {
+ 'api_key' => 'somethingnotnil',
+ 'agent_major_version' => 6,
+ 'security_agent' => {
+ 'cws' => {
+ 'enabled' => true,
+ }
+ },
+ 'extra_config' => {
+ 'security_agent' => {
+ 'runtime_security_config' => {
+ 'activity_dump' => {
+ 'enabled' => true,
+ }
+ }
+ }
+ }
+ }
+ end
+ end
+
+ cached(:chef_run) do
+ solo.converge(described_recipe) do
+ solo.resource_collection.insert(
+ Chef::Resource::Service.new('datadog-agent', solo.run_context))
+ end
+ end
+
+ it 'security-agent.yaml is created' do
+ expect(chef_run).to create_template('/etc/datadog-agent/security-agent.yaml')
+ end
+
+ it 'security-agent.yaml contains expected YAML configuration' do
+ expected_yaml = <<-EOF
+ compliance_config:
+ enabled: false
+ runtime_security_config:
+ enabled: true
+ activity_dump:
+ enabled: true
+ EOF
+
+ expect(chef_run).to(render_file('/etc/datadog-agent/security-agent.yaml').with_content { |content|
+ expect(YAML.safe_load(content).to_json).to be_json_eql(YAML.safe_load(expected_yaml).to_json)
+ })
+ end
+ end
+end

ADD
templates/default/security-agent.yaml.erb
+<%
+## Populate system_probe_config ##
+security_agent_config = {
+ runtime_security_config: {
+ enabled: @runtime_security_enabled,
+ }.merge(@runtime_security_extra_config),
+ compliance_config: {
+ enabled: @compliance_enabled,
+ }.merge(@compliance_extra_config),
+}
+-%>
+
+<%= JSON.parse(security_agent_config.to_json).to_yaml %>
\ No newline at end of file

MODIFY
templates/default/system_probe.yaml.erb
templates/default/system_probe.yaml.erb
@@ -7,9 +7,15 @@ system_probe_config = {
debug_port: @debug_port,
bpf_debug: @bpf_debug,
enable_conntrack: @enable_conntrack,
- }.merge(@extra_config),
+ }.merge(@system_probe_extra_config),
}
+if @runtime_security_enabled
+ system_probe_config['runtime_security_config'] = {
+ enabled: @runtime_security_enabled
+ }.merge(@runtime_security_extra_config)
+end
+
# We let the Agent default value take effect if user didn't explicitly
# specify something else than nil for 'network_enabled'
if !node['datadog']['system_probe']['network_enabled'].nil?

Allow enabling CWS and CSPM  (#843)