How Do You Prepare ECS Fargate for a SOC 2 Audit?
A prospect won't sign without your SOC 2 Type II report. You bought Vanta, the dashboard lit up red — and half the failing controls point at your ECS task definitions. AWS being SOC 2 certified does not make you compliant — it covers the cloud; you own what runs in it. This is the ECS-specific remediation: the exact Fargate settings an auditor's tooling flags, the copy-paste fixes, and why the real work of Type II is six months of evidence, not a one-day config sprint.
- ·AWS's SOC 2 covers the cloud (Artifact report, under NDA). Your ECS task definitions, IAM, and logging are yours to prove — that's the shared responsibility line.
- ·Security Hub flags specific ECS controls: ECS.4 (non-privileged), ECS.5 (read-only root FS), ECS.8 (no secrets in env vars), ECS.9 (logging), ECS.20 (non-root user), ECS.2 (no public IP).
- ·Most ECS findings map to two Trust Services Criteria: CC6 (logical access) and CC7 (monitoring). Fix the task-def parameters and they clear.
- ·Type II is a ~6-month observation window. The hard part isn't the one-time fix — it's continuous evidence the controls held across every environment, every day.
- ·SOC 2 does NOT require EKS-style admission controllers or a service mesh for ECS. Don't over-build controls the auditor never asked for.
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.
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
}
}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:
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.
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 = falsemeans 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.
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.
FAQ
The config is a day.
The evidence is six months.
Fortem gives you continuous fleet-wide state — RBAC by environment, a who-did-what audit log, and config across every account — the operational evidence layer a Type II actually leans on. It doesn't replace Vanta or Drata; it keeps the fleet underneath them consistent. Book a 20-minute walkthrough.