Inspecteur Variables Terraform

Inspectez les définitions de variables Terraform, defaults et types

Terraform Variable Inspection and Analysis

Terraform variables define the input interface of a module — they are the parameters that consumers must provide (or may optionally override) when calling module "x" { ... }. A well-designed variable interface makes a module self-documenting: each variable has a clear type constraint, a meaningful description, sensible defaults for optional parameters, validation rules that reject invalid inputs early, and sensitivity markers that prevent secrets from leaking into logs or state output. However, as modules grow in complexity, the variable interface can become difficult to reason about. A module with 40+ variables, nested object types, and conditional defaults requires careful inspection to understand what inputs are actually required, what shapes they expect, and what guardrails exist.

A Terraform variable inspector parses variable blocks from HCL configuration files and extracts structured metadata: the variable name, its type constraint (from simple primitives like string and number to complex types like map(object({...}))), its default value (which determines whether the variable is required or optional), its description (critical for documentation and IDE support), any validation blocks with custom rules, and whether the variable is marked sensitive = true. This structured extraction enables module consumers to quickly understand how to configure a module, documentation generators to produce accurate input tables, and linting tools to detect missing descriptions, overly permissive any types, or required variables without clear documentation explaining what value to provide.

Variable Types and Type Constraints in Terraform

Terraform's type system for variables ranges from simple primitives to deeply nested structural types. Understanding the full type hierarchy is essential for inspecting module interfaces:

  • Primitive types: string, number, and bool represent scalar values. These are the simplest variable types and accept direct literal values. A variable declared as type = string will accept any string and reject numbers or booleans unless explicitly converted.
  • Collection types: list(type), set(type), and map(type) represent homogeneous collections where every element shares the same type. For example, list(string) accepts ["a", "b", "c"] but rejects ["a", 1, true]. Maps are particularly common for tagging patterns: type = map(string) for resource tags.
  • Structural types: object({...}) and tuple([...]) define exact shapes with per-attribute types. Objects are the most powerful type constraint — object({ name = string, port = number, enabled = bool }) enforces that callers provide exactly those attributes with those types. Optional attributes use optional(type, default) in Terraform 1.3+.
  • The any type: Disables type checking entirely. While sometimes necessary for pass-through values, overuse of any weakens the module interface by deferring type errors to apply-time rather than catching them at plan-time. An inspector flags any usage as a potential code smell requiring justification.
  • Nested complex types: Real-world modules often use deeply nested types like map(object({ rules = list(object({ port = number, cidr = string })) })). These complex types are hard to read inline in HCL — an inspector presents them in a structured, navigable format that makes the expected shape immediately clear.

Required vs Optional Variables and Default Values

The presence or absence of a default argument in a variable block is what determines whether a variable is required or optional. This distinction is fundamental to understanding a module's input contract:

  • Required variables (no default): A variable without a default value must be explicitly provided by the caller. If omitted, Terraform will prompt interactively (in CLI mode) or fail with an error (in automation). Required variables represent the minimum configuration a module needs to function — the essential parameters without which the module cannot provision infrastructure.
  • Optional variables (with default): Variables with a default value can be omitted by callers, in which case the default is used. Defaults should represent the most common or safest configuration. For example, default = true for an encryption flag ensures encryption is enabled unless explicitly disabled — a secure-by-default pattern.
  • Nullable variables: Since Terraform 1.1, variables can be declared with nullable = false to reject null as a value even when a default exists. This prevents callers from accidentally nullifying a variable that has a meaningful default. An inspector surfaces this attribute to clarify whether null is a valid input.
  • Empty defaults as sentinels: Some modules use default = "" or default = null as sentinels, with conditional logic inside the module that behaves differently based on whether the variable was explicitly set. An inspector detecting empty or null defaults alongside complex conditional usage can flag these as potentially confusing interface patterns that deserve documentation.

A variable inspector categorizes every variable as required or optional, groups them accordingly, and highlights cases where the default value may be surprising (empty strings, null, empty lists) or where a required variable lacks a description explaining what value to provide.

Validation Rules and Input Constraints

Terraform validation blocks define custom rules that inputs must satisfy beyond their type constraint. These rules catch invalid values at terraform plan time rather than at apply-time (or worse, creating broken infrastructure that fails silently):

  • Condition expressions: Each validation block has a condition that must evaluate to true for the input to be accepted. Conditions can use any Terraform expression — length(), regex(), can(), contains(), numeric comparisons, and more. For example, condition = length(var.name) >= 3 && length(var.name) <= 63 enforces name length bounds.
  • Error messages: The error_message string explains what the caller did wrong when the condition fails. Good error messages are specific and actionable: "Environment must be one of: dev, staging, prod" is far more helpful than "Invalid value". An inspector extracts and displays these messages to document the allowed value space.
  • Multiple validation blocks: A single variable can have multiple validation blocks, each checking a different constraint. For instance, a CIDR variable might have one validation for format (can(cidrhost(var.cidr, 0))) and another for prefix length (tonumber(split("/", var.cidr)[1]) >= 16). An inspector lists all validations to give a complete picture of the accepted input space.
  • Pattern-based validation: The regex() function is commonly used for validating naming conventions, DNS labels, ARN formats, and other structured strings. For example, condition = can(regex("^[a-z][a-z0-9-]{1,61}[a-z0-9]$", var.bucket_name)) enforces S3 bucket naming rules. An inspector recognizes regex patterns and can display the allowed format clearly.

By extracting all validation rules, an inspector enables module consumers to understand what values are accepted without reading module source code — the validation rules, combined with type constraints and error messages, fully document the allowed input space.

Sensitive Variables and Security Considerations

