Ssh Connection to Azure Vm with Terraform

SSH connection to Azure VM with Terraform

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@something.com"
}]
}

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"
}
}

Terraform Azure VM SSH Key

The problem is due to the configuration of the VM. It seems like you use the resource azurerm_linux_virtual_machine and set the SSH key as:

admin_username      = "azureroot"
admin_ssh_key {
username = "azureroot"
public_key = file("~/.ssh/id_rsa.pub")
}

For the public key, you use the function file() to load the public key from your current machine with the path ~/.ssh/id_rsa.pub. So when you are in a different machine, maybe your teammate's, then the public key should be different from yours. And it makes the problem.

Here I have two suggestions for you. One is that use the static public key like this:

admin_username      = "azureroot"
admin_ssh_key {
username = "azureroot"
public_key = "xxxxxxxxx"
}

Then no matter where you execute the Terraform code, the public key will not cause the problem. And you can change the things as you want, for example, the NSG rules.

Cannot connect via SSH to Azure Virtual Machine

I tested your code in my environment and it gets deployed successfully but when performing SSH it errors out with connection timed out.

At first I modified it by using the azurerm_linux_virtual_machine instead of the azurerm_virtual_machine as Terraform Documentation mentions below , but it still failed.

The azurerm_virtual_machine resource has been superseded by the
azurerm_linux_virtual_machine and azurerm_windows_virtual_machine
resources. The existing azurerm_virtual_machine resource will continue
to be available throughout the 2.x releases however is in a
feature-frozen state to maintain compatibility - new functionality
will instead be added to the azurerm_linux_virtual_machine and
azurerm_windows_virtual_machine resources.

So , as a solution , I tested again by removing the NSG rule and the NSG association with NIC using the below code , and it worked out successfully. You don't need to add the SSH Port in NSG as by default Azure checks if the OS is Windows then it will open RDP and if Linux then SSH port will be opened.

Code:

provider "azurerm" {
features{}
}

data "azurerm_resource_group" "example" {
name = "ansumantest"
}

resource "azurerm_virtual_network" "example" {
name = "example-network"
address_space = ["10.0.0.0/16"]
location = data.azurerm_resource_group.example.location
resource_group_name = data.azurerm_resource_group.example.name
}

resource "azurerm_subnet" "example" {
name = "internal"
resource_group_name = data.azurerm_resource_group.example.name
virtual_network_name = azurerm_virtual_network.example.name
address_prefixes = ["10.0.2.0/24"]
}
resource "azurerm_public_ip" "aks-nfs-public-ip" {
name = "aks-nfs-public-ip"
location = data.azurerm_resource_group.example.location
resource_group_name = data.azurerm_resource_group.example.name
allocation_method = "Dynamic"

tags = {
environment = "Production"
}
}

resource "azurerm_network_interface" "example" {
name = "example-nic"
location = data.azurerm_resource_group.example.location
resource_group_name = data.azurerm_resource_group.example.name

ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.example.id
public_ip_address_id = azurerm_public_ip.aks-nfs-public-ip.id
private_ip_address_allocation = "Dynamic"
}
}

resource "azurerm_ssh_public_key" "example" {
name = "ansuman-sshkey"
resource_group_name = data.azurerm_resource_group.example.name
location = data.azurerm_resource_group.example.location
public_key = file("~/.ssh/id_rsa.pub")
}

resource "azurerm_linux_virtual_machine" "example" {
name = "example-machine"
resource_group_name = data.azurerm_resource_group.example.name
location = data.azurerm_resource_group.example.location
size = "Standard_F2"
admin_username = "adminuser"
network_interface_ids = [
azurerm_network_interface.example.id,
]

admin_ssh_key {
username = "adminuser"
public_key = azurerm_ssh_public_key.example.public_key
}

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

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

Note: I am using Terraform version 1.0.11 and azurerm provider version v2.88.1 on windows.

Output:

Sample Image

SSH command used : ssh -i C:\Users\user\.ssh\id_rsa adminuser@20.xxx.xx.245

Sample Image

Note: Please make sure OpenSSH SSH Server and OpenSSH Authentication Agent are both running in your local machine.

Trouble sshing into Azure Linux Virtual Machine

After my validation, you could save the output private pem key to a file named key.pem in the home directory. for example, C:\Users\username\ in Windows 10 or /home/username/ in Linux.

Sample Image

Then you can access the Azure VM via the command in the shell.

ssh -i "C:\Users\username\key.pem"  azureuser@23.x.x.x

Result

Sample Image

In addition, the private key generated by tls_private_key will be stored unencrypted in your Terraform state file. It's recommended to generate a private key file outside of Terraform and distribute it securely to the system where Terraform will be run.

You can use ssh-keygen in PowerShell in Windows 10 to create the key pair on the client machine. The key pair is saved into the directory C:\Users\username\.ssh.

For example, then you can send the public key to the Azure VM with Terraform function file:

admin_ssh_key {
username = "azureuser"
public_key = file("C:\\Users\\someusername\\.ssh\\id_rsa.pub")
#tls_private_key.example_ssh.public_key_openssh
}

Terraform Azure Linux VM with Azure AD Access

To logon to a linux VM with Azure AD. You would need to perform below actions.

  1. Install AAD linux extension, which appears to be installed as per your screenshot
  2. Enable System assigned Managed Identity which facilitates the AD login. I see this also being created.
  3. As mentioned in “Azure AD” section on your screenshot, you would need to assign one of Virtual Machine Administrator Login or Virtual Machine User Login roles via RBAC on the VM resource.

The third one is equally important like it’s predecessors to allow AD logins.

When all three steps are performed, az ssh vm --ip XXX.XXX.XXX.XXX would let you logon to the VM.

Update

---- adding tf code as requested in comments-----

add managed identity to VM resource

resource "azurerm_linux_virtual_machine" "dev" {
// blah-blah
identity {
type = "SystemAssigned"
}
}

add role assignment

resource "azurerm_role_assignment" "assign-vm-role" {
scope = azurerm_linux_virtual_machine.dev.id
role_definition_name = "Virtual Machine Administrator Login"
principal_id = <id-of-group/user/sp>
}

Terraform Azure_Linux_VM makes SSH key not work

Turns out I did overwrite the default (adminuser) with a cloud_init config.
After adding the default user to the cloud_config I could connect via SSH to adminuser@xxx.xxx.xxx.xxx

 data "template_cloudinit_config" "config" {                                     
gzip = true
base64_encode = true

part {
content_type = "text/cloud-config"
content = "users: [default, foobar, barfoo]"
}
}



Related Topics



Leave a reply



Submit