HashiCorp Terraform Associate (004) Question 110
Single answer4d Understand and use complex typesA platform team wants to standardize how application teams define firewall rules in a reusable Terraform module. Each rule must include a port number and protocol, and may optionally include a list of CIDR blocks. The team wants Terraform to validate the structure of the input before planning resources. Which variable definition best meets this requirement while correctly using Terraform complex types?
- A
variable "firewall_rules" { type = list(object({ port = number protocol = string cidr_blocks = optional(list(string)) })) }
- B
variable "firewall_rules" { type = map(string) }
- C
variable "firewall_rules" { type = object({ port = number protocol = string cidr_blocks = list(string) }) }
- D
variable "firewall_rules" { type = list(tuple([number, string, list(string)])) }
Show answer and explanation
Correct answer: A
Explanation
Terraform complex types are designed to validate structured input data at the variable boundary. In this scenario, the module needs a collection of firewall rule definitions, so list(object(...)) is the best fit. Using object attributes gives each field a clear name, improving readability and reducing input mistakes. Terraform's optional(...) modifier for object attributes allows certain fields to be omitted while preserving type validation when present. By contrast, map(string) is too loose, object({...}) models only one rule instead of many, and tuple(...) relies on positional values rather than meaningful attribute names. This aligns with Terraform language guidance on type constraints, especially collection types such as list and structural types such as object.
- A. Correct.
Correct. This definition uses a list of objects, which is appropriate when the module expects multiple firewall rule entries with named attributes. The object type enforces that each rule has a numeric port and string protocol, and optional(list(string)) allows cidr_blocks to be omitted while still validating its type when provided. This is the most practical and maintainable choice for real-world module inputs.
- B. Incorrect.
Incorrect. map(string) only validates that the input is a map whose values are strings. It cannot enforce a nested structure with required attributes like port and protocol, and it cannot represent port as a number or cidr_blocks as a list of strings. A candidate might choose this if they confuse flexible maps with structured validation.
- C. Incorrect.
Incorrect. object({...}) defines a single object, not multiple rule objects. This would work only if the module accepted exactly one firewall rule. In the scenario, the team needs a collection of rules, so wrapping the object in a list or map is necessary. Also, cidr_blocks is required here, but the scenario says it should be optional.
- D. Incorrect.
Incorrect. tuple([number, string, list(string)]) can represent ordered values of fixed positions and types, but it is not a good fit for named fields like port, protocol, and cidr_blocks. Tuples are harder to read and maintain because callers must remember positional meaning. It also makes cidr_blocks required rather than optional.