Ansible and Terraform: Github

Published: Mar 30, 2023 by Isaac Johnson

Monday, I covered setting up Terraform to fire up an Ansible playbook during Infrastructure creation time. While that worked fine, we ideally would like to keep our playbooks in GIT.

Today, we’ll tie it together with Github and AKV using a stored PAT to clone a remote repo we’ll use for playbooks. We will then setup Terraform Cloud for a new project and change our playbooks to move out of local-exec to a function remote-exec model. Lastly, we’ll optimize a given playbook to handle inline Docker installs.

Pulling from Github

This was a fine example when our Playbook would be stored with the Terraform.

However, I tend to keep my playbooks in their own Github repository, often to be used with AWX.

How might we handle external playbooks?

Dynamically cloning Github Playbooks

We can use a secret store of our choosing to fetch a Github PAT then use that to clone a repo.

Since the null resource we’ll setup to fetch the repo has no native tie-in to the VM resource block, we’ll need to add a depeneds_on block

In our main.tf we can add an AKV block with the Clone step

# Fetching an AKV Secret

data "azurerm_key_vault" "idjakv" {
  name                = "idjakv"
  resource_group_name = "idjakvrg"
}

data "azurerm_key_vault_secret" "ghpassword" {
  name         = "GithubToken-MyFull90d"
  key_vault_id = data.azurerm_key_vault.idjakv.id
}

#pull the code from github
resource "null_resource" "git_clone" {
  provisioner "local-exec" {
    command = "git clone https://idjohnson:${data.azurerm_key_vault_secret.ghpassword.value}@github.com/idjohnson/ansible-playbooks ./local_co"
  }
}

The we use the playbook and add a depends_on at the end of the VM Create

  provisioner "local-exec" {
    command = "ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -u azureuser -i '${azurerm_linux_virtual_machine.my_terraform_vm.public_ip_address},' --private-key ${local_file.idrsa.filename} -e 'pub_key=${local_file.idrsapub.filename}' ./local_co/cloudcustodian.yaml"
    
  }

  depends_on = [ null_resource.git_clone ]
}

We can see it in action:

