The key construct for the Authoritative Release is that all aspects of the release process are predictable and repeatable. To avoid deploy-time variations in Terraform dependencies, modules are not downloaded at deploytime, instead they are resolved at build time and packaged into an immutable release package. For a consistent way-of-working, the Terraform build process resolves and validates dependencies.
Most Terraform module resolution approaches are to pull from source control (Git) or registry at deploy-time, which can require additional credential management, risks unexpected module changes (if tags are used) and potential network connectivity issues. This approach is the treat modules like software dependencies, resolving them at build time and building them into an all-in-one immutable package.
The following state.tf
defines the modules and versions that are required
terraform {
backend "local" {}
}
module "stack_modules" {
source = "app.terraform.io/example/modules/azurerm"
version = "0.2.0"
}
module "stack_components" {
source = "app.terraform.io/example/components/azurerm"
version = "0.1.3"
}
The following builld.tsk
triggers module download from a private registry using credentials in TERRAFORM_REGISTRY_TOKEN
, these credentials will not be required at deploy time.
Write-Host "[$TASK_NAME] Verify Version`n" -ForegroundColor Cyan
terraform --version
VARCHK
MAKDIR $env:APPDATA\terraform.d
$conf = "$env:APPDATA\terraform.d\credentials.tfrc.json"
Set-Content $conf '{'
Add-Content $conf ' "credentials": {'
Add-Content $conf ' "app.terraform.io": {'
Add-Content $conf " `"token`": `"$env:TERRAFORM_REGISTRY_TOKEN`""
Add-Content $conf ' }'
Add-Content $conf ' }'
Add-Content $conf '}'
Get-Content $conf
Write-Host "[$TASK_NAME] Log the module registry details`n" -ForegroundColor Cyan
Get-Content state.tf
Write-Host "[$TASK_NAME] In a clean workspace, first init will download modules, then fail, ignore this and init again"
if ( ! ( Test-Path ./.terraform/modules/azurerm )) { IGNORE "terraform init -upgrade -input=false" }
Write-Host "[$TASK_NAME] Initialise with local state storage and download modules`n" -ForegroundColor Cyan
terraform init -upgrade -input=false
Once all modules have been downloaded, syntax is then validated.
Write-Host "[$TASK_NAME] Validate Syntax`n" -ForegroundColor Cyan
terraform validate
Write-Host "[$TASK_NAME] Generate the graph to validate the plan`n" -ForegroundColor Cyan
terraform graph
All the deploy-time files are copied into the release
directory. Because tokens cannot be used during the build process, an arbitrary numeric is used, and this is then replaced in the resulting release
directory. Tokenisation is covered in more detail in the following section
Write-Host "[$TASK_NAME] Tokenise variable file`n" -ForegroundColor Cyan
REFRSH .terraform\modules\* ..\release\.terraform\modules\
VECOPY *".tf" ..\release
VECOPY *".json" ..\release
REPLAC ..\release\variables.tf '{ default = 3 }' '{ default = %agent_count% }'
The deploytime components are then copied into the release package, based on the storeFor
definition in your solution directory
# Tokenised Terraform Files
release
The modules and helper scripts are then packed into a self-extracting release executable as per standard CDAF release build process