diff --git a/assets/queries/terraform/aws/team_tag_not_present/metadata.json b/assets/queries/terraform/aws/team_tag_not_present/metadata.json new file mode 100644 index 000000000..e60e4811d --- /dev/null +++ b/assets/queries/terraform/aws/team_tag_not_present/metadata.json @@ -0,0 +1,12 @@ +{ + "id": "a2b3c4d5-e6f7-8901-gh23-ijkl456m7890", + "queryName": "Team Tag Missing", + "severity": "MEDIUM", + "category": "Best Practices", + "descriptionText": "Ensures that every cloud resource has a 'Team' tag for ownership tracking.", + "descriptionUrl": "https://your-cloud-policy-docs.com/enforce-team-tag", + "platform": "Terraform", + "descriptionID": "a2b3c4d5", + "cloudProvider": "aws", + "cwe": "200" +} diff --git a/assets/queries/terraform/aws/team_tag_not_present/query.rego b/assets/queries/terraform/aws/team_tag_not_present/query.rego new file mode 100644 index 000000000..156ad8f8c --- /dev/null +++ b/assets/queries/terraform/aws/team_tag_not_present/query.rego @@ -0,0 +1,56 @@ +package Cx + +import data.generic.common as common_lib +import data.generic.terraform as tf_lib + +# Required tags to be enforced across all Terraform resources +required_tags := {"Team"} + +# Case where "tags" exists but required tags are missing +CxPolicy[result] { + resource_type := input.document[i].resource[resource_name][name] + common_lib.valid_key(resource_type, "tags") + + tags := resource_type.tags + missing_labels := {tag | required_tags[tag]; not common_lib.valid_key(tags, tag)} + + count(missing_labels) > 0 + + result := { + "documentId": input.document[i].id, + "resourceType": resource_name, + "resourceName": tf_lib.get_specific_resource_name(resource_type, resource_name, name), + "searchKey": sprintf("%s[%s].tags", [resource_name, name]), + "issueType": "MissingValue", + "keyExpectedValue": sprintf("Every resource should have tags: %v", [required_tags]), + "keyActualValue": sprintf("Missing tags: %v", [missing_labels]), + "searchLine": common_lib.build_search_line(["resource", resource_name, name, "tags"], []), + "remediation": json.marshal({ + "before": sprintf("tags = {%v}", [tags]), + "after": sprintf("tags = {%v}", [tags | required_tags]) + }), + "remediationType": "addition" + } +} + +# Case where "tags" block is completely missing +CxPolicy[result] { + resource := input.document[i].resource[resource_type][name] + not common_lib.valid_key(resource, "tags") + + result := { + "documentId": input.document[i].id, + "resourceType": resource_type, + "resourceName": tf_lib.get_specific_resource_name(resource, resource_type, name), + "searchKey": sprintf("%s[%s].tags", [resource_type, name]), + "issueType": "MissingValue", + "keyExpectedValue": sprintf("Every resource should have a 'tags' block containing: %v", [required_tags]), + "keyActualValue": "'tags' block is missing", + "searchLine": common_lib.build_search_line(["resource", resource_type, name], []), + "remediation": json.marshal({ + "before": "No 'tags' block", + "after": sprintf("tags = %v", [required_tags]) + }), + "remediationType": "addition" + } +} diff --git a/assets/queries/terraform/aws/team_tag_not_present/test/negative0.tf b/assets/queries/terraform/aws/team_tag_not_present/test/negative0.tf new file mode 100644 index 000000000..0a3215111 --- /dev/null +++ b/assets/queries/terraform/aws/team_tag_not_present/test/negative0.tf @@ -0,0 +1,9 @@ +resource "aws_instance" "good_example" { + ami = "ami-123456" + instance_type = "t2.micro" + + tags = { + Team = "DevOps" # ✅ "Team" tag is present + Environment = "Production" + } +} diff --git a/assets/queries/terraform/aws/team_tag_not_present/test/negative1.tf b/assets/queries/terraform/aws/team_tag_not_present/test/negative1.tf new file mode 100644 index 000000000..457665355 --- /dev/null +++ b/assets/queries/terraform/aws/team_tag_not_present/test/negative1.tf @@ -0,0 +1,7 @@ +resource "aws_s3_bucket" "good_example" { + bucket = "my-bucket" + + tags = { + Team = "Security" # ✅ "Team" tag is present + } +} diff --git a/assets/queries/terraform/aws/team_tag_not_present/test/positive.tf b/assets/queries/terraform/aws/team_tag_not_present/test/positive.tf new file mode 100644 index 000000000..b4e12e7b2 --- /dev/null +++ b/assets/queries/terraform/aws/team_tag_not_present/test/positive.tf @@ -0,0 +1,14 @@ +resource "aws_instance" "bad_example" { + ami = "ami-123456" + instance_type = "t2.micro" + + tags = { + Environment = "Production" # ❌ Missing "Team" tag + } +} + +resource "aws_s3_bucket" "bad_example" { + bucket = "my-bucket" + + # ❌ No tags at all +} diff --git a/assets/queries/terraform/aws/team_tag_not_present/test/positive_expected_result.json b/assets/queries/terraform/aws/team_tag_not_present/test/positive_expected_result.json new file mode 100644 index 000000000..5c00a80cd --- /dev/null +++ b/assets/queries/terraform/aws/team_tag_not_present/test/positive_expected_result.json @@ -0,0 +1,12 @@ +[ + { + "queryName": "Team Tag Missing", + "severity": "MEDIUM", + "line": 5 + }, + { + "queryName": "Team Tag Missing", + "severity": "MEDIUM", + "line": 10 + } +]