builder@DESKTOP-72D2D9T:~/Workspaces/tfAnsibleAzure$ terraform apply
data.azurerm_key_vault.idjakv: Reading...
data.azurerm_key_vault.idjakv: Read complete after 1s [id=/subscriptions/d955c0ba-13dc-44cf-a29a-8fed74cbb22d/resourceGroups/idjakvrg/providers/Microsoft.KeyVault/vaults/idjakv]
data.azurerm_key_vault_secret.ghpassword: Reading...
data.azurerm_key_vault_secret.ghpassword: Read complete after 5s [id=https://idjakv.vault.azure.net/secrets/GithubToken-MyFull90d/948990437f7148b9a18d9491ea6c2fee]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_linux_virtual_machine.my_terraform_vm will be created
  + resource "azurerm_linux_virtual_machine" "my_terraform_vm" {
      + admin_username                  = "azureuser"
      + allow_extension_operations      = true
      + computer_name                   = "myvm"
      + disable_password_authentication = true
      + extensions_time_budget          = "PT1H30M"
      + id                              = (known after apply)
      + location                        = "eastus"
      + max_bid_price                   = -1
      + name                            = "myVM"
      + network_interface_ids           = (known after apply)
      + patch_assessment_mode           = "ImageDefault"
      + patch_mode                      = "ImageDefault"
      + platform_fault_domain           = -1
      + priority                        = "Regular"
      + private_ip_address              = (known after apply)
      + private_ip_addresses            = (known after apply)
      + provision_vm_agent              = true
      + public_ip_address               = (known after apply)
      + public_ip_addresses             = (known after apply)
      + resource_group_name             = "idj-east-rg"
      + size                            = "Standard_DS1_v2"
      + virtual_machine_id              = (known after apply)

      + admin_ssh_key {
          + public_key = (known after apply)
          + username   = "azureuser"
        }

      + boot_diagnostics {
          + storage_account_uri = (known after apply)
        }

      + os_disk {
          + caching                   = "ReadWrite"
          + disk_size_gb              = (known after apply)
          + name                      = "myOsDisk"
          + storage_account_type      = "Premium_LRS"
          + write_accelerator_enabled = false
        }

      + source_image_reference {
          + offer     = "0001-com-ubuntu-server-jammy"
          + publisher = "Canonical"
          + sku       = "22_04-lts-gen2"
          + version   = "latest"
        }
    }

  # azurerm_network_interface.my_terraform_nic will be created
  + resource "azurerm_network_interface" "my_terraform_nic" {
      + applied_dns_servers           = (known after apply)
      + dns_servers                   = (known after apply)
      + enable_accelerated_networking = false
      + enable_ip_forwarding          = false
      + id                            = (known after apply)
      + internal_dns_name_label       = (known after apply)
      + internal_domain_name_suffix   = (known after apply)
      + location                      = "eastus"
      + mac_address                   = (known after apply)
      + name                          = "myNIC"
      + private_ip_address            = (known after apply)
      + private_ip_addresses          = (known after apply)
      + resource_group_name           = "idj-east-rg"
      + virtual_machine_id            = (known after apply)

      + ip_configuration {
          + gateway_load_balancer_frontend_ip_configuration_id = (known after apply)
          + name                                               = "my_nic_configuration"
          + primary                                            = (known after apply)
          + private_ip_address                                 = (known after apply)
          + private_ip_address_allocation                      = "Dynamic"
          + private_ip_address_version                         = "IPv4"
          + public_ip_address_id                               = (known after apply)
          + subnet_id                                          = (known after apply)
        }
    }

  # azurerm_network_interface_security_group_association.example will be created
  + resource "azurerm_network_interface_security_group_association" "example" {
      + id                        = (known after apply)
      + network_interface_id      = (known after apply)
      + network_security_group_id = (known after apply)
    }

  # azurerm_network_security_group.my_terraform_nsg will be created
  + resource "azurerm_network_security_group" "my_terraform_nsg" {
      + id                  = (known after apply)
      + location            = "eastus"
      + name                = "myNetworkSecurityGroup"
      + resource_group_name = "idj-east-rg"
      + security_rule       = [
          + {
              + access                                     = "Allow"
              + description                                = ""
              + destination_address_prefix                 = "*"
              + destination_address_prefixes               = []
              + destination_application_security_group_ids = []
              + destination_port_range                     = "22"
              + destination_port_ranges                    = []
              + direction                                  = "Inbound"
              + name                                       = "SSH"
              + priority                                   = 1001
              + protocol                                   = "Tcp"
              + source_address_prefix                      = "*"
              + source_address_prefixes                    = []
              + source_application_security_group_ids      = []
              + source_port_range                          = "*"
              + source_port_ranges                         = []
            },
        ]
    }

  # azurerm_public_ip.my_terraform_public_ip will be created
  + resource "azurerm_public_ip" "my_terraform_public_ip" {
      + allocation_method       = "Dynamic"
      + ddos_protection_mode    = "VirtualNetworkInherited"
      + fqdn                    = (known after apply)
      + id                      = (known after apply)
      + idle_timeout_in_minutes = 4
      + ip_address              = (known after apply)
      + ip_version              = "IPv4"
      + location                = "eastus"
      + name                    = "myPublicIP"
      + resource_group_name     = "idj-east-rg"
      + sku                     = "Basic"
      + sku_tier                = "Regional"
    }

  # azurerm_resource_group.rg will be created
  + resource "azurerm_resource_group" "rg" {
      + id       = (known after apply)
      + location = "eastus"
      + name     = "idj-east-rg"
    }

  # azurerm_storage_account.my_storage_account will be created
  + resource "azurerm_storage_account" "my_storage_account" {
      + access_tier                       = (known after apply)
      + account_kind                      = "StorageV2"
      + account_replication_type          = "LRS"
      + account_tier                      = "Standard"
      + allow_nested_items_to_be_public   = true
      + cross_tenant_replication_enabled  = true
      + default_to_oauth_authentication   = false
      + enable_https_traffic_only         = true
      + id                                = (known after apply)
      + infrastructure_encryption_enabled = false
      + is_hns_enabled                    = false
      + large_file_share_enabled          = (known after apply)
      + location                          = "eastus"
      + min_tls_version                   = "TLS1_2"
      + name                              = (known after apply)
      + nfsv3_enabled                     = false
      + primary_access_key                = (sensitive value)
      + primary_blob_connection_string    = (sensitive value)
      + primary_blob_endpoint             = (known after apply)
      + primary_blob_host                 = (known after apply)
      + primary_connection_string         = (sensitive value)
      + primary_dfs_endpoint              = (known after apply)
      + primary_dfs_host                  = (known after apply)
      + primary_file_endpoint             = (known after apply)
      + primary_file_host                 = (known after apply)
      + primary_location                  = (known after apply)
      + primary_queue_endpoint            = (known after apply)
      + primary_queue_host                = (known after apply)
      + primary_table_endpoint            = (known after apply)
      + primary_table_host                = (known after apply)
      + primary_web_endpoint              = (known after apply)
      + primary_web_host                  = (known after apply)
      + public_network_access_enabled     = true
      + queue_encryption_key_type         = "Service"
      + resource_group_name               = "idj-east-rg"
      + secondary_access_key              = (sensitive value)
      + secondary_blob_connection_string  = (sensitive value)
      + secondary_blob_endpoint           = (known after apply)
      + secondary_blob_host               = (known after apply)
      + secondary_connection_string       = (sensitive value)
      + secondary_dfs_endpoint            = (known after apply)
      + secondary_dfs_host                = (known after apply)
      + secondary_file_endpoint           = (known after apply)
      + secondary_file_host               = (known after apply)
      + secondary_location                = (known after apply)
      + secondary_queue_endpoint          = (known after apply)
      + secondary_queue_host              = (known after apply)
      + secondary_table_endpoint          = (known after apply)
      + secondary_table_host              = (known after apply)
      + secondary_web_endpoint            = (known after apply)
      + secondary_web_host                = (known after apply)
      + sftp_enabled                      = false
      + shared_access_key_enabled         = true
      + table_encryption_key_type         = "Service"
    }

  # azurerm_subnet.my_terraform_subnet will be created
  + resource "azurerm_subnet" "my_terraform_subnet" {
      + address_prefixes                               = [
          + "10.0.1.0/24",
        ]
      + enforce_private_link_endpoint_network_policies = (known after apply)
      + enforce_private_link_service_network_policies  = (known after apply)
      + id                                             = (known after apply)
      + name                                           = "mySubnet"
      + private_endpoint_network_policies_enabled      = (known after apply)
      + private_link_service_network_policies_enabled  = (known after apply)
      + resource_group_name                            = "idj-east-rg"
      + virtual_network_name                           = "example-network"
    }

  # azurerm_virtual_network.examplevnet will be created
  + resource "azurerm_virtual_network" "examplevnet" {
      + address_space       = [
          + "10.0.0.0/16",
        ]
      + dns_servers         = (known after apply)
      + guid                = (known after apply)
      + id                  = (known after apply)
      + location            = "eastus"
      + name                = "example-network"
      + resource_group_name = "idj-east-rg"
      + subnet              = (known after apply)
    }

  # local_file.idrsa will be created
  + resource "local_file" "idrsa" {
      + content              = (sensitive value)
      + content_base64sha256 = (known after apply)
      + content_base64sha512 = (known after apply)
      + content_md5          = (known after apply)
      + content_sha1         = (known after apply)
      + content_sha256       = (known after apply)
      + content_sha512       = (known after apply)
      + directory_permission = "0777"
      + file_permission      = "0600"
      + filename             = "./id_rsa"
      + id                   = (known after apply)
    }

  # local_file.idrsapub will be created
  + resource "local_file" "idrsapub" {
      + content              = (known after apply)
      + content_base64sha256 = (known after apply)
      + content_base64sha512 = (known after apply)
      + content_md5          = (known after apply)
      + content_sha1         = (known after apply)
      + content_sha256       = (known after apply)
      + content_sha512       = (known after apply)
      + directory_permission = "0777"
      + file_permission      = "0633"
      + filename             = "./id_rsa.pub"
      + id                   = (known after apply)
    }

  # null_resource.git_clone will be created
  + resource "null_resource" "git_clone" {
      + id = (known after apply)
    }

  # random_id.random_id will be created
  + resource "random_id" "random_id" {
      + b64_std     = (known after apply)
      + b64_url     = (known after apply)
      + byte_length = 8
      + dec         = (known after apply)
      + hex         = (known after apply)
      + id          = (known after apply)
      + keepers     = {
          + "resource_group" = "idj-east-rg"
        }
    }

  # tls_private_key.example_ssh will be created
  + resource "tls_private_key" "example_ssh" {
      + algorithm                     = "RSA"
      + ecdsa_curve                   = "P224"
      + id                            = (known after apply)
      + private_key_openssh           = (sensitive value)
      + private_key_pem               = (sensitive value)
      + private_key_pem_pkcs8         = (sensitive value)
      + public_key_fingerprint_md5    = (known after apply)
      + public_key_fingerprint_sha256 = (known after apply)
      + public_key_openssh            = (known after apply)
      + public_key_pem                = (known after apply)
      + rsa_bits                      = 4096
    }

Plan: 14 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + public_ip_address   = (known after apply)
  + resource_group_name = "idj-east-rg"
  + tls_private_key     = (sensitive value)

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

tls_private_key.example_ssh: Creating...
tls_private_key.example_ssh: Creation complete after 2s [id=cb9aa724ad537b00a1aaf9708ce2a9693759736f]
local_file.idrsapub: Creating...
local_file.idrsa: Creating...
local_file.idrsapub: Creation complete after 0s [id=b8e61a8de9041e826c9955d5f60f0b92d7fb486a]
local_file.idrsa: Creation complete after 0s [id=bad17c6318bde0ae95037c8eb773f730b9e52c85]
null_resource.git_clone: Creating...
azurerm_resource_group.rg: Creating...
null_resource.git_clone: Provisioning with 'local-exec'...
null_resource.git_clone (local-exec): (output suppressed due to sensitive value in config)
null_resource.git_clone (local-exec): (output suppressed due to sensitive value in config)
azurerm_resource_group.rg: Creation complete after 1s [id=/subscriptions/d955c0ba-13dc-44cf-a29a-8fed74cbb22d/resourceGroups/idj-east-rg]
azurerm_virtual_network.examplevnet: Creating...
azurerm_network_security_group.my_terraform_nsg: Creating...
azurerm_public_ip.my_terraform_public_ip: Creating...
random_id.random_id: Creating...
random_id.random_id: Creation complete after 0s [id=tF0hC99t1Ew]
azurerm_storage_account.my_storage_account: Creating...
null_resource.git_clone: Creation complete after 2s [id=6596202982561700173]
azurerm_public_ip.my_terraform_public_ip: Creation complete after 3s [id=/subscriptions/d955c0ba-13dc-44cf-a29a-8fed74cbb22d/resourceGroups/idj-east-rg/providers/Microsoft.Network/publicIPAddresses/myPublicIP]
azurerm_network_security_group.my_terraform_nsg: Creation complete after 5s [id=/subscriptions/d955c0ba-13dc-44cf-a29a-8fed74cbb22d/resourceGroups/idj-east-rg/providers/Microsoft.Network/networkSecurityGroups/myNetworkSecurityGroup]
azurerm_virtual_network.examplevnet: Creation complete after 6s [id=/subscriptions/d955c0ba-13dc-44cf-a29a-8fed74cbb22d/resourceGroups/idj-east-rg/providers/Microsoft.Network/virtualNetworks/example-network]
azurerm_subnet.my_terraform_subnet: Creating...
azurerm_storage_account.my_storage_account: Still creating... [10s elapsed]
azurerm_subnet.my_terraform_subnet: Creation complete after 5s [id=/subscriptions/d955c0ba-13dc-44cf-a29a-8fed74cbb22d/resourceGroups/idj-east-rg/providers/Microsoft.Network/virtualNetworks/example-network/subnets/mySubnet]
azurerm_network_interface.my_terraform_nic: Creating...
azurerm_network_interface.my_terraform_nic: Creation complete after 1s [id=/subscriptions/d955c0ba-13dc-44cf-a29a-8fed74cbb22d/resourceGroups/idj-east-rg/providers/Microsoft.Network/networkInterfaces/myNIC]
azurerm_network_interface_security_group_association.example: Creating...
azurerm_network_interface_security_group_association.example: Creation complete after 2s [id=/subscriptions/d955c0ba-13dc-44cf-a29a-8fed74cbb22d/resourceGroups/idj-east-rg/providers/Microsoft.Network/networkInterfaces/myNIC|/subscriptions/d955c0ba-13dc-44cf-a29a-8fed74cbb22d/resourceGroups/idj-east-rg/providers/Microsoft.Network/networkSecurityGroups/myNetworkSecurityGroup]
azurerm_storage_account.my_storage_account: Still creating... [20s elapsed]
azurerm_storage_account.my_storage_account: Creation complete after 24s [id=/subscriptions/d955c0ba-13dc-44cf-a29a-8fed74cbb22d/resourceGroups/idj-east-rg/providers/Microsoft.Storage/storageAccounts/diagb45d210bdf6dd44c]
azurerm_linux_virtual_machine.my_terraform_vm: Creating...
azurerm_linux_virtual_machine.my_terraform_vm: Still creating... [10s elapsed]
azurerm_linux_virtual_machine.my_terraform_vm: Still creating... [20s elapsed]
azurerm_linux_virtual_machine.my_terraform_vm: Still creating... [30s elapsed]
azurerm_linux_virtual_machine.my_terraform_vm: Still creating... [40s elapsed]
azurerm_linux_virtual_machine.my_terraform_vm: Provisioning with 'remote-exec'...
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Connecting to remote host via SSH...
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):   Host: 20.163.139.190
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):   User: azureuser
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):   Password: false
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):   Private key: true
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):   Certificate: false
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):   SSH Agent: false
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):   Checking Host Key: false
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):   Target Platform: unix
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Connected!
azurerm_linux_virtual_machine.my_terraform_vm: Still creating... [50s elapsed]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Hit:1 http://azure.archive.ubuntu.com/ubuntu jammy InRelease
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:2 http://azure.archive.ubuntu.com/ubuntu jammy-updates InRelease [119 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:3 http://azure.archive.ubuntu.com/ubuntu jammy-backports InRelease [107 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:4 http://azure.archive.ubuntu.com/ubuntu jammy-security InRelease [110 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:5 http://azure.archive.ubuntu.com/ubuntu jammy/universe amd64 Packages [14.1 MB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages 56.0 kB/14.1 MB 0%]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:6 http://azure.archive.ubuntu.com/ubuntu jammy/universe Translation-en [5652 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [6 Translation-en 123 kB/5652 kB 2%]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B] [6 Translatio
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:7 http://azure.archive.ubuntu.com/ubuntu jammy/universe amd64 c-n-f Metadata [286 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:8 http://azure.archive.ubuntu.com/ubuntu jammy/multiverse amd64 Packages [217 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B] [8 Packages 1
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:9 http://azure.archive.ubuntu.com/ubuntu jammy/multiverse Translation-en [112 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B] [9 Translatio
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:10 http://azure.archive.ubuntu.com/ubuntu jammy/multiverse amd64 c-n-f Metadata [8372 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B] [10 Commands-
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:11 http://azure.archive.ubuntu.com/ubuntu jammy-updates/main amd64 Packages [949 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B] [11 Packages
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:12 http://azure.archive.ubuntu.com/ubuntu jammy-updates/main Translation-en [205 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B] [12 Translati
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:13 http://azure.archive.ubuntu.com/ubuntu jammy-updates/main amd64 c-n-f Metadata [13.8 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B] [13 Commands-
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:14 http://azure.archive.ubuntu.com/ubuntu jammy-updates/restricted amd64 Packages [684 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B] [14 Packages
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:15 http://azure.archive.ubuntu.com/ubuntu jammy-updates/restricted Translation-en [107 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B] [15 Translati
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:16 http://azure.archive.ubuntu.com/ubuntu jammy-updates/universe amd64 Packages [895 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B] [16 Packages
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:17 http://azure.archive.ubuntu.com/ubuntu jammy-updates/universe Translation-en [179 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B] [17 Translati
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:18 http://azure.archive.ubuntu.com/ubuntu jammy-updates/universe amd64 c-n-f Metadata [18.4 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B] [18 Commands-
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:19 http://azure.archive.ubuntu.com/ubuntu jammy-updates/multiverse amd64 Packages [24.1 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B] [19 Packages
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:20 http://azure.archive.ubuntu.com/ubuntu jammy-updates/multiverse Translation-en [6312 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B] [20 Translati
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:21 http://azure.archive.ubuntu.com/ubuntu jammy-updates/multiverse amd64 c-n-f Metadata [444 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B] [21 Commands-
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:22 http://azure.archive.ubuntu.com/ubuntu jammy-backports/main amd64 Packages [40.7 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:23 http://azure.archive.ubuntu.com/ubuntu jammy-backports/main Translation-en [9800 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:24 http://azure.archive.ubuntu.com/ubuntu jammy-backports/main amd64 c-n-f Metadata [392 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:25 http://azure.archive.ubuntu.com/ubuntu jammy-backports/restricted amd64 c-n-f Metadata [116 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:26 http://azure.archive.ubuntu.com/ubuntu jammy-backports/universe amd64 Packages [19.5 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:27 http://azure.archive.ubuntu.com/ubuntu jammy-backports/universe Translation-en [14.0 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B] [27 Translati
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:28 http://azure.archive.ubuntu.com/ubuntu jammy-backports/universe amd64 c-n-f Metadata [392 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:29 http://azure.archive.ubuntu.com/ubuntu jammy-backports/multiverse amd64 c-n-f Metadata [116 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 84% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:30 http://azure.archive.ubuntu.com/ubuntu jammy-security/main amd64 Packages [693 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 85% [5 Packages store 0 B] [30 Packages
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 86% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:31 http://azure.archive.ubuntu.com/ubuntu jammy-security/main Translation-en [143 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 86% [5 Packages store 0 B] [Waiting for
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:32 http://azure.archive.ubuntu.com/ubuntu jammy-security/main amd64 c-n-f Metadata [9016 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 86% [5 Packages store 0 B] [32 Commands
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 86% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:33 http://azure.archive.ubuntu.com/ubuntu jammy-security/restricted amd64 Packages [645 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 86% [5 Packages store 0 B] [33 Packages
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 88% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:34 http://azure.archive.ubuntu.com/ubuntu jammy-security/restricted Translation-en [100 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 88% [5 Packages store 0 B] [34 Translat
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 89% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:35 http://azure.archive.ubuntu.com/ubuntu jammy-security/restricted amd64 c-n-f Metadata [588 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 89% [5 Packages store 0 B] [35 Commands
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 89% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:36 http://azure.archive.ubuntu.com/ubuntu jammy-security/universe amd64 Packages [714 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 89% [5 Packages store 0 B] [36 Packages
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 91% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:37 http://azure.archive.ubuntu.com/ubuntu jammy-security/universe Translation-en [118 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 91% [5 Packages store 0 B] [37 Translat
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 91% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:38 http://azure.archive.ubuntu.com/ubuntu jammy-security/universe amd64 c-n-f Metadata [14.1 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 91% [5 Packages store 0 B] [38 Commands
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 91% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:39 http://azure.archive.ubuntu.com/ubuntu jammy-security/multiverse amd64 Packages [19.4 kB]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 91% [5 Packages store 0 B] [39 Packages
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 91% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:40 http://azure.archive.ubuntu.com/ubuntu jammy-security/multiverse Translation-en [4068 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 91% [5 Packages store 0 B] [40 Translat
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 91% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Get:41 http://azure.archive.ubuntu.com/ubuntu jammy-security/multiverse amd64 c-n-f Metadata [228 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 91% [5 Packages store 0 B] [41 Commands
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 91% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 91% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 91% [5 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 91% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 91% [6 Translation-en store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 91% [6 Translation-en store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 92% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 92% [7 Commands-amd64 store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 92% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 92% [8 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 92% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 92% [9 Translation-en store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 92% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 92% [10 Commands-amd64 store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 93% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 93% [11 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 93% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 93% [12 Translation-en store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 93% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 93% [13 Commands-amd64 store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 93% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 93% [14 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 94% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 94% [15 Translation-en store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 94% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 94% [16 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 94% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 94% [17 Translation-en store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 94% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 94% [18 Commands-amd64 store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 95% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 95% [19 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 95% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 95% [20 Translation-en store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 95% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 95% [21 Commands-amd64 store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 95% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 95% [22 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 95% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 95% [23 Translation-en store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 96% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 96% [24 Commands-amd64 store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 96% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 96% [25 Commands-amd64 store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 96% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 96% [26 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 96% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 96% [27 Translation-en store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 97% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 97% [28 Commands-amd64 store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 97% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 97% [29 Commands-amd64 store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 97% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 97% [30 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 97% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 97% [31 Translation-en store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 98% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 98% [32 Commands-amd64 store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 98% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 98% [33 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 98% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 98% [34 Translation-en store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 98% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 98% [35 Commands-amd64 store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 99% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 99% [36 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec):
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 99% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 99% [37 Translation-en store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 99% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 99% [38 Commands-amd64 store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 99% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 99% [39 Packages store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 100% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 100% [40 Translation-en store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 100% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 100% [41 Commands-amd64 store 0 B]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 100% [Working]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Fetched 26.3 MB in 5s (5847 kB/s)
azurerm_linux_virtual_machine.my_terraform_vm: Still creating... [1m0s elapsed]
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 0%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 0%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 0%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 4%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 4%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 6%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 6%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 7%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 7%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 7%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 7%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 50%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 50%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 71%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 71%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 71%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 71%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 72%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 72%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 75%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 75%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 77%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 77%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 80%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 80%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 81%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 81%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 85%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 85%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 86%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 86%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 86%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 86%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 86%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 86%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 87%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 87%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 87%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 87%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 87%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 87%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 87%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 87%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 89%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 89%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 91%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 91%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 94%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 94%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 95%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 95%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 98%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 98%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 99%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 99%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 99%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 99%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 99%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 99%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... Done
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Building dependency tree... 0%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Building dependency tree... 0%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Building dependency tree... 0%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Building dependency tree... 50%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Building dependency tree... 50%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Building dependency tree... Done
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading state information... 0%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading state information... 0%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading state information... Done
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 21 packages can be upgraded. Run 'apt list --upgradable' to see them.
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 0%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... 100%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading package lists... Done
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Building dependency tree... 0%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Building dependency tree... 0%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Building dependency tree... 50%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Building dependency tree... 50%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Building dependency tree... Done
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading state information... 0%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading state information... 0%
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Reading state information... Done
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): python3 is already the newest version (3.10.6-1~22.04).
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): python3 set to manually installed.
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): 0 upgraded, 0 newly installed, 0 to remove and 21 not upgraded.
azurerm_linux_virtual_machine.my_terraform_vm (remote-exec): Done!
azurerm_linux_virtual_machine.my_terraform_vm: Provisioning with 'local-exec'...
azurerm_linux_virtual_machine.my_terraform_vm (local-exec): Executing: ["/bin/sh" "-c" "ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -u azureuser -i '20.163.139.190,' --private-key ./id_rsa -e 'pub_key=./id_rsa.pub' ./local_co/cloudcustodian.yaml"]

azurerm_linux_virtual_machine.my_terraform_vm (local-exec): PLAY [Install Cloud Custodian] *************************************************

azurerm_linux_virtual_machine.my_terraform_vm (local-exec): TASK [Gathering Facts] *********************************************************
azurerm_linux_virtual_machine.my_terraform_vm: Still creating... [1m10s elapsed]
azurerm_linux_virtual_machine.my_terraform_vm (local-exec): ok: [20.163.139.190]

azurerm_linux_virtual_machine.my_terraform_vm (local-exec): TASK [Install Python3] *********************************************************
azurerm_linux_virtual_machine.my_terraform_vm: Still creating... [1m20s elapsed]
azurerm_linux_virtual_machine.my_terraform_vm: Still creating... [1m30s elapsed]
azurerm_linux_virtual_machine.my_terraform_vm: Still creating... [1m40s elapsed]
azurerm_linux_virtual_machine.my_terraform_vm (local-exec): changed: [20.163.139.190]

azurerm_linux_virtual_machine.my_terraform_vm (local-exec): TASK [Check Version] ***********************************************************
azurerm_linux_virtual_machine.my_terraform_vm (local-exec): changed: [20.163.139.190]

azurerm_linux_virtual_machine.my_terraform_vm (local-exec): TASK [Install Custodian locally] ***********************************************
azurerm_linux_virtual_machine.my_terraform_vm: Still creating... [1m50s elapsed]
azurerm_linux_virtual_machine.my_terraform_vm (local-exec): changed: [20.163.139.190]

azurerm_linux_virtual_machine.my_terraform_vm (local-exec): TASK [Add Cloud Modules to Local] **********************************************
azurerm_linux_virtual_machine.my_terraform_vm: Still creating... [2m0s elapsed]
azurerm_linux_virtual_machine.my_terraform_vm: Still creating... [2m10s elapsed]
azurerm_linux_virtual_machine.my_terraform_vm: Still creating... [2m20s elapsed]
azurerm_linux_virtual_machine.my_terraform_vm: Still creating... [2m30s elapsed]
azurerm_linux_virtual_machine.my_terraform_vm: Still creating... [2m40s elapsed]
azurerm_linux_virtual_machine.my_terraform_vm: Still creating... [2m50s elapsed]
azurerm_linux_virtual_machine.my_terraform_vm (local-exec): changed: [20.163.139.190]

azurerm_linux_virtual_machine.my_terraform_vm (local-exec): TASK [Pull Docker Image] *******************************************************
azurerm_linux_virtual_machine.my_terraform_vm (local-exec): fatal: [20.163.139.190]: FAILED! => {"changed": true, "cmd": "docker pull cloudcustodian/c7n  \n", "delta": "0:00:00.003240", "end": "2023-03-26 23:51:26.642022", "msg": "non-zero return code", "rc": 127, "start": "2023-03-26 23:51:26.638782", "stderr": "/bin/sh: 1: docker: not found", "stderr_lines": ["/bin/sh: 1: docker: not found"], "stdout": "", "stdout_lines": []}

azurerm_linux_virtual_machine.my_terraform_vm (local-exec): PLAY RECAP *********************************************************************
azurerm_linux_virtual_machine.my_terraform_vm (local-exec): 20.163.139.190             : ok=5    changed=4    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

╷
│ Error: local-exec provisioner error
│
│   with azurerm_linux_virtual_machine.my_terraform_vm,
│   on main.tf line 176, in resource "azurerm_linux_virtual_machine" "my_terraform_vm":
│  176:   provisioner "local-exec" {
│
│ Error running command 'ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -u azureuser -i '20.163.139.190,'
│ --private-key ./id_rsa -e 'pub_key=./id_rsa.pub' ./local_co/cloudcustodian.yaml': exit status 2. Output:
│ PLAY [Install Cloud Custodian] *************************************************
│
│ TASK [Gathering Facts] *********************************************************
│ ok: [20.163.139.190]
│
│ TASK [Install Python3] *********************************************************
│ changed: [20.163.139.190]
│
│ TASK [Check Version] ***********************************************************
│ changed: [20.163.139.190]
│
│ TASK [Install Custodian locally] ***********************************************
│ changed: [20.163.139.190]
│
│ TASK [Add Cloud Modules to Local] **********************************************
│ changed: [20.163.139.190]
│
│ TASK [Pull Docker Image] *******************************************************
│ fatal: [20.163.139.190]: FAILED! => {"changed": true, "cmd": "docker pull cloudcustodian/c7n  \n", "delta":
│ "0:00:00.003240", "end": "2023-03-26 23:51:26.642022", "msg": "non-zero return code", "rc": 127, "start": "2023-03-26
│ 23:51:26.638782", "stderr": "/bin/sh: 1: docker: not found", "stderr_lines": ["/bin/sh: 1: docker: not found"],
│ "stdout": "", "stdout_lines": []}
│
│ PLAY RECAP *********************************************************************
│ 20.163.139.190             : ok=5    changed=4    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0
│
│

I need to add Docker to the playbook for the Cloud Custodian install to work, but you get the idea.

Locally I can see the repo created, however, my PAT is stored in the URL so that would be something I would want to hide

builder@DESKTOP-72D2D9T:~/Workspaces/tfAnsibleAzure$ ls
apache-install.yml  id_rsa.pub  main.tf     providers.tf       terraform.tfstate.backup
id_rsa              local_co    outputs.tf  terraform.tfstate  variables.tf
builder@DESKTOP-72D2D9T:~/Workspaces/tfAnsibleAzure$ cd local_co
builder@DESKTOP-72D2D9T:~/Workspaces/tfAnsibleAzure/local_co$ git remote show origin
* remote origin
  Fetch URL: https://idjohnson:ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@github.com/idjohnson/ansible-playbooks
  Push  URL: https://idjohnson:ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@github.com/idjohnson/ansible-playbooks
  HEAD branch: main
  Remote branches:
    main       tracked
    no-traefik tracked
  Local branch configured for 'git pull':
    main merges with remote main
  Local ref configured for 'git push':
    main pushes to main (up to date)

TF Cloud

Let’s create a token with https://app.terraform.io/app/settings/tokens?source=terraform-login.

/content/images/2023/03/ansiblegit-02.png

This will create a token we can use

/content/images/2023/03/ansiblegit-04.png

I can paste that into the terminal

/content/images/2023/03/ansiblegit-05.png

That will store it locally

$ cat /home/builder/.terraform.d/credentials.tfrc.json
{
  "credentials": {
    "app.terraform.io": {
      "token": "b****************************************************************************************************************I"
    }
  }
}

Next, I’ll need a Workspace to use. I can go to the Workspaces area and create a new one

/content/images/2023/03/ansiblegit-06.png

Terraform Cloud: Verson Control workflow

Let’s start by using the “Version control workflow”

/content/images/2023/03/ansiblegit-07.png

connect to Github

/content/images/2023/03/ansiblegit-08.png

And I’ll leave mostly defaults and create workspace

/content/images/2023/03/ansiblegit-09.png

Then I’ll start a new plan

/content/images/2023/03/ansiblegit-10.png

and start a run

/content/images/2023/03/ansiblegit-11.png

which fails

/content/images/2023/03/ansiblegit-12.png

This is because when I did this locally, I was able to use the Azure CLI logged in as myself. Now, I’ll want to use a Service Principal

I already have an App Registration with proper permissions, but an expired cred

/content/images/2023/03/ansiblegit-13.png

Then I can create a new secret

/content/images/2023/03/ansiblegit-14.png

I’ll try setting the ENV Vars as Workspace Variables in TF Cloud

/content/images/2023/03/ansiblegit-15.png

Now when I start a Plan, we see it passes that issue with Azure and Shows everything it intends to create

/content/images/2023/03/ansiblegit-16.png

I confirmed and applied

/content/images/2023/03/ansiblegit-17.png

Which created the objects

/content/images/2023/03/ansiblegit-18.png

When complete, I could see the listing in TF Cloud of what it created, but also what we cannot do

/content/images/2023/03/ansiblegit-19.png

The fact is, the local-exec block of running ‘ansible-playbook’;


  provisioner "remote-exec" {
    inline = ["sudo apt update", "sudo apt install python3 -y", "echo Done!"]

    connection {
      host        = azurerm_linux_virtual_machine.my_terraform_vm.public_ip_address
      type        = "ssh"
      user        = "azureuser"
      private_key = tls_private_key.example_ssh.private_key_pem
    }
  }

  provisioner "local-exec" {
    command = "ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -u azureuser -i '${azurerm_linux_virtual_machine.my_terraform_vm.public_ip_address},' --private-key ${local_file.idrsa.filename} -e 'pub_key=${local_file.idrsapub.filename}' apache-install.yml"
    
  }

Will just not work because TF Cloud doesn’t have that binary locally

/content/images/2023/03/ansiblegit-20.png

I should expect the same issues with the “clone_with_github” branch

To test, I’ll switch to that branch in the Workspace

/content/images/2023/03/ansiblegit-21.png

And start a new run, which I can see uses that branch

/content/images/2023/03/ansiblegit-22.png

Ah - Recall that we created a secret in AKV and that my locally logged in user could reach it. In order to allow the SP used by TF Cloud to use it, we’ll need to add permissions

I’ll set a Key and Secret Permission template for the Access Policy in Azure Key Vault

/content/images/2023/03/ansiblegit-23.png

Knowing the right SP is easy as I can copy and paste the Object ID shown in the TF Cloud error (which I masked in the screenshot) into the search and it comes right up

/content/images/2023/03/ansiblegit-24.png

Then create

/content/images/2023/03/ansiblegit-25.png

Now my plan can access AKV

/content/images/2023/03/ansiblegit-26.png

I can watch in the Azure Portal as TF Cloud removes and re-adds the VM

/content/images/2023/03/ansiblegit-27.png

It hung and after 20m I needed to cancel it

/content/images/2023/03/ansiblegit-28.png

I could comment everything out, do a run, which would scrub it all, then undo and do a follow-up run. This would work to refresh things, however I could save myself some time, and just delete the RG in Azure:

/content/images/2023/03/ansiblegit-29.png

Then do a fresh plan. Before I do the new plan, however, Let’s fix what we know will be an issue - running Ansible LOCALLY.

It’s a bit zany, but our destination host is a Linux machine. Adding ansible to self-provision (akin to Chef Zero/Solo), is rather easy;

I’ll comment out the clone (since I don’t need it), but then move it into the remote-exec block. This means I also need to install Ansible on the fly. Lastly, I need to remove the “depends_on” since I no longer depend on cloning a GIT repo


#pull the code from github
/*
resource "null_resource" "git_clone" {
  provisioner "local-exec" {
    command = "git clone https://idjohnson:${data.azurerm_key_vault_secret.ghpassword.value}@github.com/idjohnson/ansible-playbooks ./local_co"
  }
}
*/

# Create virtual machine

resource "azurerm_linux_virtual_machine" "my_terraform_vm" {
  name                  = "myVM"
  location              = azurerm_resource_group.rg.location
  resource_group_name   = azurerm_resource_group.rg.name
  network_interface_ids = [azurerm_network_interface.my_terraform_nic.id]
  size                  = "Standard_DS1_v2"

  os_disk {
    name                 = "myOsDisk"
    caching              = "ReadWrite"
    storage_account_type = "Premium_LRS"
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "0001-com-ubuntu-server-jammy"
    sku       = "22_04-lts-gen2"
    version   = "latest"
  }

  computer_name                   = "myvm"
  admin_username                  = "azureuser"
  disable_password_authentication = true

  admin_ssh_key {
    username   = "azureuser"
    public_key = tls_private_key.example_ssh.public_key_openssh
  }

  boot_diagnostics {
    storage_account_uri = azurerm_storage_account.my_storage_account.primary_blob_endpoint
  }

  provisioner "remote-exec" {
    inline = [
      "sudo apt-add-repository -y ppa:ansible/ansible", 
      "sudo apt update",
      "sudo apt install python3 build-essential python-dev ansible -y", 
      "git clone https://idjohnson:${data.azurerm_key_vault_secret.ghpassword.value}@github.com/idjohnson/ansible-playbooks ./local_co",
      "ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -u azureuser -i '${azurerm_linux_virtual_machine.my_terraform_vm.public_ip_address},' --private-key ${local_file.idrsa.filename} -e 'pub_key=${local_file.idrsapub.filename}' ./local_co/cloudcustodian.yaml",      
      "echo Done!"
    ]

    connection {
      host        = azurerm_linux_virtual_machine.my_terraform_vm.public_ip_address
      type        = "ssh"
      user        = "azureuser"
      private_key = tls_private_key.example_ssh.private_key_pem
    }
  }

  // depends_on = [ null_resource.git_clone ]
}

The new Plan run shows it will create everything. The “Destroy” is kind of funny as it really just means it won’t run the “null” resource block

/content/images/2023/03/ansiblegit-30.png

If I want to debug it, I have a bit of an issue in that I cannot see the Private PEM created (as I could locally). However, I can reset the password for the azureuser user;

/content/images/2023/03/ansiblegit-31.png

Then SSH directly

/content/images/2023/03/ansiblegit-32.png

This let me figure out I missed the “-y” in the add apt-add-repo command

/content/images/2023/03/ansiblegit-33.png

And that python-dev is no longer valid in Ubuntu Jammy.

azureuser@myvm:~$ sudo apt install python3 build-essential python-dev ansible -y
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Package python-dev is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source
However the following packages replace it:
  python2-dev python2 python-dev-is-python3

E: Package 'python-dev' has no installation candidate

I removed it (figuring it wasn’t really needed anyway). I made a few more changes.

$ git diff -C4
diff --git a/main.tf b/main.tf
index 00cdbb5..79ebd0f 100644
--- a/main.tf
+++ b/main.tf
@@ -166,10 +166,10 @@ resource "azurerm_linux_virtual_machine" "my_terraform_vm" {
 
   provisioner "remote-exec" {
     inline = [
-      "sudo apt-add-repository ppa:ansible/ansible", 
+      "sudo apt-add-repository -y ppa:ansible/ansible", 
       "sudo apt update",
-      "sudo apt install python3 build-essential python-dev ansible -y", 
-      "git clone https://idjohnson:${data.azurerm_key_vault_secret.ghpassword.value}@github.com/idjohnson/ansible-playbooks ./local_co",
+      "sudo apt install python3 build-essential ansible -y", 
+      "git clone https://github.com/idjohnson/ansible-playbooks ./local_co",
       "ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -u azureuser -i '${azurerm_linux_virtual_machine.my_terraform_vm.public_ip_address},' --private-key ${local_file.idrsa.filename} -e 'pub_key=${local_file.idrsapub.filename}' ./local_co/cloudcustodian.yaml",      
       "echo Done!"
     ]

To make sure it ran fresh, I stopped everything and deleted the VM to try again.

/content/images/2023/03/ansiblegit-34.png

Basically, I must do this since by setting a password I enabled password on the box which will then make sudo require one if I re-run.

/content/images/2023/03/ansiblegit-35.png

What is nice is that because I removed the secrets from the remote-exec, I can now see output

/content/images/2023/03/ansiblegit-36.png

This clued me into the issue of using localhost with playbooks set to “all”

  Resolving deltas: 100% (103/103)
  Resolving deltas: 100% (103/103), done.
  [WARNING]: provided hosts list is empty, only localhost is available. Note that
  the implicit localhost does not match 'all'
  PLAY [Install Cloud Custodian] *************************************************
  skipping: no hosts matched
  PLAY RECAP *********************************************************************
  Done!

I can do some testing now as I’ve saved the Private key into AKV at create time;

/content/images/2023/03/ansiblegit-37.png

builder@DESKTOP-QADGF36:~/Workspaces/tfAnsibleAzure$ vi test.pem
builder@DESKTOP-QADGF36:~/Workspaces/tfAnsibleAzure$ chmod 600 ./test.pem
builder@DESKTOP-QADGF36:~/Workspaces/tfAnsibleAzure$ ssh -i ./test.pem azureuser@172.174.88.106
The authenticity of host '172.174.88.106 (172.174.88.106)' can't be established.
ECDSA key fingerprint is SHA256:eSrweewSI7qzZpsT7LVWdajtK5eDcbqo9av+6YucNtU.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '172.174.88.106' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 22.04.2 LTS (GNU/Linux 5.15.0-1035-azure x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Thu Mar 30 14:37:52 UTC 2023

  System load:  0.0               Processes:             99
  Usage of /:   7.7% of 28.89GB   Users logged in:       0
  Memory usage: 11%               IPv4 address for eth0: 10.0.1.4
  Swap usage:   0%


Expanded Security Maintenance for Applications is not enabled.

3 updates can be applied immediately.
To see these additional updates run: apt list --upgradable

1 additional security update can be applied with ESM Apps.
Learn more about enabling ESM Apps service at https://ubuntu.com/esm


Last login: Thu Mar 30 14:15:53 2023 from 3.216.132.92
azureuser@myvm:~$

I was able to figure out a way to trigger it locally

azureuser@myvm:~$ echo -e "[all]\nlocalhost" > myhosts.ini
azureuser@myvm:~$ cat myhosts.ini
[all]
localhost
azureuser@myvm:~$ ansible-playbook -i myhosts.ini --connection=local ./local_co/cloudcustodian.yaml

PLAY [Install Cloud Custodian] *****************************************************************************************

TASK [Gathering Facts] *************************************************************************************************
ok: [localhost]

TASK [Install Python3] *************************************************************************************************
changed: [localhost]
...snip....

It’s worth pointing out that because this is a provision block at create time, just updating the block will not trigger the VM to update

/content/images/2023/03/ansiblegit-38.png

To force an update, you’ll need to delete the VM and refire the plan. Arguably, if you plan to regularly update hosts with tools, then you likely want to either create a pipeline with Packer or switch to using AWX to easily apply playbooks on-demand.

Playbook improvements

Realizing this particular playbook, my cloud custodian, did both non-docker and docker versions in one, rather unneccessarily, I moved to a two playbook model;

$ cat cloudcustodian.yaml
---
- name: Install Cloud Custodian
  hosts: all

  tasks:
  - name: Install Python3
    ansible.builtin.shell: |
      apt-get install -y python3 python3-venv python3-pip
    become: true
    args:
      chdir: /tmp

  - name: Check Version
    ansible.builtin.shell: |
      python3 -m pip --version
    args:
      chdir: /tmp

  - name: Install Custodian locally
    ansible.builtin.shell: |
      umask 0002
      python3 -m venv custodian
      source custodian/bin/activate
      pip install c7n  
    become: true
    args:
      chdir: /tmp

  - name: Add Cloud Modules to Local
    ansible.builtin.shell: |
      umask 0002
      python3 -m venv custodian
      source custodian/bin/activate
      pip install requests
      pip install msrest
      pip install c7n-azure  
      pip install c7n-gcp  
    become: true
    args:
      chdir: /tmp

Then the docker one, which would install docker AND use root the first time

$ cat cloudcustodiandocker.yaml
---
- name: Install Cloud Custodian Docker
  hosts: all

  tasks:
  - name: Install dockerio
    ansible.builtin.shell: |
      apt update
      apt install -y docker.io
    become: true
    args:
      chdir: /tmp

  - name: Install docker snap
    ansible.builtin.shell: |
      apt update
      snap install docker
    become: true
    args:
      chdir: /tmp
  
  # must be root the first time. later we can add to docker group
  - name: Pull Docker Image
    ansible.builtin.shell: |
      docker pull cloudcustodian/c7n  
    become: true
    args:
      chdir: /tmp

I then stripped out the docker steps from my provisioner block and used the new playbook

  provisioner "remote-exec" {
    inline = [
      "sudo apt-add-repository -y ppa:ansible/ansible", 
      "sudo apt update",
      "sudo apt install python3 build-essential ansible -y", 
      "git clone https://github.com/idjohnson/ansible-playbooks ./local_co",
      "echo -e '[all]\nlocalhost' > myhosts.ini",
      "ansible-playbook -i myhosts.ini --connection=local ./local_co/cloudcustodiandocker.yaml",      
      "echo Done!"
    ]

Which after fixing a minor issue in the ini file worked:

azureuser@myvm:~$ ansible-playbook -i myhosts.ini --connection=local ./local_co/cloudcustodiandocker.yaml

PLAY [Install Cloud Custodian Docker] **********************************************************************************

TASK [Gathering Facts] *************************************************************************************************
ok: [localhost]

TASK [Install dockerio] ************************************************************************************************
changed: [localhost]

TASK [Install docker snap] *********************************************************************************************
changed: [localhost]

TASK [Pull Docker Image] ***********************************************************************************************
changed: [localhost]

PLAY RECAP *************************************************************************************************************
localhost                  : ok=4    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

This demonstrates a key element of the model; determining what belongs in terraform versus what belongs in Ansible.

One’s playbooks should be clear on their dependencies. If they use docker, is it required or will it be setup? And arguably, if you are only deploying a containerized app, then is it really an Infrastructure play or a Pipeline Deployment using something like Github Actions, Gitlab Runners or Azure DevOps?

And, lest I neglect one of the smaller Hashi products, is this better suited to Nomad for deployment.

Some of the ways you can tease that out is by asking:

  1. Will this thing I’m setting up be deployed regularily?
    1. such as Application containers
    2. or security updates
    3. This is a good case for scheduled jobs in AWX or AzDO
  2. Is it married in lock-step with the platform?
    1. such as core OS features or User Provisioning
    2. This is a good case for applying in Terraform at creation
  3. Is it Optional - I only sometimes want it added
    1. such as a application stack that affects only some servers
    2. This is a good case for using a playbook applied by AWX

Summary

From The first post we setup Terraform locally (using TFEnv) and created a stack of Azure resources to host a VM. We expanded this to have multiple files and install things like python inline with remote-exec and wrapped with local-exec invocations of ansible-playbooks. This was fine for local development, but wouldn’t really scale.

Today we expanded this to pull from Github (and a private repo at that) by using a GH PAT we stored in AKV. We then showed we could pull a set of Playbooks from GIT and run them locally. Moving on, we tackled setting up Terraform Cloud and worked our terraform to a point we could fetch and run playbooks during create time remotely.

This isn’t the first time we’ve discussed Terraform Cloud. I wrote about it in Jan 2021 shortly after it rolled out and again during HC2022 when they added OPA support. However, I cannot stress enough what am amazing offering TF Cloud is. I put it on the same shelf as Azure DevOps, Github and Gitlab as amazing full featured services that have incredibly useful low-cost/free tiers.

Terraform Ansible Azure Github

Have something to add? Feedback? Try our new forums

Isaac Johnson

Isaac Johnson

Cloud Solutions Architect

Isaac is a CSA and DevOps engineer who focuses on cloud migrations and devops processes. He also is a dad to three wonderful daughters (hence the references to Princess King sprinkled throughout the blog).

Theme built by C.S. Rhymes