Terraform Azurerm部署Azure VM时SSH认证失败求助
Terraform AzureRM remote-exec SSH认证失败排查与修复
错误信息
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 (linxuser@172.173.252.191:22): ssh: handshake failed: ssh: unable to authenticate, attempted methods [none │ publickey], no supported methods remain
问题背景
我是Terraform AzureRM新手,在Windows环境下尝试在Azure创建虚拟机并执行配置脚本,一直被上述SSH认证错误困扰。
配置代码
# 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" # } # }
已尝试的方法
- 动态与静态公IP分配切换(当前使用静态)
- 手动生成密钥
- 设置手动密钥权限为600
- 设置remote-exec与azurerm_linux_virtual_machine的依赖关系
- 将provision移入azurerm_linux_virtual_machine资源块
解决方案
核心修复:用户名拼写错误
在azurerm_linux_virtual_machine.tm_vm资源中,配置的admin_username是linuxuser,但remote-exec的connection块中user写成了linxuser(少了字母u)。VM上不存在linxuser账户,直接导致公钥认证失败。
修正后的connection块:
connection { host = data.azurerm_public_ip.data_public_ip.ip_address type = "ssh" user = "linuxuser" # 修正用户名拼写 private_key = tls_private_key.key_generation.private_key_pem timeout = "5m" }
其他优化建议
Windows私钥格式处理:
Terraform生成的PEM私钥在Windows下可能存在换行符问题,建议通过file()函数读取本地保存的密钥文件,而非直接引用资源内容:private_key = file("${var.compute_name}_key.pem")同时用Git Bash执行
chmod 600 ${var.compute_name}_key.pem设置正确权限。增加连接延迟:
VM创建完成后SSH服务可能未完全启动,可在connection块中添加延迟:connection { # ... 其他参数 delay = "30s" # 等待30秒后再尝试连接 }NSG规则收紧:
当前NSG允许所有端口入站,生产环境建议仅开放SSH端口:resource "azurerm_network_security_rule" "ssh_inbound" { name = "AllowSSHInbound" priority = 100 direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = "22" source_address_prefix = "*" # 建议替换为你的公网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 }替代方案:使用custom_data:
如果SSH连接问题持续,可通过custom_data在VM启动时直接执行脚本,无需SSH:resource "azurerm_linux_virtual_machine" "tm_vm" { # ... 其他配置 custom_data = filebase64("provision.tpl") }注意
provision.tpl需符合cloud-init格式(Ubuntu默认支持)。
内容的提问来源于stack exchange,提问作者P.R
相关产品推荐
相关产品推荐

