Skip to content

Latest commit

Β 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

☁️ Azure Automation Variable (Int) Terraform Module

Creates an Azure Automation integer variable β€” a typed asset that runbooks read and write as shared state β€” for hashicorp/azurerm ~> 4.0.

Terraform azurerm Module Type Resources

🧩 Overview

  • Creates an azurerm_automation_variable_int (the keystone this) β€” an integer variable asset inside an existing Automation account.
  • Stores a whole-number value that runbooks read and write, so a job can persist a counter, a threshold, or a last-processed marker between runs.
  • Supports encryption at rest through a single boolean: set encrypted = true and the value is wrapped sensitive and never returned by the API on read.
  • Accepts an optional description, emits the variable id and name, and handles no secret output.

πŸ’‘ Why it matters: Automation variables are the durable memory of unattended runbooks. Defining an integer variable as its own typed module makes the value a plan-time number β€” a string typo becomes a type error instead of a runbook that silently reads back the wrong shape β€” and keeps the encrypt-at-rest decision to one explicit flag.

❀️ Support this project

If this module saves you time:

πŸ—ΊοΈ Where this fits in the family

flowchart LR
  aa["terraform-azurerm-automation-account"]
  me["terraform-azurerm-automation-variable-int"]
  v["azurerm_automation_variable_int"]
  s1["terraform-azurerm-automation-variable-bool"]
  s2["terraform-azurerm-automation-variable-datetime"]
  s3["terraform-azurerm-automation-variable-object"]
  s4["terraform-azurerm-automation-variable-string"]
  rb["runbooks read/write the variable"]
  aa -->|"automation_account_name"| me
  aa -->|"also parents"| s1
  aa -->|"also parents"| s2
  aa -->|"also parents"| s3
  aa -->|"also parents"| s4
  me -->|"creates"| v
  v -.->|"shared state"| rb
  classDef me fill:#0078D4,stroke:#004578,color:#ffffff;
  classDef target fill:#004578,stroke:#002d4d,color:#ffffff;
  classDef ext fill:#f2f2f2,stroke:#c8c8c8,color:#111111;
  class me me;
  class v target;
  class aa,s1,s2,s3,s4,rb ext;
Loading

🧬 What this module builds

flowchart TB
  in["name + automation_account_name + value(int) + encrypted"]
  this["azurerm_automation_variable_int.this"]
  out["Outputs: id, name"]
  in --> this
  this --> out
  classDef target fill:#004578,stroke:#002d4d,color:#ffffff;
  classDef ext fill:#f2f2f2,stroke:#c8c8c8,color:#111111;
  class this target;
  class in,out ext;
Loading

Resource inventory

Resource Role Cardinality
azurerm_automation_variable_int keystone this single

βœ… Provider / Versions

Requirement Value
Terraform >= 1.12.0
azurerm provider ~> 4.0
Provider block None β€” the caller configures provider "azurerm" { features {} }, auth, and subscription

Schema notes that bite (verified against the live schema):

  • Three fields are force-new. name, resource_group_name, and automation_account_name are immutable β€” changing any of them replaces the variable. value, encrypted, and description all update in place.
  • value is a number, not a string. The provider stores it as an integer; passing a fractional or string-shaped value is a type error at plan time. Leave it null to create the variable with no value set.
  • encrypted changes read behavior. It defaults to false. When set to true, the module wraps the value sensitive so it never surfaces in plan output, and Azure does not return the value on read β€” Terraform tracks it from configuration rather than from the API.
  • No tags. The resource type does not support tags, so the module omits the variable β€” the universal tail is timeouts only.

πŸ”‘ Required Azure RBAC Roles / Permissions

  • Automation Contributor (or equivalent) on the parent Automation account.

Azure Prerequisites

  • An existing Automation account to hold the variable.
  • The caller configures the provider "azurerm" { features {} } block, authentication, and subscription β€” this module declares none of them.

πŸ“ Module Structure

terraform-azurerm-automation-variable-int/
β”œβ”€β”€ providers.tf   # required_version + azurerm ~> 4.0 pin; no provider block
β”œβ”€β”€ variables.tf   # keystone inputs, value/encrypted/description, timeouts (no tags)
β”œβ”€β”€ main.tf        # azurerm_automation_variable_int.this
β”œβ”€β”€ outputs.tf     # id first, then name
β”œβ”€β”€ README.md      # this document
β”œβ”€β”€ SCOPE.md       # cross-module contract
β”œβ”€β”€ LICENSE        # MIT
└── .gitignore

βš™οΈ Quick Start

The smallest real call creates an integer variable in an existing Automation account:

