How Do You Prepare ECS Fargate for a SOC 2 Audit?
AWS is SOC 2 certified - so why aren't you?
AWS's SOC 2 covers security of the cloud - datacenters, hypervisor, hardware. You own security in the cloud: your ECS task definitions, IAM, and logging. The auditor only tests your half.
The single most common SOC 2 misconception on AWS is that running on a SOC 2-certified platform makes you SOC 2-compliant. It doesn't. The shared responsibility model splits the control set: AWS proves the infrastructure is secure, and you prove that what you run on it is secure.
You can download AWS's own SOC 2 report from AWS Artifact - the self-service portal in the console, gated behind an NDA - and hand it to your auditor. That lets them inherit AWS's infrastructure controls and stop looking at the datacenter. What's left is your half - and for an ECS shop, your half is mostly task definitions, IAM scoping, and logging. The auditor will also want the audit trail of who changed what across your fleet - CloudTrail is the evidence source for that control.
The rest of this guide is the ECS-specific part nobody else writes down.
| AWS proves (inherited) | You prove (tested) |
|---|---|
| Datacenter physical security | Task-def hardening (ECS.4/.5/.20) |
| Hypervisor & host patching | IAM scoping & least privilege |
| Fargate platform isolation | Secrets handling (SSM / Secrets Manager) |
| Network backbone | Logging & monitoring (ECS.9/.12) |
Ready to use: a SOC 2-clean task definition
This Fargate task definition clears the Security Hub ECS controls that flag a task - the high-severity ones (ECS.4, ECS.5, ECS.8, ECS.9, ECS.2) plus the medium-severity non-root and Container Insights checks. Each hardened line is annotated with the control ID it satisfies.
The whole point: every flagged setting is a task-definition parameter, not an application rewrite. Drop this into your shared ECS module and every environment inherits the same clean baseline.
Ready to use - copy this today:
resource "aws_ecs_task_definition" "app" {
family = "use1-prod-main-app"
requires_compatibilities = ["FARGATE"]
network_mode = "awsvpc"
cpu = "512"
memory = "1024"
execution_role_arn = aws_iam_role.task_exec.arn
task_role_arn = aws_iam_role.task.arn
container_definitions = jsonencode([{
name = "app"
image = "${aws_ecr_repository.app.repository_url}:${var.image_tag}"
user = "10001" # ECS.20 - non-root Linux user
privileged = false # ECS.4 - no elevated privileges
readonlyRootFilesystem = true # ECS.5 - read-only root filesystem
# ECS.8 - secrets via valueFrom, never plain environment vars
secrets = [{
name = "DB_PASSWORD"
valueFrom = aws_secretsmanager_secret.db.arn
}]
# ECS.9 - task definition must declare a log configuration
logConfiguration = {
logDriver = "awslogs"
options = {
"awslogs-group" = "/ecs/use1-prod-main-app"
"awslogs-region" = "us-east-1"
"awslogs-stream-prefix" = "app"
}
}
}])
}
# ECS.2 - never auto-assign a public IP (ECS.16 is the task-set equivalent)
resource "aws_ecs_service" "app" {
name = "use1-prod-main-app"
task_definition = aws_ecs_task_definition.app.arn
launch_type = "FARGATE"
network_configuration {
subnets = var.private_subnet_ids
assign_public_ip = false
}
}
If your container needs scratch space, readonlyRootFilesystem = true breaks apps that write to /tmp. Don't revert the control - mount a writable tmpfs volume for the paths that need it. The root filesystem stays read-only; the auditor still passes ECS.5; your app still writes its temp files.
The ECS controls an auditor's tooling flags
Security Hub checks specific ECS controls: ECS.4 non-privileged, ECS.5 read-only root filesystem, ECS.8 no credential keys in env vars, ECS.9 logging, ECS.20 non-root user, ECS.2 / ECS.16 no public IP. These are the AWS-published Security Hub CSPM checks for ECS. An auditor - or your own CSPM dashboard, or Vanta/Drata pulling from Security Hub - surfaces failures by control ID.
Each row below is a task-definition parameter and the value that fails it:
| Control | Fails when | The fix | TSC |
|---|---|---|---|
| ECS.4 | privileged = true |
privileged: false |
CC6 |
| ECS.5 | readonlyRootFilesystem false / absent |
readonlyRootFilesystem: true |
CC6 |
| ECS.20 | Linux user is root or unset | user: a non-root UID |
CC6 |
| ECS.2 | AssignPublicIp ENABLED |
assign_public_ip: DISABLED |
CC6 |
| ECS.8 | AWS credential key in environment vars | secrets via valueFrom (SSM / Secrets Manager) |
CC6 |
| ECS.9 | no logConfiguration |
logConfiguration with awslogs / FireLens |
CC7 |
| ECS.12 | Container Insights off on cluster | enable Container Insights | CC7 |
The TSC column is the Trust Services Criterion each control maps to - explained below. AWS tags these controls against NIST 800-53 and PCI; the SOC 2 mapping is the one your auditor draws, and it's worth handing them pre-drawn.
Fix it in the task definition
Every high-severity ECS finding is one task-definition parameter: readonlyRootFilesystem, user, privileged, secrets via valueFrom, logConfiguration, assignPublicIp. Set them once in your module. None of these are application changes. They're container-definition fields - the same ones covered in every task-definition field and the common mistakes.
The remediation that trips teams up isn't writing the values; it's applying them to every task definition across every environment without missing one.
KEY INSIGHT: Set the hardened parameters as module-level defaults, not per-service overrides. A shared ECS module that bakes in readonlyRootFilesystem = true, a non-root user, and assign_public_ip = false means every new environment is compliant the day it's created - and you can't forget the setting on environment number twelve.
Map ECS controls to Trust Services Criteria
Most ECS findings map to two criteria: CC6 logical access (non-root, no privilege, no public IP) and CC7 monitoring (logging, Container Insights, GuardDuty). Your auditor wants the mapping spelled out.
SOC 2's Common Criteria are where ECS lives. CC6 (Logical and Physical Access Controls - the logical half is yours) is the bucket for least privilege: ECS.4 (no privileged containers), ECS.5 (read-only root filesystem), ECS.20 (non-root user), and ECS.2 / ECS.16 (no public IP) all reduce the access an attacker gets if a container is compromised.
CC7 (System Operations) is monitoring: ECS.9 (logging configured), ECS.12 (Container Insights), and GuardDuty Runtime Monitoring give you the detection the criterion asks for. CC6 also covers human access - auditors expect per-environment RBAC scoping developer access so no one but the right people can touch a given environment.
Handing your auditor the control-to-criterion mapping pre-drawn - "ECS.5 satisfies our CC6.1 least-privilege control" - turns a back-and-forth into a checkbox. They do this mapping anyway; doing it for them shortens the audit.
The real work is six months of evidence
Type II isn't a one-day fix - it's a ~6-month observation window. The auditor wants proof the controls held every day, across every environment. One drifted task def in month four is a finding.
A first SOC 2 Type II runs roughly months 1–3 to implement controls, then a six-month window where the auditor verifies they operated continuously. Type I is a point-in-time snapshot; Type II is the movie. That distinction is the whole cost: the hardened task definition takes an afternoon, but proving it stayed hardened across eleven environments for six months is the part that consumes the platform team.
This is where multi-environment ECS shops feel it. Vanta and Drata automate the evidence collection from Security Hub and Config - but they collect whatever state exists. If a developer spins up environment twelve from an older module, or someone toggles a setting at 2am during an incident, the drift is real and the evidence captures it. The control that matters most at fleet scale isn't any single ECS.x check - it's knowing the whole fleet's state, continuously, so drift surfaces the day it happens, not in the auditor's sample three months later.
What SOC 2 does NOT require for ECS
SOC 2 is risk-based, not prescriptive. It does not require EKS-style admission controllers, a service mesh, or a specific scanner for ECS. Don't over-build controls the auditor never asked for.
Unlike a prescriptive standard, SOC 2 lets you define your own controls against the Trust Services Criteria, then proves you operate them. There is no SOC 2 line item that says "run OPA Gatekeeper" or "deploy a service mesh." Teams coming from Kubernetes sometimes import a control set they don't need - admission webhooks, Pod Security Standards, a sidecar mesh - none of which an ECS auditor asks for.
The trap is scope creep: every extra control you claim in your system description is a control you now have to produce six months of evidence for. Match your stated controls to your actual architecture. For ECS Fargate, the high-severity Security Hub controls plus scoped IAM, logging, and an audit trail cover the Common Criteria an auditor tests. Build those well; skip the rest.
If you read this, you might also want to know
Do I need a separate AWS account for SOC 2? Not strictly. SOC 2 doesn't mandate account structure - it cares that prod is isolated and access is scoped. A separate prod account is the cleanest way to draw that boundary and makes the auditor's scoping trivial, but a single account with hard IAM separation and tagging can pass. Most teams split prod out anyway, for blast radius as much as for the audit.
Does Fargate make SOC 2 easier than EC2? Yes, on the infrastructure half. Fargate removes the host from your responsibility - no EC2 patching, no host hardening, no SSH access control to evidence. AWS builds the patched Fargate platform versions; you stay current by running platform version LATEST and redeploying - ECS.10 fails if a service is pinned to an older version. You inherit more of the control set, leaving you the task-definition and IAM half. On EC2 launch type, host-level controls land back on you.
How long does a first SOC 2 Type II take? Plan on 9-12 months end to end: roughly 1-3 months to implement and document controls, then a 6-month observation window the auditor reviews, then the report. A Type I (point-in-time) can be done in weeks and is sometimes used as a stepping stone to show progress while the Type II window runs.
Can Vanta or Drata collect ECS evidence automatically? Partly. They integrate with AWS Security Hub and Config to pull control state - including the ECS.x findings - and map them to SOC 2 criteria automatically. What they can't do is fix drift or give you a single operational view of every environment's live state. They report what exists; keeping the fleet itself consistent is still on you.
Book a 20-min fleet walkthrough: fortem.dev/book
Comments
No comments yet. Start the discussion.