Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow enabling CWS and CSPM #843

Merged
merged 3 commits into from
Mar 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions attributes/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,10 @@
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.
Expand Down
3 changes: 3 additions & 0 deletions recipes/dd-agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ def template_vars
# 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'

Expand Down
78 changes: 78 additions & 0 deletions recipes/security-agent.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#
# 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
16 changes: 14 additions & 2 deletions recipes/system-probe.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
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

Expand All @@ -47,14 +48,24 @@
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'],
sysprobe_socket: node['datadog']['system_probe']['sysprobe_socket'],
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
Expand All @@ -70,6 +81,7 @@
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 }
Expand Down
58 changes: 58 additions & 0 deletions spec/security-agent_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
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
13 changes: 13 additions & 0 deletions templates/default/security-agent.yaml.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<%
## 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 %>
8 changes: 7 additions & 1 deletion templates/default/system_probe.yaml.erb
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down