module "retry_limit" {
  source                  = "git::https://github.com/microsoftexpert/terraform-azurerm-automation-variable-int.git?ref=v1.0.0"
  name                    = "MaxRetries"
  resource_group_name     = "rg-automation-eastus"
  automation_account_name = "aa-contoso"
  value                   = 5
}

ℹ️ The caller configures provider "azurerm" { features {} }, authentication, and the subscription β€” this module declares none of them. The Automation account must already exist.

πŸ”Œ Cross-Module Contract

Consumes

Input Type Source module
resource_group_name string terraform-azurerm-resource-group (name)
automation_account_name string terraform-azurerm-automation-account (name)

Emits

Output Description
id Variable Resource ID (first)
name Variable name β€” the key a runbook uses with Get-AutomationVariable

πŸ“š Example Library

1 Β· A simple integer value
module "batch_size" {
  source                  = "git::https://github.com/microsoftexpert/terraform-azurerm-automation-variable-int.git?ref=v1.0.0"
  name                    = "BatchSize"
  resource_group_name     = "rg-automation-eastus"
  automation_account_name = "aa-contoso"
  value                   = 42
}

πŸ’‘ value is a number, so 42 is stored as an integer β€” no quoting, no casting inside the runbook.

2 Β· Zero as a valid value
module "failure_count" {
  source                  = "git::https://github.com/microsoftexpert/terraform-azurerm-automation-variable-int.git?ref=v1.0.0"
  name                    = "ConsecutiveFailures"
  resource_group_name     = "rg-automation-eastus"
  automation_account_name = "aa-contoso"
  value                   = 0
}

ℹ️ 0 is a real value, distinct from null. Use it to seed a counter that a runbook increments from a known baseline.

3 Β· No value (null)
module "last_processed_id" {
  source                  = "git::https://github.com/microsoftexpert/terraform-azurerm-automation-variable-int.git?ref=v1.0.0"
  name                    = "LastProcessedId"
  resource_group_name     = "rg-automation-eastus"
  automation_account_name = "aa-contoso"
  # value omitted β€” the variable exists but holds no value until a runbook sets it
}

πŸ’‘ Omit value (it defaults to null) to declare the variable and let a runbook populate it at runtime with Set-AutomationVariable.

4 Β· Encrypted at rest
module "throttle_seed" {
  source                  = "git::https://github.com/microsoftexpert/terraform-azurerm-automation-variable-int.git?ref=v1.0.0"
  name                    = "ThrottleSeed"
  resource_group_name     = "rg-automation-eastus"
  automation_account_name = "aa-contoso"
  value                   = 9000
  encrypted               = true
}

πŸ”’ With encrypted = true the value is wrapped sensitive and Azure does not return it on read. Terraform tracks the value from configuration, so keep the module the source of truth.

5 Β· With a description
module "page_size" {
  source                  = "git::https://github.com/microsoftexpert/terraform-azurerm-automation-variable-int.git?ref=v1.0.0"
  name                    = "PageSize"
  resource_group_name     = "rg-automation-eastus"
  automation_account_name = "aa-contoso"
  value                   = 100
  description             = "Number of records fetched per API page by the sync runbook"
}

ℹ️ description updates in place, so you can document a variable's purpose without replacing it.

6 Β· A negative value
module "temperature_floor" {
  source                  = "git::https://github.com/microsoftexpert/terraform-azurerm-automation-variable-int.git?ref=v1.0.0"
  name                    = "TemperatureFloor"
  resource_group_name     = "rg-automation-eastus"
  automation_account_name = "aa-contoso"
  value                   = -20
}

πŸ’‘ Integer variables accept negative values β€” useful for thresholds, offsets, or bounds that dip below zero.

7 Β· A retry counter referenced by a runbook
module "max_retries" {
  source                  = "git::https://github.com/microsoftexpert/terraform-azurerm-automation-variable-int.git?ref=v1.0.0"
  name                    = "MaxRetries"
  resource_group_name     = "rg-automation-eastus"
  automation_account_name = "aa-contoso"
  value                   = 3
  description             = "Upper bound on retry attempts for the reconciliation runbook"
}

A PowerShell runbook reads and updates it as shared state:

