ECS task definitions should not share the host's process namespace
Sharing the host's PID namespace removes a fundamental isolation boundary. Containers with host PID visibility can enumerate all processes running on the host, send signals to them, and read sensitive information from /proc. An attacker who compromises a single container can then inspect the environment variables of every other process on the host, including those belonging to other tenants or the ECS agent itself, and environment variables frequently carry secrets.
This setting is rarely needed in production. Most use cases that appear to require host PID mode (debugging, process monitoring) can be handled through sidecar containers sharing task-level PID namespaces or dedicated observability tooling.
Retrofit consideration
If any running tasks depend on host PID visibility for custom health checks or process monitoring, removing pid_mode = "host" will break that functionality. Identify those dependencies before making changes.
Implementation
Choose the approach that matches how you manage Terraform.
Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.
module "ecs" {
source = "pcidss.compliance.tf/terraform-aws-modules/ecs/aws//modules/service"
version = ">=6.0.0"
cluster_arn = "arn:aws:ecs:us-east-1:123456789012:cluster/example-cluster"
container_definitions = {
main = {
essential = true
image = "public.ecr.aws/docker/library/httpd:latest"
portMappings = [
{
containerPort = 80
protocol = "tcp"
}
]
}
}
cpu = 256
memory = 512
name = "abc123"
subnet_ids = ["subnet-12345678"]
}
module "ecs" {
source = "nistcsf.compliance.tf/terraform-aws-modules/ecs/aws//modules/service"
version = ">=6.0.0"
cluster_arn = "arn:aws:ecs:us-east-1:123456789012:cluster/example-cluster"
container_definitions = {
main = {
essential = true
image = "public.ecr.aws/docker/library/httpd:latest"
portMappings = [
{
containerPort = 80
protocol = "tcp"
}
]
}
}
cpu = 256
memory = 512
name = "abc123"
subnet_ids = ["subnet-12345678"]
}
module "ecs" {
source = "nistcsfv11.compliance.tf/terraform-aws-modules/ecs/aws//modules/service"
version = ">=6.0.0"
cluster_arn = "arn:aws:ecs:us-east-1:123456789012:cluster/example-cluster"
container_definitions = {
main = {
essential = true
image = "public.ecr.aws/docker/library/httpd:latest"
portMappings = [
{
containerPort = 80
protocol = "tcp"
}
]
}
}
cpu = 256
memory = 512
name = "abc123"
subnet_ids = ["subnet-12345678"]
}
If you use terraform-aws-modules/ecs/aws//modules/service, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.
module "ecs" {
source = "terraform-aws-modules/ecs/aws//modules/service"
version = ">=6.0.0"
cluster_arn = "arn:aws:ecs:us-east-1:123456789012:cluster/example-cluster"
container_definitions = {
main = {
essential = true
image = "public.ecr.aws/docker/library/httpd:latest"
portMappings = [
{
containerPort = 80
protocol = "tcp"
}
]
}
}
cpu = 256
memory = 512
name = "abc123"
subnet_ids = ["subnet-12345678"]
}
Use AWS provider resources directly. See docs for the resources involved: aws_ecs_task_definition.
resource "aws_ecs_task_definition" "this" {
container_definitions = jsonencode([{ name = "app", image = "nginx:latest", essential = true, portMappings = [{ containerPort = 80 }] }])
cpu = "256"
family = "pofix-abc123"
memory = "512"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
}
What this control checks
In the aws_ecs_task_definition resource, the pid_mode argument controls which PID namespace containers use. It fails if pid_mode is set to "host". To pass, either omit pid_mode entirely (the default does not share the host namespace) or set it to "task", which shares a PID namespace only among containers within the same task. Fargate tasks do not support "host" PID mode at all and pass by default. For EC2 launch type tasks, explicitly verify that pid_mode is absent or set to "task".
Common pitfalls
Revision drift from console or CI/CD re-registration
ECS task definitions are immutable; each update creates a new revision. If someone registers a new revision via the AWS Console or
aws ecs register-task-definitionwith--pid-mode host, Terraform will not detect the drift because the old revision still matches state. Pin services to Terraform-managed revisions and monitor all active revisions, not just the latest one tracked in state.Confusing pid_mode with ipc_mode
ipc_modealso accepts"host"and exposes a different namespace: System V IPC. Fixingpid_modealone does not address IPC namespace sharing. Review both arguments when hardening task definitions.Task-level PID sharing misunderstood as host sharing
pid_mode = "task"lets containers within the same task share a PID namespace with each other, which is useful for sidecar patterns. It is not the same as"host"and passes this control. Don't remove"task"unless you have a specific reason to fully isolate PID namespaces between containers in the same task.
Audit evidence
Auditors will look for AWS Config rule evaluation results showing all active ECS task definitions in a compliant state, or equivalent output from a Cloud Security Posture Management tool. The DescribeTaskDefinition API response for each active task definition should show pidMode as either null or "task", never "host".
A bulk export using aws ecs list-task-definitions followed by aws ecs describe-task-definition for each ARN works as point-in-time evidence. For continuous assurance, Config recording for AWS::ECS::TaskDefinition resources with an appropriate managed or custom rule provides ongoing evidence with timestamps and change history.
Framework-specific interpretation
PCI DSS v4.0: Requirements 2.2 and 6.3.1 both cover this. Req 2.2 expects system components to be configured securely; leaving pid_mode = "host" on any task in a CDE is a straightforward hardening failure. Req 6.3.1 applies to how security features are defined for software components, and process namespace isolation falls squarely within that scope.
NIST Cybersecurity Framework v2.0: PR.DS and PR.IR both apply. A container that can read /proc for every host process crosses the boundary PR.DS is designed to protect, and PR.IR concerns itself with limiting blast radius when a single workload is compromised. Keeping PID namespaces task-scoped addresses both.
Related controls
Tool mappings
Use these identifiers to cross-reference this control across tools, reports, and evidence.
Compliance.tf Control:
ecs_task_definition_no_host_pid_modeAWS Config Managed Rule:
ECS_TASK_DEFINITION_PID_MODE_CHECKCheckov Check:
CKV_AWS_335Powerpipe Control:
aws_compliance.control.ecs_task_definition_no_host_pid_modeProwler Check:
ecs_task_definitions_host_namespace_not_sharedAWS Security Hub Control:
ECS.3
Last reviewed: 2026-03-09