We may want to validate and possibly suppress any sensitive information defined within our variables.
- Task 1: Validate variables in Terraform Configuration
- Task 2: Suppress sensitive information
- Task 3: View the Terraform state file
Change directory into a folder specific to this challenge.
For example: cd /workstation/terraform/azure/variable-validation/
.
We will start with a few of the basic resources needed.
Create a file variables.tf
and add the following configuration:
variable "resource_group_name" {}
variable "EnvironmentTag" {}
variable "prefix" {}
variable "location" {
default = "East US"
}
variable "computer_name" {}
variable "admin_username" {}
variable "admin_password" {}
variable "num_vms" {
default = 2
}
variable "vm_size" {
type = string
description = "Server Size"
default = "Standard_A2"
validation {
condition = contains(["Standard_D2s_v4", "Standard_A2", "Standard_DS1_v2"], var.vm_size)
error_message = "You must use an approved VM Size. Options are Standard_A2, Standard_DS1_v2 or Standard_D2s_v4."
}
}
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "training" {
name = var.resource_group_name
location = var.location
}
resource "azurerm_virtual_network" "training" {
name = "azureuser${var.prefix}vn"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.training.location
resource_group_name = azurerm_resource_group.training.name
}
resource "azurerm_subnet" "training" {
name = "azureuser${var.prefix}sub"
resource_group_name = azurerm_resource_group.training.name
virtual_network_name = azurerm_virtual_network.training.name
address_prefixes = ["10.0.2.0/24"]
}
resource "azurerm_public_ip" "training" {
count = var.num_vms
name = "azureuser${var.prefix}varval-${count.index + 1}"
location = azurerm_resource_group.training.location
resource_group_name = azurerm_resource_group.training.name
allocation_method = "Dynamic"
idle_timeout_in_minutes = 30
domain_name_label = "azureuser${var.prefix}domain${count.index + 1}"
}
resource "azurerm_network_interface" "training" {
count = var.num_vms
name = "azureuser${var.prefix}varval-${count.index + 1}"
location = azurerm_resource_group.training.location
resource_group_name = azurerm_resource_group.training.name
ip_configuration {
name = "azureuser${var.prefix}ip"
subnet_id = azurerm_subnet.training.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.training[count.index].id
}
}
resource "azurerm_virtual_machine" "training" {
count = var.num_vms
name = "${var.prefix}vm-${count.index + 1}"
location = azurerm_resource_group.training.location
resource_group_name = azurerm_resource_group.training.name
network_interface_ids = [azurerm_network_interface.training[count.index].id]
vm_size = var.vm_size
delete_os_disk_on_termination = true
delete_data_disks_on_termination = true
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "18.04-LTS"
version = "latest"
}
storage_os_disk {
name = "${var.prefix}disk-${count.index + 1}"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
os_profile {
computer_name = var.computer_name
admin_username = var.admin_username
admin_password = var.admin_password
}
os_profile_linux_config {
disable_password_authentication = false
}
tags = {
environment = var.EnvironmentTag
}
}
Create a file terraform.tfvars
and add the following configuration and change out the ### with your initials.
resource_group_name = "###-resourcegroup-var-validate"
EnvironmentTag = "staging"
prefix = "###"
location = "East US"
computer_name = "myserver"
admin_username = "testadmin"
admin_password = "Password1234!"
vm_size = "Standard_D2s_v4"
num_vms = 1
terraform init
terraform plan
Now run a plan with a VM Size that is not approved:
terraform plan -var vm_size=Standard_GS1
Initializing Terraform configuration...
╷
│ Error: Invalid value for variable
│
│ on variables.tf line 14:
│ 14: variable "vm_size" {
│
│ You must use an approved operating system. Options are Standard_A2, Standard_DS1_v2 or Standard_D2s_v4.
│
│ This was checked by the validation rule at variables.tf:19,3-13.
Now run a plan with a VM Size that is approved:
terraform plan -var vm_size=Standard_A2
Terraform allows us to mark variables as sensitive and suppress that information. Create contactinfo.tf
contactinfo.tf
variable "department" {
type = string
validation {
condition = length(var.department) == 3
error_message = "Department length must be 3 characters."
}
}
variable "cost_code" {
type = string
validation {
condition = can(regex("^(?:[0-9]{1,2}\\-){2}[0-9]{1,2}$", var.cost_code))
error_message = "Must be an cost code address of the form X-X-X."
}
}
variable "phone_number" {
type = string
sensitive = true
default = "867-5309"
}
locals {
contact_info = {
department = var.department
cost_code = var.cost_code
phone_number = var.phone_number
}
my_number = nonsensitive(var.phone_number)
}
output "department" {
value = local.contact_info.department
}
output "cost_code" {
value = local.contact_info.cost_code
}
output "phone_number" {
value = local.contact_info.phone_number
}
output "my_number" {
value = local.my_number
}
Append the following items to the terraform.tfvars
file:
department = "ABC"
cost_code = "1-3-4"
Execute a terraform validate
with the variables in the terraform.tfvars
.
terraform validate
You will notice that the output block errors as it needs to have the sensitive = true
value set.
╷
│ Error: Output refers to sensitive values
│
│ on variables.tf line 73:
│ 73: output "phone_number" {
│
│ To reduce the risk of accidentally exporting sensitive data that was intended to be only internal, Terraform requires that any root module output containing
│ sensitive data be explicitly marked as sensitive, to confirm your intent.
│
│ If you do intend to export this data, annotate the output value as sensitive by adding the following argument:
│ sensitive = true
╵
Update the output to set the sensitive = true
attribute and rerun the validate.
output "phone_number" {
sensitive = true
value = local.contact_info.phone_number
}
terraform validate
After validation is succesful, apply the configuration.
terraform apply
Outputs:
cost_code = "1-3-4"
department = "ABC"
my_number = "867-5309"
phone_number = <sensitive>
Even though items are marked as sensitive within the Terraform configuration, they are stored within the Terraform state file. It is therefore critical to limit the access to the Terraform state file.
{
{
"version": 4,
"terraform_version": "1.0.9",
"serial": 5,
"lineage": "67c71c6f-af25-b300-2ea7-6d0f4b226b7b",
"outputs": {
"cost_code": {
"value": "1-3-4",
"type": "string"
},
"department": {
"value": "ABC",
"type": "string"
},
"my_number": {
"value": "867-5309",
"type": "string"
},
"phone_number": {
"value": "867-5309",
"type": "string",
"sensitive": true
},
...