Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SSH connection to Azure VM with Terraform

I have successfully created a VM as part of a Resource Group on Azure using Terraform. Next step is to ssh in the new machine and run a few commands. For that, I have created a provisioner as part of the VM resource and set up an SSH connection:

resource "azurerm_virtual_machine" "helloterraformvm" {
    name = "terraformvm"
    location = "West US"
    resource_group_name = "${azurerm_resource_group.helloterraform.name}"
    network_interface_ids = ["${azurerm_network_interface.helloterraformnic.id}"]
    vm_size = "Standard_A0"

    storage_image_reference {
        publisher = "Canonical"
        offer = "UbuntuServer"
        sku = "14.04.2-LTS"
        version = "latest"
    }


    os_profile {
        computer_name = "hostname"
        user     = "some_user"
        password = "some_password"
    }

    os_profile_linux_config {
        disable_password_authentication = false
    }

    provisioner "remote-exec" {
        inline = [
          "sudo apt-get install docker.io -y"
        ]
        connection {
          type     = "ssh"
          user     = "some_user"
          password = "some_password"
        }
    }

}

If I run "terraform apply", it seems to get into an infinite loop trying to ssh unsuccessfully, repeating this log over and over:

azurerm_virtual_machine.helloterraformvm (remote-exec): Connecting to remote host via SSH...
azurerm_virtual_machine.helloterraformvm (remote-exec):   Host:
azurerm_virtual_machine.helloterraformvm (remote-exec):   User: testadmin
azurerm_virtual_machine.helloterraformvm (remote-exec):   Password: true
azurerm_virtual_machine.helloterraformvm (remote-exec):   Private key: false
azurerm_virtual_machine.helloterraformvm (remote-exec):   SSH Agent: true

I'm sure I'm doing something wrong, but I don't know what it is :(

EDIT:

I have tried setting up this machine without the provisioner, and I can SSH to it no problems with the given username/passwd. However I need to look up the host name in the Azure portal because I don't know how to retrieve it from Terraform. It's suspicious that the "Host:" line in the log is empty, so I wonder if it has anything to do with that?

UPDATE:

I've tried with different things like indicating the host name in the connection with

host = "${azurerm_public_ip.helloterraformip.id}" 

and

host = "${azurerm_public_ip.helloterraformips.ip_address}"

as indicated in the docs, but with no success.

I've also tried using ssh-keys instead of password, but same result - infinite loop of connection tries, with no clear error message as of why it's not connecting.

like image 222
zapatilla Avatar asked Jul 09 '17 14:07

zapatilla


People also ask

Can you use SSH keys to connect to an Azure virtual machine?

Azure currently supports SSH protocol 2 (SSH-2) RSA public-private key pairs with a minimum length of 2048 bits. Other key formats such as ED25519 and ECDSA are not supported.

Can I manually SSH into a VM using terraform?

I am new at Terraform and would like some help. I have successfully created a VM and can manually SSH into it with no problem. The issue is I am working with a team on a project and they can't do any changes to the Tf files without making Terraform delete all the resources and recreating them.

How to install SSH key in Azure DevOps?

Copy the private key file created in the previous step id_rsa into azure pipelines -> Library -> Secure files. The file can be renamed to make it more friendly to use later on in the Install SSH Key devops task. In my case I have renamed my private key to terraform_rsa. Under the user settings in Azure Devops go to SSH public keys and select Add.

How do I run terraform code from Azure DevOps pipeline?

When using an Azure DevOps pipeline to execute terraform code from a DevOps agent referencing an Azure Devops git Repo as a module source, we can make use of the Install SSH Key devops task to install the SSH key pair we just created onto the DevOps agent that will be executing the terraform code. We will create a few variables next.

How to save terraform file to Azure Storage?

Save it as a file named script.sh and save it to Azure Storage account or GitHub (The file should be public). Modify terraform file like below:


1 Answers

I have managed to make this work. I changed several things:

  • Gave name of host to connection.
  • Configured SSH keys properly - they need to be unencrypted.
  • Took the connection element out of the provisioner element.

Here's the full working Terraform file, replacing the data like SSH keys, etc.:

