Skip to content

Commit baacd30

Browse files
authored
Base CWS implementation (#7)
1 parent eda2053 commit baacd30

File tree

4 files changed

+144
-21
lines changed

4 files changed

+144
-21
lines changed

examples/ecs_fargate/main.tf

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,29 +35,37 @@ module "ecs_task" {
3535
is_log_router_dependency_enabled = true,
3636
}
3737

38+
dd_cws = {
39+
enabled = true,
40+
}
41+
3842
# Configure Task Definition
3943
family = "datadog-terraform-app"
40-
container_definitions = {
41-
dogstatsd = {
42-
name = "datadog-dogstatsd-app",
43-
image = "ghcr.io/datadog/apps-dogstatsd:main",
44-
essential = false,
44+
container_definitions = jsonencode([
45+
{
46+
name = "datadog-dogstatsd-app",
47+
image = "ghcr.io/datadog/apps-dogstatsd:main",
48+
essential = false,
4549
},
46-
apm = {
47-
name = "datadog-apm-app",
48-
image = "ghcr.io/datadog/apps-tracegen:main",
49-
essential = false,
50+
{
51+
name = "datadog-apm-app",
52+
image = "ghcr.io/datadog/apps-tracegen:main",
53+
essential = false,
5054
},
51-
cws = {
55+
{
5256
name = "datadog-cws-app",
5357
image = "public.ecr.aws/ubuntu/ubuntu:22.04_stable",
5458
essential = true,
5559
entryPoint = [
5660
"/usr/bin/bash",
5761
"-c",
5862
"cp /usr/bin/bash /tmp/malware; chmod u+s /tmp/malware; apt update;apt install -y curl wget; /tmp/malware -c 'while true; do wget https://google.com; sleep 60; done'"
59-
]
63+
],
6064
}
65+
])
66+
runtime_platform = {
67+
cpu_architecture = "ARM64",
68+
operating_system_family = "LINUX",
6169
}
6270
requires_compatibilities = ["FARGATE"]
6371
}

modules/ecs_fargate/datadog.tf

Lines changed: 100 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
locals {
2+
# Datadog ECS task tags
3+
tags = {
4+
dd_ecs_terraform_module = "1.0.0"
5+
}
6+
27
# Datadog Firelens log configuration
38
dd_firelens_log_configuration = var.dd_log_collection.enabled ? merge(
49
{
@@ -33,6 +38,17 @@ locals {
3338
is_dsd_socket_mount = var.dd_dogstatsd.enabled && var.dd_dogstatsd.socket_enabled && local.is_linux
3439
is_apm_dsd_volume = local.is_apm_socket_mount || local.is_dsd_socket_mount
3540

41+
cws_entry_point_prefix = ["/cws-instrumentation-volume/cws-instrumentation", "trace", "--"]
42+
is_cws_supported = local.is_linux && var.dd_cws.enabled
43+
44+
cws_mount = local.is_cws_supported ? [
45+
{
46+
sourceVolume = "cws-instrumentation-volume"
47+
containerPath = "/cws-instrumentation-volume"
48+
readOnly = false
49+
}
50+
] : []
51+
3652
apm_dsd_mount = local.is_apm_dsd_volume ? [
3753
{
3854
containerPath = "/var/run/datadog"
@@ -76,9 +92,17 @@ locals {
7692
}
7793
] : []
7894

95+
cws_dependency = local.is_cws_supported ? [
96+
{
97+
containerName = "cws-instrumentation-init"
98+
condition = "SUCCESS"
99+
}
100+
] : []
101+
79102
modified_container_definitions = [
80-
for container in var.container_definitions : merge(
103+
for container in jsondecode(var.container_definitions) : merge(
81104
container,
105+
# Note: only configure CWS on container if entryPoint is set
82106
{
83107
# Append new environment variables to any existing ones.
84108
environment = concat(
@@ -90,13 +114,28 @@ locals {
90114
# Append new volume mounts to any existing mountPoints.
91115
mountPoints = concat(
92116
lookup(container, "mountPoints", []),
93-
local.apm_dsd_mount
117+
local.apm_dsd_mount,
118+
local.is_cws_supported && lookup(container, "entryPoint", []) != [] ? local.cws_mount : [],
94119
)
95120
dependsOn = concat(
96121
lookup(container, "dependsOn", []),
97122
local.agent_dependency,
98123
local.log_router_dependency,
124+
local.is_cws_supported && lookup(container, "entryPoint", []) != [] ? local.cws_dependency : [],
99125
)
126+
entryPoint = local.is_cws_supported && lookup(container, "entryPoint", []) != [] ? concat(
127+
local.cws_entry_point_prefix,
128+
lookup(container, "entryPoint", []),
129+
) : null
130+
linuxParameters = local.is_cws_supported && lookup(container, "entryPoint", []) != [] ? {
131+
# Note: SYS_PTRACE is the only supported capability on Fargate
132+
capabilities = {
133+
add = [
134+
"SYS_PTRACE",
135+
]
136+
drop = []
137+
}
138+
} : null
100139
},
101140
# Only override the log configuration if the Datadog firelens configuration exists
102141
local.dd_firelens_log_configuration != null ? { logConfiguration = local.dd_firelens_log_configuration } : {}
@@ -110,12 +149,30 @@ locals {
110149
}
111150
] : []
112151

152+
cws_volume = local.is_cws_supported ? [
153+
{
154+
name = "cws-instrumentation-volume"
155+
}
156+
] : []
157+
113158
modified_volumes = concat(
114-
[for k, v in coalesce(var.volumes, {}) : v],
115-
local.apm_dsd_volume
159+
[for k, v in coalesce(var.volumes, []) : v],
160+
local.apm_dsd_volume,
161+
local.cws_volume,
116162
)
117163

118164
# Datadog Agent container environment variables
165+
base_env = [
166+
{
167+
name = "ECS_FARGATE"
168+
value = "true"
169+
},
170+
{
171+
name = "DD_ECS_TASK_COLLECTION_ENABLED"
172+
value = "true"
173+
}
174+
]
175+
119176
dynamic_env = [
120177
for pair in [
121178
{ key = "DD_API_KEY", value = var.dd_api_key },
@@ -140,10 +197,23 @@ locals {
140197
}
141198
] : []
142199

200+
cws_vars = local.is_cws_supported ? [
201+
{
202+
name = "DD_RUNTIME_SECURITY_CONFIG_ENABLED"
203+
value = "true"
204+
},
205+
{
206+
name = "DD_RUNTIME_SECURITY_CONFIG_EBPFLESS_ENABLED"
207+
value = "true"
208+
}
209+
] : []
210+
143211
dd_agent_env = concat(
144-
var.dd_environment,
212+
local.base_env,
145213
local.dynamic_env,
146214
local.origin_detection_vars,
215+
local.cws_vars,
216+
var.dd_environment,
147217
)
148218

149219
# Datadog Agent container definition
@@ -175,6 +245,8 @@ locals {
175245
mountPoints = local.apm_dsd_mount,
176246
logConfiguration = local.dd_firelens_log_configuration,
177247
dependsOn = var.dd_log_collection.is_log_router_dependency_enabled && local.dd_firelens_log_configuration != null ? local.log_router_dependency : [],
248+
systemControls = []
249+
volumesFrom = []
178250
},
179251
var.dd_health_check.command == null ? {} : {
180252
healthCheck = {
@@ -204,6 +276,11 @@ locals {
204276
cpu = var.dd_log_collection.cpu
205277
memory_limit_mib = var.dd_log_collection.memory_limit_mib
206278
user = "0"
279+
mountPoints = []
280+
environment = []
281+
portMappings = []
282+
systemControls = []
283+
volumesFrom = []
207284
},
208285
var.dd_log_collection.log_router_health_check.command == null ? {} : {
209286
healthCheck = {
@@ -217,4 +294,22 @@ locals {
217294
)
218295
] : []
219296

297+
# Datadog CWS tracer definition
298+
dd_cws_container = local.is_cws_supported ? [
299+
{
300+
name = "cws-instrumentation-init"
301+
image = "datadog/cws-instrumentation:latest"
302+
cpu = var.dd_cws.cpu
303+
memory_limit_mib = var.dd_cws.memory_limit_mib
304+
user = "0"
305+
essential = false
306+
entryPoint = []
307+
command = ["/cws-instrumentation", "setup", "--cws-volume-mount", "/cws-instrumentation-volume"]
308+
mountPoints = local.cws_mount
309+
environment = []
310+
portMappings = []
311+
systemControls = []
312+
volumesFrom = []
313+
}
314+
] : []
220315
}

modules/ecs_fargate/main.tf

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ resource "aws_ecs_task_definition" "this" {
88
concat(
99
local.dd_agent_container,
1010
local.dd_log_container,
11+
local.dd_cws_container,
1112
[for k, v in local.modified_container_definitions : v],
1213
)
1314
)
@@ -139,7 +140,10 @@ resource "aws_ecs_task_definition" "this" {
139140
}
140141
}
141142

142-
tags = var.tags
143+
tags = merge(
144+
var.tags,
145+
local.tags,
146+
)
143147

144148
depends_on = [
145149
aws_iam_role.new_ecs_task_role,

modules/ecs_fargate/variables.tf

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,12 +197,28 @@ variable "dd_log_collection" {
197197
}
198198
}
199199

200+
variable "dd_cws" {
201+
description = "Configuration for Datadog Cloud Workload Security (CWS)"
202+
type = object({
203+
enabled = bool
204+
cpu = optional(number)
205+
memory_limit_mib = optional(number)
206+
})
207+
default = {
208+
enabled = false
209+
}
210+
validation {
211+
condition = var.dd_cws != null
212+
error_message = "The Datadog Cloud Workload Security (CWS) configuration must be defined."
213+
}
214+
}
215+
200216
################################################################################
201217
# Task Definition
202218
################################################################################
203219

204220
variable "container_definitions" {
205-
description = "A map of valid [container definitions](http://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDefinition.html). Please note that you should only provide values that are part of the container definition document"
221+
description = "A list of valid [container definitions](http://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDefinition.html). Please note that you should only provide values that are part of the container definition document"
206222
type = any
207223
}
208224

@@ -298,8 +314,8 @@ variable "requires_compatibilities" {
298314
variable "runtime_platform" {
299315
description = "Configuration block for `runtime_platform` that containers in your task may use"
300316
type = object({
301-
cpu_architecture = string
302-
operating_system_family = string
317+
cpu_architecture = optional(string, "LINUX")
318+
operating_system_family = optional(string, "X86_64")
303319
})
304320
default = {
305321
operating_system_family = "LINUX"
@@ -316,7 +332,7 @@ variable "skip_destroy" {
316332
variable "tags" {
317333
description = "A map of additional tags to add to the task definition/set created"
318334
type = map(string)
319-
default = {}
335+
default = null
320336
}
321337

322338
variable "task_role_arn" {

0 commit comments

Comments
 (0)