{
  "title": "Step-by-Step Terraform Templates to Create Compliant Subnetworks for Public Services: FAR 52.204-21 / CMMC 2.0 Level 1 - Control - SC.L1-B.1.XI",
  "date": "2026-04-04",
  "author": "Lakeridge Technologies",
  "featured_image": "/assets/images/blog/2026/4/step-by-step-terraform-templates-to-create-compliant-subnetworks-for-public-services-far-52204-21-cmmc-20-level-1-control-scl1-b1xi.jpg",
  "content": {
    "full_html": "<p>This post provides hands-on Terraform templates and step-by-step guidance to create compliant public subnetworks for hosting internet-facing services in alignment with FAR 52.204-21 basic safeguarding and CMMC 2.0 Level 1 SC.L1-B.1.XI expectations, with practical tips for a small business environment.</p>\n\n<h2>Why subnetworks matter for FAR 52.204-21 and CMMC 2.0 Level 1</h2>\n<p>FAR 52.204-21 requires contractors to implement basic safeguards for contractor information systems, and CMMC 2.0 Level 1 focuses on basic cyber hygiene—both of which include network segmentation and boundary protections to reduce exposure of sensitive information. Creating dedicated public subnetworks for public services (e.g., web frontends, public APIs) while keeping sensitive assets in private subnets reduces attack surface, simplifies auditing, and supports least privilege and separation of duties.</p>\n\n<h2>High-level design and compliance mapping</h2>\n<p>Design a VPC with: (1) one or more public subnets for internet-facing services, each associated with a dedicated route table and Internet Gateway; (2) private subnets for application or data stores; (3) strict security groups that only allow required ingress (e.g., 80/443) and explicit egress controls; (4) centralized logging for VPC Flow Logs and OS/application logs; and (5) management access via bastion hosts or vendor management tools such as AWS Systems Manager Session Manager. These controls provide evidence and operational behavior that align to the Compliance Framework requirements for boundary protection, monitoring, and access restrictions.</p>\n\n<h2>Step-by-step Terraform templates (AWS example)</h2>\n<p>Below are compact, practical Terraform snippets you can assemble into a module. This example assumes AWS; adapt provider blocks for other clouds. Files: vpc.tf, public_subnet.tf, igw_route.tf, security_groups.tf, flow_logs.tf, outputs.tf. Run terraform init, plan, apply after filling variables.</p>\n\n<h3>Main VPC and public subnet (vpc.tf / public_subnet.tf)</h3>\n<p><pre><code class=\"language-hcl\">resource \"aws_vpc\" \"main\" {\n  cidr_block           = var.vpc_cidr\n  enable_dns_hostnames = true\n  tags = {\n    Name        = \"${var.env}-vpc\"\n    Classification = var.classification\n  }\n}\n\nresource \"aws_subnet\" \"public\" {\n  count                   = length(var.public_subnet_cidrs)\n  vpc_id                  = aws_vpc.main.id\n  cidr_block              = var.public_subnet_cidrs[count.index]\n  map_public_ip_on_launch = true\n  availability_zone       = element(data.aws_availability_zones.available.names, count.index)\n  tags = {\n    Name = \"${var.env}-public-${count.index}\"\n    Role = \"public\"\n  }\n}</code></pre></p>\n\n<h3>Internet gateway and public route table (igw_route.tf)</h3>\n<p><pre><code class=\"language-hcl\">resource \"aws_internet_gateway\" \"igw\" {\n  vpc_id = aws_vpc.main.id\n  tags = { Name = \"${var.env}-igw\" }\n}\n\nresource \"aws_route_table\" \"public_rt\" {\n  vpc_id = aws_vpc.main.id\n  route {\n    cidr_block = \"0.0.0.0/0\"\n    gateway_id = aws_internet_gateway.igw.id\n  }\n  tags = { Name = \"${var.env}-public-rt\" }\n}\n\nresource \"aws_route_table_association\" \"public_assoc\" {\n  count          = length(aws_subnet.public)\n  subnet_id      = aws_subnet.public[count.index].id\n  route_table_id = aws_route_table.public_rt.id\n}</code></pre></p>\n\n<h3>Security group for public services (security_groups.tf)</h3>\n<p><pre><code class=\"language-hcl\">resource \"aws_security_group\" \"public_sg\" {\n  name        = \"${var.env}-public-sg\"\n  description = \"Allow only HTTP/HTTPS from the Internet and health checks\"\n  vpc_id      = aws_vpc.main.id\n\n  ingress {\n    description = \"HTTP\"\n    from_port   = 80\n    to_port     = 80\n    protocol    = \"tcp\"\n    cidr_blocks = [\"0.0.0.0/0\"]\n  }\n  ingress {\n    description = \"HTTPS\"\n    from_port   = 443\n    to_port     = 443\n    protocol    = \"tcp\"\n    cidr_blocks = [\"0.0.0.0/0\"]\n  }\n  # Block SSH from Internet - enforce SSM or VPN\n  egress {\n    from_port   = 0\n    to_port     = 0\n    protocol    = \"-1\"\n    cidr_blocks = [\"0.0.0.0/0\"]\n  }\n  tags = { Name = \"${var.env}-public-sg\" }\n}</code></pre></p>\n\n<h3>VPC Flow Logs and auditing (flow_logs.tf)</h3>\n<p><pre><code class=\"language-hcl\">resource \"aws_cloudwatch_log_group\" \"vpc_flow\" {\n  name              = \"/aws/vpc/flowlogs/${var.env}\"\n  retention_in_days = 90\n}\n\nresource \"aws_flow_log\" \"vpc\" {\n  resource_id = aws_vpc.main.id\n  resource_type = \"VPC\"\n  traffic_type = \"ALL\"\n  log_destination = aws_cloudwatch_log_group.vpc_flow.arn\n  iam_role_arn = aws_iam_role.flow_logs_role.arn\n}</code></pre></p>\n\n<h2>Practical implementation notes for a small business</h2>\n<p>Start small: create a single VPC and 2 public subnets across AZs for redundancy. Use Terraform modules in a private registry or version-controlled repo. Use variables for environment (dev/prod), cidr ranges, and classification tags (e.g., \"Controlled Unclassified Information\" or \"Non-sensitive\"). Use AWS Systems Manager to manage instances—this allows you to keep SSH off (no inbound 22) which is an important CMMC/NIST-aligned control to reduce attack surface.</p>\n\n<h2>Real-world example scenario</h2>\n<p>Imagine a small contractor hosting a public-facing documentation portal that may contain non-sensitive government contract information. Deploy the portal in the public subnets with the public_sg allowing only 80/443. Keep backend databases in private subnets inaccessible from the Internet; ensure the application uses IAM roles to access secrets (AWS Secrets Manager) so no credentials are stored on instances. Enable VPC Flow Logs and CloudWatch alarms for spikes in traffic that might indicate scanning or DDoS attempts—document these configurations for audit evidence required by FAR and CMMC.</p>\n\n<h2>Compliance tips, best practices, and evidence collection</h2>\n<p>Best practices: (1) tag resources consistently for automated evidence gathering (e.g., env, owner, classification); (2) enforce infrastructure-as-code reviews (pull requests) and retain Terraform state securely (remote backend with encryption and access controls); (3) enable drift detection and periodic reconciling; (4) restrict management access to known IPs or use a VPN/SSM; (5) log everything—VPC Flow Logs, CloudTrail, and host-level logs—and ship to centralized, immutable storage (S3 with MFA delete where possible); (6) store runbooks showing how subnetworks are provisioned and how to prove segregation during an audit.</p>\n\n<h2>Risks of not implementing this requirement</h2>\n<p>Without proper subnet separation and controls you increase the likelihood of data exposure, lateral movement after compromise, and inadvertent public access to sensitive systems. For contractors, failing to meet FAR 52.204-21 or CMMC Level 1 expectations risks contract disqualification, loss of award, regulatory penalties, and reputational damage. Operationally, you also face increased firefighting, higher incident response costs, and longer remediation timelines.</p>\n\n<p>In summary, using Terraform to create dedicated, well-tagged public subnetworks combined with strict security groups, centralized logging, management without open SSH, and documented evidence provides a practical, auditable path to meet the relevant FAR 52.204-21 and CMMC 2.0 Level 1 controls—start with the provided templates, tailor CIDR and tagging to your environment, enforce code reviews, and automate logging and monitoring to reduce risk.</p>",
    "plain_text": "This post provides hands-on Terraform templates and step-by-step guidance to create compliant public subnetworks for hosting internet-facing services in alignment with FAR 52.204-21 basic safeguarding and CMMC 2.0 Level 1 SC.L1-B.1.XI expectations, with practical tips for a small business environment.\n\nWhy subnetworks matter for FAR 52.204-21 and CMMC 2.0 Level 1\nFAR 52.204-21 requires contractors to implement basic safeguards for contractor information systems, and CMMC 2.0 Level 1 focuses on basic cyber hygiene—both of which include network segmentation and boundary protections to reduce exposure of sensitive information. Creating dedicated public subnetworks for public services (e.g., web frontends, public APIs) while keeping sensitive assets in private subnets reduces attack surface, simplifies auditing, and supports least privilege and separation of duties.\n\nHigh-level design and compliance mapping\nDesign a VPC with: (1) one or more public subnets for internet-facing services, each associated with a dedicated route table and Internet Gateway; (2) private subnets for application or data stores; (3) strict security groups that only allow required ingress (e.g., 80/443) and explicit egress controls; (4) centralized logging for VPC Flow Logs and OS/application logs; and (5) management access via bastion hosts or vendor management tools such as AWS Systems Manager Session Manager. These controls provide evidence and operational behavior that align to the Compliance Framework requirements for boundary protection, monitoring, and access restrictions.\n\nStep-by-step Terraform templates (AWS example)\nBelow are compact, practical Terraform snippets you can assemble into a module. This example assumes AWS; adapt provider blocks for other clouds. Files: vpc.tf, public_subnet.tf, igw_route.tf, security_groups.tf, flow_logs.tf, outputs.tf. Run terraform init, plan, apply after filling variables.\n\nMain VPC and public subnet (vpc.tf / public_subnet.tf)\nresource \"aws_vpc\" \"main\" {\n  cidr_block           = var.vpc_cidr\n  enable_dns_hostnames = true\n  tags = {\n    Name        = \"${var.env}-vpc\"\n    Classification = var.classification\n  }\n}\n\nresource \"aws_subnet\" \"public\" {\n  count                   = length(var.public_subnet_cidrs)\n  vpc_id                  = aws_vpc.main.id\n  cidr_block              = var.public_subnet_cidrs[count.index]\n  map_public_ip_on_launch = true\n  availability_zone       = element(data.aws_availability_zones.available.names, count.index)\n  tags = {\n    Name = \"${var.env}-public-${count.index}\"\n    Role = \"public\"\n  }\n}\n\nInternet gateway and public route table (igw_route.tf)\nresource \"aws_internet_gateway\" \"igw\" {\n  vpc_id = aws_vpc.main.id\n  tags = { Name = \"${var.env}-igw\" }\n}\n\nresource \"aws_route_table\" \"public_rt\" {\n  vpc_id = aws_vpc.main.id\n  route {\n    cidr_block = \"0.0.0.0/0\"\n    gateway_id = aws_internet_gateway.igw.id\n  }\n  tags = { Name = \"${var.env}-public-rt\" }\n}\n\nresource \"aws_route_table_association\" \"public_assoc\" {\n  count          = length(aws_subnet.public)\n  subnet_id      = aws_subnet.public[count.index].id\n  route_table_id = aws_route_table.public_rt.id\n}\n\nSecurity group for public services (security_groups.tf)\nresource \"aws_security_group\" \"public_sg\" {\n  name        = \"${var.env}-public-sg\"\n  description = \"Allow only HTTP/HTTPS from the Internet and health checks\"\n  vpc_id      = aws_vpc.main.id\n\n  ingress {\n    description = \"HTTP\"\n    from_port   = 80\n    to_port     = 80\n    protocol    = \"tcp\"\n    cidr_blocks = [\"0.0.0.0/0\"]\n  }\n  ingress {\n    description = \"HTTPS\"\n    from_port   = 443\n    to_port     = 443\n    protocol    = \"tcp\"\n    cidr_blocks = [\"0.0.0.0/0\"]\n  }\n  # Block SSH from Internet - enforce SSM or VPN\n  egress {\n    from_port   = 0\n    to_port     = 0\n    protocol    = \"-1\"\n    cidr_blocks = [\"0.0.0.0/0\"]\n  }\n  tags = { Name = \"${var.env}-public-sg\" }\n}\n\nVPC Flow Logs and auditing (flow_logs.tf)\nresource \"aws_cloudwatch_log_group\" \"vpc_flow\" {\n  name              = \"/aws/vpc/flowlogs/${var.env}\"\n  retention_in_days = 90\n}\n\nresource \"aws_flow_log\" \"vpc\" {\n  resource_id = aws_vpc.main.id\n  resource_type = \"VPC\"\n  traffic_type = \"ALL\"\n  log_destination = aws_cloudwatch_log_group.vpc_flow.arn\n  iam_role_arn = aws_iam_role.flow_logs_role.arn\n}\n\nPractical implementation notes for a small business\nStart small: create a single VPC and 2 public subnets across AZs for redundancy. Use Terraform modules in a private registry or version-controlled repo. Use variables for environment (dev/prod), cidr ranges, and classification tags (e.g., \"Controlled Unclassified Information\" or \"Non-sensitive\"). Use AWS Systems Manager to manage instances—this allows you to keep SSH off (no inbound 22) which is an important CMMC/NIST-aligned control to reduce attack surface.\n\nReal-world example scenario\nImagine a small contractor hosting a public-facing documentation portal that may contain non-sensitive government contract information. Deploy the portal in the public subnets with the public_sg allowing only 80/443. Keep backend databases in private subnets inaccessible from the Internet; ensure the application uses IAM roles to access secrets (AWS Secrets Manager) so no credentials are stored on instances. Enable VPC Flow Logs and CloudWatch alarms for spikes in traffic that might indicate scanning or DDoS attempts—document these configurations for audit evidence required by FAR and CMMC.\n\nCompliance tips, best practices, and evidence collection\nBest practices: (1) tag resources consistently for automated evidence gathering (e.g., env, owner, classification); (2) enforce infrastructure-as-code reviews (pull requests) and retain Terraform state securely (remote backend with encryption and access controls); (3) enable drift detection and periodic reconciling; (4) restrict management access to known IPs or use a VPN/SSM; (5) log everything—VPC Flow Logs, CloudTrail, and host-level logs—and ship to centralized, immutable storage (S3 with MFA delete where possible); (6) store runbooks showing how subnetworks are provisioned and how to prove segregation during an audit.\n\nRisks of not implementing this requirement\nWithout proper subnet separation and controls you increase the likelihood of data exposure, lateral movement after compromise, and inadvertent public access to sensitive systems. For contractors, failing to meet FAR 52.204-21 or CMMC Level 1 expectations risks contract disqualification, loss of award, regulatory penalties, and reputational damage. Operationally, you also face increased firefighting, higher incident response costs, and longer remediation timelines.\n\nIn summary, using Terraform to create dedicated, well-tagged public subnetworks combined with strict security groups, centralized logging, management without open SSH, and documented evidence provides a practical, auditable path to meet the relevant FAR 52.204-21 and CMMC 2.0 Level 1 controls—start with the provided templates, tailor CIDR and tagging to your environment, enforce code reviews, and automate logging and monitoring to reduce risk."
  },
  "metadata": {
    "description": "[Write a compelling 1-sentence SEO description about this compliance requirement]",
    "permalink": "/step-by-step-terraform-templates-to-create-compliant-subnetworks-for-public-services-far-52204-21-cmmc-20-level-1-control-scl1-b1xi.json",
    "categories": [],
    "tags": []
  }
}