B2B SaaS Starter Kit: SOC 2
For B2B SaaS companies heading toward SOC 2 Type I or II. Deploys the infrastructure layer your auditor will ask about: encrypted databases, private subnets, HTTPS-only endpoints, access logging, Multi-AZ data stores.
GitHub: compliancetf/starter-kit-saas-soc2
Registry: soc2.compliance.tf
Resources deployed: approximately 107
Architecture

The architecture covers the typical SaaS application layer: a public-facing ALB with WAF, a private EKS cluster, an Aurora PostgreSQL database in dedicated database subnets, and shared services (S3, DynamoDB, ElastiCache, SQS). VPC flow logs and CloudWatch log groups are included for CC7.1.
Module Inventory
| Module | Version | Purpose | Key SOC 2 Controls |
|---|---|---|---|
vpc | ~> 6.0 | Network isolation, flow logs, database subnets | CC6.1, CC7.1 |
alb | ~> 10.0 | HTTPS load balancing, access logs | CC6.6, CC6.7 |
waf | ~> 1.0 | Web Application Firewall (OWASP Top 10, IP reputation) | CC6.6 |
acm | ~> 6.0 | TLS certificate (DNS-validated) | CC6.7 |
kms | ~> 4.0 | Customer-managed key for EKS log encryption | CC6.1 |
eks | ~> 21.0 | Kubernetes cluster, private subnets, KMS-encrypted logs | CC6.1, CC7.1 |
rds_aurora | ~> 10.0 | Aurora PostgreSQL, Multi-AZ, encrypted, IAM auth | CC6.1, A1.2 |
s3_bucket_data | ~> 5.0 | Application data, cross-region replication | CC6.1, CC7.2, A1.2 |
s3_bucket_logs | ~> 5.0 | Centralized access logs (ALB + S3), cross-region replication | CC7.1, CC8.1, A1.2 |
dynamodb | ~> 5.0 | Key-value store, PITR | CC6.1, A1.2 |
elasticache | ~> 1.0 | Redis, encrypted at rest and in transit, auth, failover | CC6.1, A1.2 |
sqs | ~> 5.0 | Message queue, DLQ | CC6.1, CC7.2 |
cloudwatch | ~> 5.0 | Application log group | CC7.1, CC7.2 |
Quick Start
Prerequisites: Terraform >= 1.3, AWS credentials, a compliance.tf account, a Route 53 hosted zone, and an S3 replication IAM role + destination bucket for cross-region replication (required for SOC 2 A1.2).
git clone https://github.com/compliancetf/starter-kit-saas-soc2.git
cd starter-kit-saas-soc2
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars: set project_name, domain_name, route53_zone_id,
# availability_zones, s3_replication_role_arn, s3_replication_destination_bucket_arn
terraform login soc2.compliance.tf
terraform init
terraform plan
terraform applyterraform plan fails if any SOC 2 control is violated. The error names the specific control and the module that triggered it. Fix the issue and re-run.
SOC 2 Control Coverage
| SOC 2 Criterion | Description | Module(s) | What's Enforced |
|---|---|---|---|
| CC6.1 | Logical access security | KMS, RDS Aurora, S3, EKS, ElastiCache, DynamoDB, SQS | Encryption at rest, customer-managed keys, no public access, IAM authentication |
| CC6.6 | Logical access security measures against threats from outside system boundaries | ALB, WAF | TLS 1.2+ (TLS 1.3 policy), HTTPS-only, WAF with OWASP Top 10 and IP reputation rules |
| CC6.7 | Restriction of data transmission to authorized users and processes | ALB, ElastiCache | HTTPS-only listeners, transit encryption enabled |
| CC7.1 | Detection of configuration changes that introduce vulnerabilities and susceptibilities to newly discovered vulnerabilities | VPC, ALB, RDS Aurora, CloudWatch, S3 (logs) | VPC flow logs, ALB access logs, PostgreSQL log exports, CloudWatch log groups |
| CC7.2 | Monitoring of system components and controls on an ongoing basis to detect anomalies indicating malicious acts or errors | S3, SQS, CloudWatch | S3 versioning, dead-letter queues, log retention policies |
| CC8.1 | Change management controls | All modules | Infrastructure changes tracked in Terraform state and version control, deletion protection (prod) |
| A1.2 | Data backup processes, recovery infrastructure, and environmental protections | RDS Aurora, ElastiCache, S3 (data + logs) | Multi-AZ deployment, automatic failover, automated backups (7-14 days), S3 cross-region replication |
What compliance.tf Covers vs. What You Own
compliance.tf enforces the infrastructure controls in SOC 2. The table below shows the split.
What this kit handles
- Encryption at rest and in transit for all data stores
- S3 cross-region replication (SOC 2 A1.2 data durability)
- Network isolation: private subnets, database subnets, no public database access
- TLS 1.2+ on all external endpoints, enforced by the registry at plan time
- Access logging: VPC flow logs, ALB access logs, Aurora PostgreSQL logs
- Multi-AZ and automated backups
- Deletion protection in production (
environment = "prod") - Validation at
terraform plan; non-compliant configurations fail before deployment
What you own
- Application-level authentication, authorization, and session management
- Identity provider configuration and MFA enforcement
- HR policies: background checks, security awareness training
- Vendor management and third-party risk assessments
- Incident response procedures and runbooks
- Business continuity planning
- Access reviews and user lifecycle management
- Application-level audit logging for business events
compliance.tf does not replace a SOC 2 auditor. It covers the infrastructure controls. The audit will still cover organizational controls (HR policies, access reviews, incident response, vendor management) but not whether Aurora is encrypted or S3 blocks public access.
Vanta and Drata Integration
compliance.tf evidence maps directly to the categories that Vanta and Drata check automatically.
| Compliance Platform Check | SOC 2 Criterion | What compliance.tf Enforces |
|---|---|---|
| Encryption at rest (databases) | CC6.1 | RDS Aurora, DynamoDB, ElastiCache, S3 encrypted with KMS |
| HTTPS enforced on load balancers | CC6.6, CC6.7 | ALB HTTPS-only listener, TLS 1.2+ policy |
| S3 buckets not publicly accessible | CC6.1 | S3 module blocks all public access by default |
| RDS not publicly accessible | CC6.1 | Aurora deployed in private database subnets, no public endpoint |
| VPC flow logs enabled | CC7.1 | VPC module enables flow logs by default |
| Multi-AZ for RDS | A1.2 | Aurora writer + reader across multiple availability zones |
| S3 versioning enabled | CC7.2 | S3 data bucket has versioning enabled by default |
For evidence collection, point your compliance platform at the Terraform state or the AWS resource tags. All modules in this kit tag resources with Project, Environment, and ManagedBy = "terraform" so resources are easy to scope during evidence gathering.
CloudTrail is not in this kit
Vanta and Drata both check for CloudTrail, which is account-wide. Enable CloudTrail at the account level separately; it is not a module-level control. The compliance.tf get started guide covers account-level prerequisites.
Common Customizations
Swap EKS for ECS
Remove the eks module block from main.tf and replace it with the ecs module from soc2.compliance.tf. Update the ALB target group to point at your ECS service instead of EKS pods.
module "ecs" {
source = "soc2.compliance.tf/terraform-aws-modules/ecs/aws"
version = "~> 5.0"
cluster_name = local.name
fargate_capacity_providers = {
FARGATE = {
default_capacity_provider_strategy = {
weight = 100
}
}
}
tags = var.tags
}Add a second region for disaster recovery
S3 cross-region replication is already configured for the data and logs buckets via the s3_replication_role_arn and s3_replication_destination_bucket_arn variables. To extend DR to compute and database layers, use a second provider alias and duplicate the relevant module blocks:
provider "aws" {
alias = "dr"
region = "us-west-2"
}Use Aurora Global Database for database replication across regions.
Adjust instance sizes
All instance sizes are variables. Override them in terraform.tfvars:
eks_node_instance_types = ["m6i.xlarge"]
eks_node_min_size = 3
eks_node_max_size = 10
aurora_instance_class = "db.r6g.xlarge"
redis_node_type = "cache.r6g.large"Remove a module you don't need
If your application does not use DynamoDB or SQS, delete those module blocks from main.tf and remove the corresponding outputs. The remaining modules are independent; removing one does not break others.
Disable a specific control
If a SOC 2 control does not apply to your use case, disable it with a query parameter on the module source:
module "s3_bucket_data" {
source = "soc2.compliance.tf/terraform-aws-modules/s3-bucket/aws?disable=s3_bucket_object_lock_enabled"
version = "~> 5.0"
# ...
}Cost Estimate
| Component | Dev | Prod |
|---|---|---|
| VPC + NAT Gateway | ~$35 | ~$100 |
| ALB | ~$25 | ~$25+ |
| EKS control plane | ~$75 | ~$75 |
| EKS nodes (t3.medium) | ~$60 | ~$120+ |
| Aurora PostgreSQL (db.r6g.large) | ~$200 | ~$400 |
| S3 (data + logs) | ~$5 | ~$5+ |
| DynamoDB (on-demand) | ~$0 | ~$0+ |
| ElastiCache (cache.t4g.micro) | ~$10 | ~$20 |
| SQS | ~$0 | ~$0+ |
| CloudWatch Logs | ~$5 | ~$10+ |
| WAF | ~$5 | ~$5+ |
| KMS | ~$1 | ~$1+ |
| Total | ~$500-800 | ~$1,500-2,500 |
Actual costs depend on usage, data transfer, and region. Use Infracost to get an estimate from your actual terraform plan output.
Next Steps
- Brownfield Migration Kit: if you have existing Terraform using terraform-aws-modules, migrate to compliance.tf instead of deploying fresh
- Audit Evidence Guide: how to prepare infrastructure evidence for SOC 2 auditors
- SOC 2 Framework Reference: full list of controls enforced per criterion
- Version Compatibility Matrix: which upstream module versions compliance.tf supports