variables.tf
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
variable "vpc_id" {
  description = "ID of the VPC in which to create security groups"
  type        = string
}

variable "name_prefix" {
  description = "Prefix prepended to every security group name created by this module"
  type        = string

  validation {
    condition     = length(trimspace(var.name_prefix)) > 0
    error_message = "name_prefix must not be empty."
  }
}

variable "security_groups" {
  description = "Map of security group definitions"
  type = map(object({
    name_suffix = string
    description = string
    ingress_rules = optional(list(object({
      description      = optional(string, "")
      protocol         = string
      from_port        = number
      to_port          = number
      ipv4_cidr_blocks = optional(list(string), [])
      ipv6_cidr_blocks = optional(list(string), [])
      source_sg_key    = optional(string, null)
      source_sg_id     = optional(string, null)
      self             = optional(bool, false)
    })), [])
    egress_rules = optional(list(object({
      description      = optional(string, "")
      protocol         = string
      from_port        = number
      to_port          = number
      ipv4_cidr_blocks = optional(list(string), [])
      ipv6_cidr_blocks = optional(list(string), [])
      source_sg_key    = optional(string, null)
      source_sg_id     = optional(string, null)
      self             = optional(bool, false)
    })), [])
  }))
  default = {}

  validation {
    condition = alltrue([
      for sg_key, sg in var.security_groups :
      length(sg.ingress_rules) > 0 || length(sg.egress_rules) > 0
    ])
    error_message = <<-EOT
      One or more security groups have no ingress or egress rules.

      Each security group must define at least one rule in either
      ingress_rules or egress_rules. A security group with neither
      does not allow any traffic movement. Fix by either removing
      the empty security group from security_groups, or adding at
      least one rule to it.
    EOT
  }

  validation {
    condition = alltrue(flatten([
      for sg_key, sg in var.security_groups : [
        for rule in concat(sg.ingress_rules, sg.egress_rules) :
        length(rule.ipv4_cidr_blocks) > 0
        || length(rule.ipv6_cidr_blocks) > 0
        || rule.source_sg_key != null
        || rule.source_sg_id != null
        || rule.self
      ]
    ]))
    error_message = <<-EOT
      One or more rules have no source configured.

      Every ingress or egress rule must set at least one of:
      ipv4_cidr_blocks, ipv6_cidr_blocks, source_sg_key, source_sg_id,
      or self = true. A rule with none of these produces no AWS
      resource at all, which is almost always a mistake.
    EOT
  }

  validation {
    condition = alltrue(flatten([
      for sg_key, sg in var.security_groups : [
        for rule in concat(sg.ingress_rules, sg.egress_rules) :
        rule.source_sg_id == null || can(regex("^sg-[a-z0-9]+$", rule.source_sg_id))
      ]
    ]))
    error_message = <<-EOT
      One or more source_sg_id values are not a valid format. It must 
      be a security group ID (e.g. "sg-0123abcd").
    EOT
  }

  validation {
    condition = alltrue(flatten([
      for sg_key, sg in var.security_groups : [
        for rule in concat(sg.ingress_rules, sg.egress_rules) :
        rule.source_sg_key == null || contains(keys(var.security_groups), rule.source_sg_key)
      ]
    ]))
    error_message = <<-EOT
      One or more source_sg_key values reference a security group
      that is not defined in the security_groups map. It must match one of
      the keys in the security_groups map.
    EOT
  }
}

variable "tags" {
  description = "Resource tags to apply to all resources"
  type        = map(string)
  default     = {}
}