Creating a CIS Benchmark VM from Terraform

I am trying to find a way to create a hardened VM that’s available from Microsoft’s Azure Marketplace. I am not able to find the necessary sku for our TF script. Is there an example how to create a CIS Benchmark VM image from Azure?
Thanks

Add these blocks to your azurerm_virtual_machine resource. You need both.

storage_image_reference {
    offer     = var.source_image_offer     //which is "cis-centos-7-l1"
    publisher = var.source_image_publisher //which is "center-for-internet-security-inc"
    sku       = var.source_image_sku       //which is "cis-centos75-l1"
    version   = "latest"
  }

plan { // Think of this as the mobile phone plan you choose with your new phone
    name      = var.source_image_sku
    publisher = var.source_image_publisher
    product   = var.source_image_offer
  }

For actually finding the images you want I would refer you to this documentation from Microsoft. Also remember to accept the Terms beforehand.

1 Like

Wow, thank you so much for the quick reply. I added the plan block as you suggested and I also updated our TF client to the latest version (0.12.13) and the azurerm provider (1.36.1). I also followed those Microsoft links and ensured that programmatic access was enabled and accepted the terms per instructions. I am getting a different error that doesn’t make sense in that now I am adding a plan, but the error suggests a missing plan but not in the context of an update. I am not understanding how this error is being generated in light of having a plan. I will include below both the error and the snippets of terraform script showing what I have.

Again, thank you so much for replying so quickly and any help would be greatly appreciated.

Error: compute.VirtualMachinesClient#CreateOrUpdate: Failure sending request: StatusCode=400 -- Original Error: Code="CannotSetPlanOnUpdate" Message="This resource was created without a plan. A new plan cannot be associated with an update."

#Variables Definitions
variable "osPublisher" {
    default = "center-for-internet-security-inc"
              #center-for-internet-security-inc
}
variable "osTypeSku" {
    default = "cis-ws2019-l1"
              #cis-ws2019-l1
 }

variable "osProductOffer" {
     default = "cis-windows-server-2019-v1-0-0-l1"
               #cis-windows-server-2019-v1-0-0-l1
 }

resource "azurerm_virtual_machine" "WindowsServerCISL1" {
  name                          = "${var.name}"
  location                      = "${var.location}"
  resource_group_name           = "${var.resourceGroupName}"
  network_interface_ids         = ["${azurerm_network_interface.WindowsServerCISL1.id}"]
  vm_size                       = "${var.vmSize}"
  delete_os_disk_on_termination = true

  availability_set_id           = "${var.availabilitySetId}"

  storage_image_reference {
    publisher = "${var.osPublisher}"
    offer     = "${var.osProductOffer}"
    sku       = "${var.osSkuName}"
    version   = "1.0.1"
  }

  plan {
    publisher = "${var.osPublisher}"
    product   = "${var.osProductOffer}"
    name      = "${var.osSkuName}"
  }

Hmm, strange. First, the obvious mistake in the variable used for sku in your code above is “osTypeSku” not “osSkuName”.

This seems to be working fine for me (fill in the blanks and the network interface):

resource "azurerm_virtual_machine" "WindowsServerCISL1" {
  name                          = ""
  location                      = ""
  resource_group_name           = ""
  network_interface_ids         = ["${azurerm_network_interface.removed.id}"]
  vm_size                       = "Standard_B2ms"
  delete_os_disk_on_termination = true

  storage_image_reference {
    publisher = "${var.osPublisher}"
    offer     = "${var.osProductOffer}"
    sku       = "${var.osTypeSku}"
    version   = "1.0.1"
  }

  plan {
    publisher = "${var.osPublisher}"
    product   = "${var.osProductOffer}"
    name      = "${var.osTypeSku}"
  }

  storage_os_disk {
    name              = ""
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Standard_LRS"
  }

  os_profile {
    computer_name  = ""
    admin_username = ""
    admin_password = ""
  }

  os_profile_windows_config {}
}
1 Like

SuHwak,

Thank you so much again. After looking closer and with head scratching, I found the issue I was having. The first time creating the VM in TF, it failed due to not having the plan in place. I would “clean” out my attempted failed VM by “destroying” it and starting over. However, upon looking at the Azure portal, the VM was actually created without being removed when I “destroyed” it having a status of “failed” in the portal. I manually removed any instances of resources created by TF and then upon re-running everything worked perfectly.

Again, thank you so much for helping in such a timely manner. (btw, my variables names you mentioned was due to another module whose variables were named different. Thanks for pointing that out since I like consistency among my variables.)

Gregg