$max = Get-AutomationVariable -Name 'MaxRetries'
for ($i = 0; $i -lt $max; $i++) { <# attempt #> }
Set-AutomationVariable -Name 'ConsecutiveFailures' -Value ($current + 1)

πŸ’‘ The module's name output is exactly the key the runbook passes to Get-AutomationVariable. Reference it so a rename propagates instead of drifting.

8 Β· Many variables at once (for_each)
locals {
  counters = {
    MaxRetries          = 3
    BatchSize           = 500
    ConsecutiveFailures = 0
    PageSize            = 100
  }
}

module "counter" {
  source                  = "git::https://github.com/microsoftexpert/terraform-azurerm-automation-variable-int.git?ref=v1.0.0"
  for_each                = local.counters
  name                    = each.key
  resource_group_name     = "rg-automation-eastus"
  automation_account_name = "aa-contoso"
  value                   = each.value
}

πŸ’‘ A keyed for_each at the module level keeps each variable stable when you add or remove one β€” no re-indexing.

9 Β· Encrypted, from a map (for_each)
locals {
  secrets = {
    SigningRotationDays = { value = 30, encrypted = true }
    TokenTtlMinutes     = { value = 60, encrypted = true }
  }
}

module "secure_counter" {
  source                  = "git::https://github.com/microsoftexpert/terraform-azurerm-automation-variable-int.git?ref=v1.0.0"
  for_each                = local.secrets
  name                    = each.key
  resource_group_name     = "rg-automation-eastus"
  automation_account_name = "aa-contoso"
  value                   = each.value.value
  encrypted               = each.value.encrypted
}

πŸ”’ Each entry is wrapped sensitive because encrypted = true, so no value appears in plan output.

10 Β· A version stamp
module "config_version" {
  source                  = "git::https://github.com/microsoftexpert/terraform-azurerm-automation-variable-int.git?ref=v1.0.0"
  name                    = "ConfigVersion"
  resource_group_name     = "rg-automation-eastus"
  automation_account_name = "aa-contoso"
  value                   = 7
  description             = "Bumped whenever the runbook config schema changes"
}

πŸ’‘ An integer version stamp lets a runbook detect a config change with a single equality check.

11 Β· Custom timeouts
module "slow_region_counter" {
  source                  = "git::https://github.com/microsoftexpert/terraform-azurerm-automation-variable-int.git?ref=v1.0.0"
  name                    = "RegionCounter"
  resource_group_name     = "rg-automation-eastus"
  automation_account_name = "aa-contoso"
  value                   = 1
  timeouts = {
    create = "30m"
    delete = "30m"
  }
}

ℹ️ timeouts is the module's only universal-tail input β€” this resource type carries no tags.

12 Β· Renaming means replacement
# Changing name (or resource_group_name / automation_account_name) destroys and
# recreates the variable β€” these three fields are force-new.
module "counter" {
  source                  = "git::https://github.com/microsoftexpert/terraform-azurerm-automation-variable-int.git?ref=v1.0.0"
  name                    = "RetryBudgetV2" # was "RetryBudget" β€” this is a replace, not an update
  resource_group_name     = "rg-automation-eastus"
  automation_account_name = "aa-contoso"
  value                   = 10
}

⚠️ To retune a variable in place, change value, encrypted, or description β€” not the identity fields. Renaming loses any value a runbook wrote at runtime.

13 Β· πŸ—οΈ End-to-end composition

Stand up a resource group, an Automation account, and a set of integer variables the account's runbooks share as state. The variables' name outputs are the keys the runbooks reference:

module "rg" {
  source   = "git::https://github.com/microsoftexpert/terraform-azurerm-resource-group.git?ref=v1.0.0"
  name     = "rg-automation-eastus"
  location = "eastus"
}

module "automation" {
  source              = "git::https://github.com/microsoftexpert/terraform-azurerm-automation-account.git?ref=v1.0.0"
  name                = "aa-contoso"
  resource_group_name = module.rg.name
  location            = module.rg.location
}

module "max_retries" {
  source                  = "git::https://github.com/microsoftexpert/terraform-azurerm-automation-variable-int.git?ref=v1.0.0"
  name                    = "MaxRetries"
  resource_group_name     = module.rg.name
  automation_account_name = module.automation.name # from terraform-azurerm-automation-account
  value                   = 3
  description             = "Retry budget for the reconciliation runbook"
}

module "consecutive_failures" {
  source                  = "git::https://github.com/microsoftexpert/terraform-azurerm-automation-variable-int.git?ref=v1.0.0"
  name                    = "ConsecutiveFailures"
  resource_group_name     = module.rg.name
  automation_account_name = module.automation.name
  value                   = 0 # seeded; the runbook increments it at runtime
}

πŸ’‘ The account module supplies automation_account_name; each variable module contributes one integer asset. Reference sibling name outputs so the runbook keys stay in sync with the deployed variables.

πŸ“₯ Inputs

Required: name, resource_group_name, automation_account_name. Optional: value, encrypted, description. Universal tail: timeouts (no tags β€” the resource does not support them).

Full schemas
name                    = string # required, force-new
resource_group_name     = string # required, force-new
automation_account_name = string # required, force-new

value       = optional(number) # integer; null = variable created with no value
encrypted   = optional(bool)   # default false; true wraps the value sensitive, not returned on read
description = optional(string)

timeouts = optional(object({
  create = optional(string) # Go duration, e.g. "30m"
  read   = optional(string)
  update = optional(string)
  delete = optional(string)
}))

🧾 Outputs

Output Description Kind
id Resource ID of the Automation Int variable Passthrough
name Name of the variable, as created Passthrough
automation_account_name Name of the parent Automation account this variable belongs to Passthrough
resource_group_name Name of the resource group holding the parent Automation account Passthrough
variable_type Constant "Int" Derived
is_encrypted Whether the value is encrypted at rest Passthrough
has_value Whether a value was supplied Derived
value_is_readable_by_terraform False when the variable is encrypted Derived
has_description Whether a description was set Derived
renaming_this_variable_destroys_its_value Constant true Constant
is_scoped_to_one_automation_account Constant true Constant
value_is_not_emitted_by_design Constant true Constant

No secret is emitted. When encrypted is true the value is wrapped sensitive and Azure does not return it on read.

🧠 Architecture Notes

  • Identity fields are force-new. name, resource_group_name, and automation_account_name are immutable β€” changing any of them destroys and recreates the variable, losing any value a runbook wrote at runtime. value, encrypted, and description all update in place.
  • The value is typed as a number. Modeling it as an integer rather than a loose string means a malformed value fails at plan time, and runbooks read back a genuine number. Leave value null to declare the variable without setting one.
  • encrypted gates both storage and visibility. It defaults to false. When true, main.tf wraps the value with sensitive() so it never surfaces in plan output, and Azure stops returning the value on read β€” Terraform then tracks it from configuration, so the module stays the source of truth for encrypted values.
  • No tags, and no secret output. The resource type does not support tags; the universal tail is timeouts only. The module emits 12 outputs -- identity, parentage and derived facts -- but never the value itself; has_value reports presence instead.
  • features {} dependence. The provider will not initialize without a caller-side features {} block β€” expected, and owned by the root module.

🧱 Design Principles

Concern Secure default Opt-out (caller must type it)
Encryption at rest encrypted = false (a plain integer counter is not sensitive) set encrypted = true to wrap the value and hide it on read
Value visibility encrypted values are wrapped sensitive and never printed in plan β€” (enforced whenever encrypted = true)
Secret handling emits no value output; only id and name β€” (a variable's value is never emitted)
Type safety value is a number, validated at plan time β€” (a non-integer value cannot plan)

πŸš€ Runbook

terraform init -backend=false
terraform validate
terraform fmt -check

Pin the module by immutable tag (?ref=v1.0.0), never a branch. This is plan-only; a human applies from CI.

πŸ§ͺ Testing

  • terraform validate + fmt -check prove the type contract offline β€” that value is an integer, encrypted is a boolean, and the three identity fields are present β€” before any Azure call.
  • Only terraform plan against a subscription exercises the existence of the Automation account, the force-new replacement when an identity field changes, and the read-back behavior when encrypted = true.

πŸ’¬ Example Output

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

id   = "/subscriptions/.../resourceGroups/rg-automation-eastus/providers/Microsoft.Automation/automationAccounts/aa-contoso/variables/MaxRetries"
name = "MaxRetries"

πŸ” Troubleshooting

Symptom Cause Fix
Inappropriate value for attribute "value": a number is required A string or fractional value passed to value Pass a whole number (for example 42), or omit value to leave it unset
Variable replaced on a rename Changed name, resource_group_name, or automation_account_name (force-new) Expected β€” these identity fields replace the resource; change value/encrypted/description to update in place
Value not visible after apply encrypted = true β€” Azure does not return encrypted values on read Expected; Terraform tracks the value from configuration, so keep the module as the source of truth
Runbook reads null instead of a number Variable created with value omitted, or a runbook cleared it Set value in the module, or have the runbook write with Set-AutomationVariable
Apply fails: parent not found The Automation account named in automation_account_name does not exist Create the Automation account first (see the end-to-end composition example)

πŸ”— Related Docs

  • azurerm_automation_variable_int
  • Sibling modules: terraform-azurerm-automation-variable-string, terraform-azurerm-automation-variable-bool, terraform-azurerm-automation-variable-datetime, terraform-azurerm-automation-account
  • This module's SCOPE.md

πŸ’™ "Infrastructure as Code should be standardized, consistent, and secure."