Search code examples
linuxazuresshterraformazure-rm

Terraform Azurerm - timeout - last error: SSH authentication failed


Im new to terraform azure-rm. My goal is to up a VM and run a provisioning script on Azure Cloud, running the terraform from a windows machine. For the past few weeks, I have been stuck on the following error:

 Error: remote-exec provisioner error
│
│   with azurerm_linux_virtual_machine.tm_vm,
│   on main.tf line 162, in resource "azurerm_linux_virtual_machine" "tm_vm":
│  162:   provisioner "remote-exec" {
│
│ timeout - last error: SSH authentication failed ([email protected]:22): ssh: handshake failed: ssh: unable to authenticate, attempted methods [none 
│ publickey], no supported methods remain

Below is my main.tf:

# find public ip via $terraform state show azurerm_linux_virtual_machine.tm_vm

# We strongly recommend using the required_providers block to set the
# Azure Provider source and version being used
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "=3.0.0"
    }
  }
}

# Configure the Microsoft Azure Provider
provider "azurerm" {
  features {
  }
}

# Create a resource group
resource "azurerm_resource_group" "tm_resources" {
  name     = "triplem_resources"
  location = "East Us"
  tags = {
    environment = "dev"
  }
}

# Create virtual network
resource "azurerm_virtual_network" "tm_virtualnet" {
  name                = "triplem_network"
  resource_group_name = azurerm_resource_group.tm_resources.name
  location            = azurerm_resource_group.tm_resources.location
  address_space       = ["10.123.0.0/16"]

  tags = {
    environment = "dev"
  }
}

# Create Subnet
resource "azurerm_subnet" "tm_subnet" {
  name                 = "tm_subnet"
  resource_group_name  = azurerm_resource_group.tm_resources.name
  virtual_network_name = azurerm_virtual_network.tm_virtualnet.name
  address_prefixes     = ["10.123.1.0/24"]
}

# Create security group
resource "azurerm_network_security_group" "tm_security_group" {
  name                = "tm_security_group"
  location            = azurerm_resource_group.tm_resources.location
  resource_group_name = azurerm_resource_group.tm_resources.name

  tags = {
    environment = "dev"
  }
}

# Security group rules
resource "azurerm_network_security_rule" "tm_dev_rule" {
  name                        = "tm_dev_rule"
  priority                    = 100
  direction                   = "Inbound"
  access                      = "Allow"
  protocol                    = "*"
  source_port_range           = "*"
  destination_port_range      = "*"
  source_address_prefix       = "*" #<-- add my ip
  destination_address_prefix  = "*"
  resource_group_name         = azurerm_resource_group.tm_resources.name
  network_security_group_name = azurerm_network_security_group.tm_security_group.name
}

resource "azurerm_subnet_network_security_group_association" "tm_security_group_association" {
  subnet_id                 = azurerm_subnet.tm_subnet.id
  network_security_group_id = azurerm_network_security_group.tm_security_group.id
}

resource "azurerm_public_ip" "tm_ip" {
  name                    = "tm_ip"
  location                = azurerm_resource_group.tm_resources.location
  resource_group_name     = azurerm_resource_group.tm_resources.name
  allocation_method       = "Static"
  idle_timeout_in_minutes = 30

  tags = {
    environment = "dev"
  }
}

resource "azurerm_network_interface" "tm_net_interface" {
  name                = "tm_net_interface"
  location            = azurerm_resource_group.tm_resources.location
  resource_group_name = azurerm_resource_group.tm_resources.name

  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.tm_subnet.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.tm_ip.id
  }

  tags = {
    environment = "dev"
  }
}

# RSA key of size 4096 bits
resource "tls_private_key" "key_generation" {
  algorithm = "RSA"
  rsa_bits  = 4096
}

# Save key locally
resource "local_file" "tm_key" {
  filename = "${var.compute_name}_key.pem"
  content  = tls_private_key.key_generation.private_key_pem
}

# template provision file
data "template_file" "provision_file" {
  template = file("provision.tpl")
  vars     = {}
}

resource "null_resource" "test" {
  provisioner "local-exec" {
    command = "echo ${data.azurerm_public_ip.data_public_ip.ip_address}"
  }
}

# Create VM
resource "azurerm_linux_virtual_machine" "tm_vm" {
  name                  = var.compute_name
  resource_group_name   = azurerm_resource_group.tm_resources.name
  location              = azurerm_resource_group.tm_resources.location
  size                  = "Standard_F2"
  admin_username        = "linuxuser"
  network_interface_ids = [azurerm_network_interface.tm_net_interface.id]

  # Run Node Provision Script
  # custom_data = filebase64("provision.tpl")

  admin_ssh_key {
    username   = "linuxuser"
    public_key = tls_private_key.key_generation.public_key_openssh
  }

  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "16.04-LTS"
    version   = "latest"
  }

  provisioner "remote-exec" {
    inline = ["${data.template_file.provision_file.rendered}"]

    connection {
      host        = data.azurerm_public_ip.data_public_ip.ip_address
      type        = "ssh"
      user        = "linxuser"
      private_key = tls_private_key.key_generation.private_key_pem
      timeout     = "5m"
    }
  }

  depends_on = [
    azurerm_network_interface.tm_net_interface,
  ]
}

data "azurerm_public_ip" "data_public_ip" {
  name                = azurerm_public_ip.tm_ip.name
  resource_group_name = azurerm_public_ip.tm_ip.resource_group_name
}

output "print_public_ip" {
  value = data.azurerm_public_ip.data_public_ip.ip_address
}

# Run provision
# resource "null_resource" "provision" {
#   depends_on = [azurerm_linux_virtual_machine.tm_vm, data.azurerm_public_ip.data_public_ip, null_resource.test]

#   provisioner "remote-exec" {
#     inline = ["${data.template_file.provision_file.rendered}"]
#   }

#   connection {
#     host        = "${data.azurerm_public_ip.data_public_ip.ip_address}"
#     type        = "ssh"
#     user        = "linxuser"
#     private_key = file("C:/Users/wongm/Documents/GitHub/triple-m/terraform-azure/key")#tls_private_key.key_generation.private_key_pem
#     timeout "5m"
#   }
# }

Things I have tried:

  • Dynamic vs Static public IP allocation (stuck with static)
  • Manually generating key
  • Setting permission 600 on manual key
  • Setting dependency between remote-exec and azurerm_linux_virtual_machine
  • moving provision into azurerm_linux_virtual_machine block

Any help would be greatly appreciated!


Solution

  • Based on your error message it looks like your issue is simply with authentication to the server itself:

    timeout - last error: SSH authentication failed ([email protected]:22): ssh: handshake failed: ssh: unable to authenticate, attempted methods [none │ publickey], no supported methods remain

    The first item that jumps out is the potential misspelling of the username. Is the user actually supposed to be "linuxuser" vs "linxuser"?

    As a first step, I would verify the username is correct and the SSH key exists in the location you specified.

    Next, try to SSH to the server using the username and SSH key combination. This will depend upon your setup (looks as though you're on Windows). If using openssh it will simply be something like "***ssh -i keyfile username@server_ip"

    I can replicate your error message if I have a username on the server of "linuxuser" yet set the username in the terraform to "linxuser":

    timeout - last error: SSH authentication failed (linxuser@REMOVED:22): ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain

    Once I correct the username everything proceeds as intended.

    Good luck!