# Configure Azure provider
provider "azurerm" {
  subscription_id = "${var.azure_subscription_id}"
  client_id       = "${var.azure_client_id}"
  client_secret   = "${var.azure_client_secret}"
  tenant_id       = "${var.azure_tenant_id}"
}

# create a resource group if it doesn't exist
resource "azurerm_resource_group" "rg" {
    name = "sometestrg"
    location = "ukwest"
}

# create virtual network
resource "azurerm_virtual_network" "vnet" {
    name = "tfvnet"
    address_space = ["10.0.0.0/16"]
    location = "ukwest"
    resource_group_name = "${azurerm_resource_group.rg.name}"
}

# create subnet
resource "azurerm_subnet" "subnet" {
    name = "tfsub"
    resource_group_name = "${azurerm_resource_group.rg.name}"
    virtual_network_name = "${azurerm_virtual_network.vnet.name}"
    address_prefix = "10.0.2.0/24"
    #network_security_group_id = "${azurerm_network_security_group.nsg.id}"
}

# create public IPs
resource "azurerm_public_ip" "ip" {
    name = "tfip"
    location = "ukwest"
    resource_group_name = "${azurerm_resource_group.rg.name}"
    public_ip_address_allocation = "dynamic"
    domain_name_label = "sometestdn"

    tags {
        environment = "staging"
    }
}

# create network interface
resource "azurerm_network_interface" "ni" {
    name = "tfni"
    location = "ukwest"
    resource_group_name = "${azurerm_resource_group.rg.name}"

    ip_configuration {
        name = "ipconfiguration"
        subnet_id = "${azurerm_subnet.subnet.id}"
        private_ip_address_allocation = "static"
        private_ip_address = "10.0.2.5"
        public_ip_address_id = "${azurerm_public_ip.ip.id}"
    }
}

# create storage account
resource "azurerm_storage_account" "storage" {
    name = "someteststorage"
    resource_group_name = "${azurerm_resource_group.rg.name}"
    location = "ukwest"
    account_type = "Standard_LRS"

    tags {
        environment = "staging"
    }
}

# create storage container
resource "azurerm_storage_container" "storagecont" {
    name = "vhd"
    resource_group_name = "${azurerm_resource_group.rg.name}"
    storage_account_name = "${azurerm_storage_account.storage.name}"
    container_access_type = "private"
    depends_on = ["azurerm_storage_account.storage"]
}



# create virtual machine
resource "azurerm_virtual_machine" "vm" {
    name = "sometestvm"
    location = "ukwest"
    resource_group_name = "${azurerm_resource_group.rg.name}"
    network_interface_ids = ["${azurerm_network_interface.ni.id}"]
    vm_size = "Standard_A0"

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

    storage_os_disk {
        name = "myosdisk"
        vhd_uri = "${azurerm_storage_account.storage.primary_blob_endpoint}${azurerm_storage_container.storagecont.name}/myosdisk.vhd"
        caching = "ReadWrite"
        create_option = "FromImage"
    }

    os_profile {
        computer_name = "testhost"
        admin_username = "testuser"
        admin_password = "Password123"
    }

    os_profile_linux_config {
      disable_password_authentication = false
      ssh_keys = [{
        path     = "/home/testuser/.ssh/authorized_keys"
        key_data = "ssh-rsa xxx [email protected]"
      }]
    }

    connection {
        host = "sometestdn.ukwest.cloudapp.azure.com"
        user = "testuser"
        type = "ssh"
        private_key = "${file("~/.ssh/id_rsa_unencrypted")}"
        timeout = "1m"
        agent = true
    }

    provisioner "remote-exec" {
        inline = [
          "sudo apt-get update",
          "sudo apt-get install docker.io -y",
          "git clone https://github.com/somepublicrepo.git",
          "cd Docker-sample",
          "sudo docker build -t mywebapp .",
          "sudo docker run -d -p 5000:5000 mywebapp"
        ]
    }

    tags {
        environment = "staging"
    }
}
like image 84
zapatilla Avatar answered Oct 21 '22 15:10

zapatilla