# DAT policy evaluations ======================================================= # Controls: DAT-001 through DAT-009 package controls.aws.dat import data.common.exemptions as exemptions import data.common.outputs as outputs # DAT-001 — RDS DB Instances Must Not Be Publicly Accessible ------------------ deny contains msg if { some policy_id in {"ICP-TF-AWS-DAT-001", "ICP-TF-AWS-GAC-010"} some _, rc in input.resource_changes rc.type in {"aws_db_instance", "aws_rds_cluster_instance"} rc.change.actions[_] in ["create", "update"] rc.change.after.publicly_accessible == true 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' is publicly accessible", [rc.type, rc.name]), ) } # DAT-002 — Enable RDS Storage Encryption At Rest ----------------------------- deny contains msg if { some policy_id in {"ICP-TF-AWS-DAT-002", "ICP-TF-AWS-GAC-009"} some _, rc in input.resource_changes rc.type in {"aws_db_instance", "aws_rds_cluster"} rc.change.actions[_] in ["create", "update"] rc.change.after.storage_encrypted != true 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' does not have storage encryption enabled", [rc.type, rc.name]), ) } # DAT-003 — Publish RDS Engine Logs to CloudWatch ----------------------------- deny contains msg if { policy_id := "ICP-TF-AWS-DAT-003" some _, rc in input.resource_changes rc.type in {"aws_db_instance", "aws_rds_cluster"} rc.change.actions[_] in ["create", "update"] not _has_log_exports(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("'%s.%s' has no CloudWatch log exports configured", [rc.type, rc.name]), ) } _has_log_exports(after) if { count(after.enabled_cloudwatch_logs_exports) > 0 } # DAT-004 — Enable RDS Deletion Protection ------------------------------------ deny contains msg if { some policy_id in {"ICP-TF-AWS-DAT-004", "ICP-TF-AWS-GAC-011"} some _, rc in input.resource_changes rc.type in {"aws_db_instance", "aws_rds_cluster"} rc.change.actions[_] in ["create", "update"] rc.change.after.deletion_protection != true 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' does not have deletion protection enabled", [rc.type, rc.name]), ) } # DAT-005 — Enable RDS Automatic Minor Version Upgrades ----------------------- deny contains msg if { policy_id := "ICP-TF-AWS-DAT-005" some _, rc in input.resource_changes rc.type == "aws_db_instance" rc.change.actions[_] in ["create", "update"] rc.change.after.auto_minor_version_upgrade != true 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("RDS instance '%s' does not have auto minor version upgrade enabled", [rc.name]), ) } # DAT-006 — Enable DynamoDB Point-in-Time Recovery ---------------------------- deny contains msg if { some policy_id in {"ICP-TF-AWS-DAT-006", "ICP-TF-AWS-GAC-024"} some _, rc in input.resource_changes rc.type == "aws_dynamodb_table" rc.change.actions[_] in ["create", "update"] not _pitr_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("DynamoDB table '%s' does not have point-in-time recovery enabled", [rc.name]), ) } _pitr_enabled(after) if { some pitr in after.point_in_time_recovery pitr.enabled == true } # DAT-007 — Redshift Clusters Must Not Be Publicly Accessible ----------------- deny contains msg if { policy_id := "ICP-TF-AWS-DAT-007" some _, rc in input.resource_changes rc.type == "aws_redshift_cluster" rc.change.actions[_] in ["create", "update"] rc.change.after.publicly_accessible == true 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("Redshift cluster '%s' is publicly accessible", [rc.name]), ) } # DAT-008 — Enable Redshift Audit Logging ------------------------------------- deny contains msg if { policy_id := "ICP-TF-AWS-DAT-008" some _, rc in input.resource_changes rc.type == "aws_redshift_cluster" rc.change.actions[_] in ["create", "update"] not _redshift_logging_enabled(rc) 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("Redshift cluster '%s' does not have audit logging enabled", [rc.name]), ) } _redshift_logging_enabled(rc) if { some _, other in input.resource_changes other.type == "aws_redshift_logging" other.change.actions[_] in ["create", "update"] other.change.after.cluster_identifier == rc.change.after.cluster_identifier } # DAT-009 — Enforce ElastiCache Redis Encryption in Transit and At Rest ------- deny contains msg if { policy_id := "ICP-TF-AWS-DAT-009" some _, rc in input.resource_changes rc.type == "aws_elasticache_replication_group" rc.change.actions[_] in ["create", "update"] not _elasticache_encrypted(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("ElastiCache replication group '%s' does not enforce encryption in transit and at rest", [rc.name]), ) } _elasticache_encrypted(after) if { after.transit_encryption_enabled == true _truthy(after.at_rest_encryption_enabled) } _truthy(v) if v == true _truthy(v) if v == "true"