For AI agents: A markdown version of this page is available at https://docs.datadoghq.com/security/code_security/iac_security/iac_rules/terraform-aws-security-group-without-description.md. A documentation index is available at /llms.txt.
This product is not supported for your selected Datadog site. ().

Metadata

Id: terraform-aws-security-group-without-description

Provider: AWS

Platform: Terraform

Severity: Low

Category: Best Practices

Learn More

Description

It is a best practice for AWS security groups to include a meaningful description attribute in their Terraform configuration, such as in the following example:

description = "Allow TLS inbound traffic"

Omitting the description field, as shown below, can lead to confusion and hinder effective management or auditing of security groups, especially in environments with many resources:

resource "aws_security_group" "allow_tls" {
  name   = "allow_tls"
  vpc_id = aws_vpc.main.id
  // missing description
  ...
}

Without clear descriptions, security teams may struggle to quickly identify the purpose of a group, increasing the risk of misconfigurations and delayed incident response.

Compliant Code Examples

resource "aws_security_group" "allow_tls" {
  name        = "allow_tls"
  description = "Allow TLS inbound traffic"
  vpc_id      = aws_vpc.main.id

  ingress {
    description      = "TLS from VPC"
    from_port        = 443
    to_port          = 443
    protocol         = "tcp"
    cidr_blocks      = [aws_vpc.main.cidr_block]
    ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block]
  }

  tags = {
    Name = "allow_tls"
  }
}
resource "aws_security_group" "allow_tls" {
  name        = "allow_tls"
  description = "Managed by Terraform"
  vpc_id      = aws_vpc.main.id

  ingress {
    description      = "TLS from VPC"
    from_port        = 443
    to_port          = 443
    protocol         = "tcp"
    cidr_blocks      = [aws_vpc.main.cidr_block]
    ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block]
  }

  tags = {
    Name = "allow_tls"
  }
}

Non-Compliant Code Examples

# Note for positive2.json, the plan-JSON sibling exercising this same
# omitted-description scenario: see the plan-JSON variant DatadogPolicy
# body in query.rego for how it's resolved via
# configuration.root_module.resources[].expressions.
resource "aws_security_group" "allow_tls" {
  name        = "allow_tls"
  vpc_id      = aws_vpc.main.id

  ingress {
    description      = "TLS from VPC"
    from_port        = 443
    to_port          = 443
    protocol         = "tcp"
    cidr_blocks      = [aws_vpc.main.cidr_block]
    ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block]
  }

  tags = {
    Name = "allow_tls"
  }
}
# A count-indexed security group with no description declared. See
# test/positive3.json for the plan-JSON equivalent: doc.resource.aws_security_group's
# flattened key is "allow_tls[0]" (index included), not the bare
# "allow_tls" that configuration.root_module.resources[].name would give -
# the plan-JSON DatadogPolicy body in query.rego resolves this by
# reading _dd_tfplan_meta.aws_security_group[name] instead, which is
# keyed identically to doc.resource.
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_security_group" "allow_tls" {
  count  = 1
  name   = "allow-tls-${count.index}"
  vpc_id = aws_vpc.main.id
}
# given:
#  - a security group with description explicitly set to null
# when:
#  - the AWS provider fills in its own schema default ("Managed by
#    Terraform") since no real description was ever configured
# then:
#  - still flag it, the same as if description had been omitted entirely
#
# description = null keeps a real entry under configuration_expressions
# (constant_value: null), not an absent key - a bare presence check alone
# would treat this as "a description was configured" and wrongly stay
# silent. See test/negative2.tf for the case that must correctly stay
# silent (description explicitly set to the non-null default string).
resource "aws_security_group" "allow_tls" {
  name        = "allow_tls"
  description = null
  vpc_id      = aws_vpc.main.id

  ingress {
    description      = "TLS from VPC"
    from_port        = 443
    to_port          = 443
    protocol         = "tcp"
    cidr_blocks      = [aws_vpc.main.cidr_block]
    ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block]
  }

  tags = {
    Name = "allow_tls"
  }
}