This post explains how small businesses can use Terraform to automate the deployment of compliant subnetwork topologies for public-facing components in line with the Compliance Framework, including practical Terraform code examples, architecture patterns, and operational best practices tied to FAR 52.204-21 and CMMC 2.0 Level 1 expectations (SC.L1-B.1.XI).
Understanding the compliance objective
The Compliance Framework requires that public-facing components are segregated, hardened, logged, and managed so that contractor and federal information is protected from unauthorized access and disclosure. For small businesses, meeting this typically means: placing internet-exposed resources in dedicated public subnets, restricting direct access to backend systems, enabling egress controls, collecting network logs, and automating repeatable, auditable deployments. Terraform provides a deterministic way to codify these constraints and to bake compliance checks into CI/CD pipelines.
Recommended architecture pattern for public-facing deployments
A simple, compliant pattern for a small-business web/API workload is: a VPC with at least two Availability Zones; dedicated public subnets for load balancers and NAT gateways (map public IPs); private subnets for application servers and databases; an Internet Gateway attached to the VPC; route tables that only allow public subnet 0.0.0.0/0 via the IGW; a NAT Gateway in each AZ for private subnet egress; Security Groups and Network ACLs that implement explicit allow rules; VPC Flow Logs and CloudTrail enabled for auditing. This separation reduces attack surface and makes it easier to demonstrate control implementation for FAR and CMMC reviewers.
Terraform implementation — practical examples
Below are compact yet practical Terraform snippets you can adapt. They show a VPC, two public subnets, an IGW and route table, and a security group pattern that allows the ALB to speak to app servers while limiting direct internet exposure for backends.
# vpc.tf
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = merge(var.common_tags, { Name = "compliant-vpc" })
}
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main.id
tags = merge(var.common_tags, { Name = "compliant-igw" })
}
resource "aws_subnet" "public" {
count = length(var.public_subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnet_cidrs[count.index]
map_public_ip_on_launch = true
availability_zone = element(data.aws_availability_zones.available.names, count.index)
tags = merge(var.common_tags, { Name = "public-${count.index}" , Tier="public" })
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
tags = merge(var.common_tags, { Name = "public-rt" })
}
resource "aws_route_table_association" "public_assoc" {
count = length(aws_subnet.public)
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
Security group strategy (ALB + app servers): ALB SG allows 80/443 from 0.0.0.0/0; App SG allows only the ALB SG on the app port (e.g., 8080). Never open SSH (22) or DB ports (e.g., 3306/5432) to the internet; use bastion or session manager for admin access.
# security-groups.tf
resource "aws_security_group" "alb" {
name = "alb-sg"
description = "Allow HTTP/HTTPS"
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = var.common_tags
}
resource "aws_security_group" "app" {
name = "app-sg"
description = "Allow only ALB to reach app"
vpc_id = aws_vpc.main.id
ingress {
from_port = var.app_port
to_port = var.app_port
protocol = "tcp"
security_groups = [aws_security_group.alb.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["10.0.0.0/8"] # restrict egress where practical
}
tags = var.common_tags
}
Operational automation and CI/CD controls
Make infrastructure changes through a pipeline: terraform fmt, terraform validate, tfsec/Checkov scanning, terraform plan (stored as artifact), and manual or automated approval (PR-based policy). Keep state in an encrypted S3 bucket with DynamoDB state-locking (prevent concurrent applies). Example S3 backend and DynamoDB locking are standard patterns that also help evidence “controlled change” for audits. Store sensitive variables in an encrypted secrets manager and assign least-privilege IAM for the pipeline role — for example, a role that can only apply resources under a specific tag like environment=staging or environment=prod.
Logging, monitoring, and evidence capture
Enable VPC Flow Logs and send them to CloudWatch or S3 with lifecycle rules. Enable CloudTrail for all regions and ensure events are retained per your contract requirements. For small businesses, a recommended minimum is: VPC Flow Logs (capture accept/reject + traffic) + CloudTrail + ALB access logs. Automate creation of these resources in Terraform and tie them into your retention policy; include an S3 bucket policy to encrypt and restrict access. These artifacts are often requested during FAR/CMMC assessments as evidence of monitoring and boundary controls.
Compliance tips, testing, and governance
Use modular Terraform code (a 'network' module consumed by app stacks) so the network design is consistent across projects. Add guardrails with policy-as-code (OPA/Gatekeeper for Kubernetes, Sentinel for Terraform Enterprise, or Open Policy Agent in your CI) to prevent PRs that, for example, create internet-facing database instances or omit flow logs. Implement automated tests (Terratest or kitchen-terraform) to assert that public subnets have route tables to IGW and that private subnets do not. Maintain an evidence folder in CI that contains plan outputs, security scans, and approval logs to simplify compliance reviews.
Risk of non-implementation
Failure to implement these segregation and logging controls increases the risk of unauthorized access, lateral movement from internet-exposed components into sensitive systems, and undetected exfiltration. For small businesses contracting with the federal government, non-compliance can lead to contract termination, loss of future opportunities, or penalties under FAR 52.204-21. From a security standpoint, it also increases the chance of downtime and customer trust loss if public-facing components are misconfigured.
In summary, automating compliant subnetwork deployment with Terraform reduces manual error, provides an auditable trail for FAR 52.204-21 and CMMC 2.0 Level 1 controls, and makes it practical for small businesses to enforce segregation, logging, and least-privilege access. Start with a clear network module, codify security group and route rules, enable flow logs and CloudTrail, enforce checks with policy-as-code, and run infrastructure changes through a controlled CI/CD pipeline; these steps create an operational posture that meets compliance objectives while remaining maintainable and scalable.