# NCD policy evaluations ======================================================= # Controls : NCD-003, NCD-005, NCD-006, NCD-007, NCD-008, NCD-009 # # Co-emitted from cmp.rego: # NCD-001 → CMP-005 Unrestricted SSH Ingress # NCD-002 → CMP-006 Unrestricted RDP Ingress # NCD-004 → CMP-008 Default Security Group Rules package controls.aws.ncd import data.common.definitions as defs import data.common.exemptions as exemptions import data.common.network as network import data.common.outputs as outputs # Scope guard ------------------------------------------------------------------ _vpc_in_scope if { some _, rc in input.resource_changes rc.type == "aws_vpc" } # NCD-003 — Block Unrestricted Access to High-Risk Ports ---------------------- deny contains msg if { policy_id := "ICP-TF-AWS-NCD-003" some _, rc in input.resource_changes rc.type in {"aws_security_group", "aws_vpc_security_group_ingress_rule"} rc.change.actions[_] in ["create", "update"] some rule in network.ingress_rules(rc) network.unrestricted_cidr(rule) some port in defs.common_use_ports network.port_in_range(port, rule) meta := data.policies[policy_id] meta.status == "active" not exemptions.policy_exemption(policy_id) not exemptions.severity_exemption(meta.severity) msg := outputs.violation( policy_id, meta, sprintf("'%s.%s' permits unrestricted ingress to high-risk port %d", [rc.type, rc.name, port]), ) } # NCD-005 — Restrict NACL Ingress to Remote Administration Ports -------------- deny contains msg if { policy_id := "ICP-TF-AWS-NCD-005" some _, rc in input.resource_changes rc.type == "aws_network_acl_rule" rc.change.actions[_] in ["create", "update"] rc.change.after.egress == false rc.change.after.protocol == "tcp" rc.change.after.rule_action == "allow" rc.change.after.cidr_block == "0.0.0.0/0" some port in defs.management_ports network.port_in_range(port, rc.change.after) meta := data.policies[policy_id] meta.status == "active" not exemptions.policy_exemption(policy_id) not exemptions.severity_exemption(meta.severity) msg := outputs.violation( policy_id, meta, sprintf("NACL rule '%s' allows ingress from 0.0.0.0/0 to admin port %d", [rc.name, port]), ) } # NCD-006 — Require VPC Endpoints for AWS Service Traffic --------------------- deny contains msg if { policy_id := "ICP-TF-AWS-NCD-006" _vpc_in_scope some service in _required_endpoint_services not _endpoint_exists(service) meta := data.policies[policy_id] meta.status == "active" not exemptions.policy_exemption(policy_id) not exemptions.severity_exemption(meta.severity) msg := outputs.violation( policy_id, meta, sprintf("No aws_vpc_endpoint found for service '%s'", [service]), ) } _required_endpoint_services := { "s3", "dynamodb", "kms", "secretsmanager", } _endpoint_exists(service) if { some _, rc in input.resource_changes rc.type == "aws_vpc_endpoint" rc.change.actions[_] in ["create", "update"] contains(rc.change.after.service_name, service) } # NCD-007 — Application Load Balancer Must Redirect HTTP to HTTPS ------------- deny contains msg if { some policy_id in {"ICP-TF-AWS-NCD-007", "ICP-TF-AWS-GAC-020"} some _, rc in input.resource_changes rc.type == "aws_lb_listener" rc.change.actions[_] in ["create", "update"] rc.change.after.port == 80 not _redirects_to_https(rc.change.after) meta := data.policies[policy_id] meta.status == "active" not exemptions.policy_exemption(policy_id) not exemptions.severity_exemption(meta.severity) msg := outputs.violation( policy_id, meta, sprintf("ALB listener '%s' on port 80 does not redirect to HTTPS", [rc.name]), ) } _redirects_to_https(after) if { some action in after.default_action action.type == "redirect" some redirect in action.redirect redirect.protocol == "HTTPS" redirect.port == "443" } # NCD-008 — CloudFront Distributions Must Enforce HTTPS to Viewers ------------ deny contains msg if { some policy_id in {"ICP-TF-AWS-NCD-008", "ICP-TF-AWS-GAC-021"} some _, rc in input.resource_changes rc.type == "aws_cloudfront_distribution" rc.change.actions[_] in ["create", "update"] not _https_enforced(rc.change.after) meta := data.policies[policy_id] meta.status == "active" not exemptions.policy_exemption(policy_id) not exemptions.severity_exemption(meta.severity) msg := outputs.violation( policy_id, meta, sprintf("CloudFront distribution '%s' does not enforce HTTPS to viewers", [rc.name]), ) } _https_enforced(after) if { after.default_cache_behavior[_].viewer_protocol_policy in {"redirect-to-https", "https-only"} after.viewer_certificate[_].minimum_protocol_version in {"TLSv1.2_2021", "TLSv1.2_2022", "TLSv1.3_2022"} } # NCD-009 — Enable API Gateway REST Stage Execution Logging ------------------- deny contains msg if { policy_id := "ICP-TF-AWS-NCD-009" some _, rc in input.resource_changes rc.type == "aws_api_gateway_method_settings" rc.change.actions[_] in ["create", "update"] rc.change.after.method_path == "*/*" not _logging_enabled(rc.change.after) meta := data.policies[policy_id] meta.status == "active" not exemptions.policy_exemption(policy_id) not exemptions.severity_exemption(meta.severity) msg := outputs.violation( policy_id, meta, sprintf("API Gateway method settings '%s' does not enable execution logging", [rc.name]), ) } _logging_enabled(after) if { some setting in after.settings setting.logging_level in {"ERROR", "INFO"} }