Variables marked with sensitive = true receive special treatment throughout the Terraform workflow. Understanding which variables are sensitive is critical for security reviews and compliance:

  • Output suppression: Sensitive variable values are redacted from CLI output, plan diffs, and terraform output displays. Instead of showing the actual value, Terraform displays (sensitive value). This prevents accidental exposure in CI/CD logs, terminal recordings, and shared plan outputs.
  • State file exposure: Despite output suppression, sensitive values are still stored in plaintext in the Terraform state file. The sensitive marker is a UI protection, not an encryption mechanism. An inspector that identifies sensitive variables can recommend additional controls: encrypted state backends, restricted state access policies, and secrets management integration (Vault, AWS Secrets Manager).
  • Common sensitive variables: Database passwords, API keys, TLS private keys, OAuth client secrets, and encryption keys should always be marked sensitive. An inspector can flag variables with names matching patterns like *_password, *_secret, *_key, or *_token that are NOT marked sensitive — a potential security oversight.
  • Propagation rules: When a sensitive variable is used in a resource attribute, the entire resource attribute becomes sensitive in plan output. If passed to an output value, that output must also be marked sensitive = true or Terraform will error. An inspector traces sensitivity propagation to identify where sensitive data flows through the module.

Code Examples

Terraform Variable Definitions with Types, Defaults, Validations, and Sensitivity

# Required variable — no default, must be provided by caller
variable "environment" {
  type        = string
  description = "Deployment environment (dev, staging, prod)"

  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Environment must be one of: dev, staging, prod."
  }
}

# Optional variable with sensible default
variable "instance_type" {
  type        = string
  description = "EC2 instance type for the application servers"
  default     = "t3.medium"

  validation {
    condition     = can(regex("^[a-z][a-z0-9]*\\.[a-z0-9]+$", var.instance_type))
    error_message = "Instance type must be a valid AWS format (e.g., t3.medium, m5.xlarge)."
  }
}

# Complex object type with nested structure
variable "vpc_config" {
  type = object({
    cidr_block         = string
    availability_zones = list(string)
    private_subnets    = list(string)
    public_subnets     = list(string)
    enable_nat_gateway = optional(bool, true)
    single_nat_gateway = optional(bool, false)
  })
  description = "VPC network configuration including CIDR, subnets, and NAT settings"

  validation {
    condition     = can(cidrhost(var.vpc_config.cidr_block, 0))
    error_message = "vpc_config.cidr_block must be a valid CIDR notation (e.g., 10.0.0.0/16)."
  }

  validation {
    condition     = length(var.vpc_config.availability_zones) >= 2
    error_message = "At least 2 availability zones are required for high availability."
  }
}

# Sensitive variable — value redacted from CLI output
variable "database_password" {
  type        = string
  description = "Master password for the RDS PostgreSQL instance"
  sensitive   = true

  validation {
    condition     = length(var.database_password) >= 16
    error_message = "Database password must be at least 16 characters for security compliance."
  }

  validation {
    condition     = can(regex("[A-Z]", var.database_password)) && can(regex("[0-9]", var.database_password))
    error_message = "Database password must contain at least one uppercase letter and one digit."
  }
}

# Map type for flexible tagging
variable "tags" {
  type        = map(string)
  description = "Resource tags applied to all provisioned infrastructure"
  default     = {}

  validation {
    condition     = alltrue([for k, v in var.tags : length(k) <= 128 && length(v) <= 256])
    error_message = "Tag keys must be ≤128 chars and values ≤256 chars (AWS limits)."
  }
}

# Variable with nullable = false (Terraform 1.1+)
variable "log_retention_days" {
  type        = number
  description = "CloudWatch log retention period in days"
  default     = 30
  nullable    = false

  validation {
    condition     = contains([1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365], var.log_retention_days)
    error_message = "Log retention must be a valid CloudWatch retention value."
  }
}

Standards & Specifications

Questions Fréquentes

What does the Terraform Variable Inspector check?

The inspector analyzes each variable block in your Terraform HCL code, reporting the name, type constraint, default value, description, sensitive flag, and any validation rules. It also detects common issues like missing types, missing descriptions, overly permissive 'any' types, and variables that likely hold secrets but lack the sensitive flag.

Why should I add type constraints to variables?

Type constraints (e.g., type = string, type = number, type = list(string)) allow Terraform to validate input values before applying changes. Without a type, any value is accepted, which can lead to confusing runtime errors. Explicit types catch mistakes early during terraform plan.

What does the sensitive flag do in Terraform?

When sensitive = true is set on a variable, Terraform redacts its value from CLI output, plan output, and logs. This prevents accidental exposure of passwords, tokens, and API keys. The inspector warns when a variable name suggests it contains secrets but lacks this flag.

Is my Terraform code sent to any server?

No. All parsing and analysis happens entirely in your browser using JavaScript. Your Terraform code — which may contain variable names, default values, and infrastructure details — never leaves your device. No data is stored, logged, or transmitted.

What Terraform variable attributes are detected?

The inspector recognizes all standard variable attributes: type (type constraint), default (default value), description (documentation string), sensitive (redaction flag), and validation blocks (with condition and error_message). Nullable and ephemeral attributes are also parsed if present.

Why does the inspector warn about type 'any'?

Using type = any disables Terraform's type checking for that variable. While occasionally necessary for generic modules, it prevents early error detection and makes code harder to understand. The inspector flags it as a warning so you can evaluate whether a more specific type would be appropriate.

Can I inspect variables from multiple .tf files?

The inspector processes one input at a time. For multi-file configurations, paste the contents of each file separately or concatenate them. The HCL parser handles multiple variable blocks in a single input without issues.

What is the maximum input size supported?

The inspector accepts Terraform files up to 2MB. Files between 200KB and 2MB will show a warning that processing may be slow. For typical Terraform configurations under 200KB, analysis is instant.