如何成功将ProxyCommand传递给Terraform的provisioner local-exec执行
问题根因
你遇到的报错确实来自多层单引号嵌套的解析冲突:Shell解析命令时会将--ssh-common-args='-o ProxyCommand='里的第二个单引号识别为第一个单引号的闭合符,导致整个命令结构被破坏,无法正常执行。你对堡垒机公网IP的变量引用${aws_instance.bastion.public_ip}是正确的,没有问题。
修复方案
方案1:直接修正命令行引号嵌套
通过转义双引号包裹--ssh-common-args的参数值,避免单引号嵌套冲突,同时修正Ansible单主机inventory的格式(末尾加逗号,避免Ansible将IP识别为文件路径),修改后的local-exec代码如下:
provisioner "local-exec" { command = "sleep 30; ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -u ubuntu --private-key ~/.ssh/id_rsa --ssh-common-args=\"-o ProxyCommand='ssh -W %h:%p ubuntu@${aws_instance.bastion.public_ip}'\" -i '${self.private_ip},' main.yml" }
这里将sleep时间从120秒缩短到30秒,只要服务器SSH服务启动完成即可执行,无需等待过长时间。
方案2:模板渲染Ansible Inventory(更易维护)
如果后续需要管理多台内网服务器,建议通过Terraform模板渲染Inventory文件,避免命令行堆砌参数,可读性和可维护性更高:
- 新建Inventory模板文件
inventory.tpl:
[servers] ${server_private_ip} ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/id_rsa ansible_ssh_common_args='-o ProxyCommand="ssh -W %h:%p ubuntu@${bastion_public_ip}"'
- 修改Terraform代码,先渲染模板再执行Ansible:
resource "aws_instance" "server1" { # 原有实例配置保持不变 ami = var.ubuntu2004 instance_type = "t3.small" subnet_id = aws_subnet.some_other_subnet.id vpc_security_group_ids = [aws_security_group.other_temp.id] key_name = "key" tags = { Name = "server1" } provisioner "local-exec" { command = templatefile("${path.module}/inventory.tpl", { server_private_ip = self.private_ip bastion_public_ip = aws_instance.bastion.public_ip }) > inventory.ini && sleep 30 && ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -i inventory.ini main.yml } }
方案3:配置SSH全局代理规则(最简便)
如果你的本地环境固定,可直接在~/.ssh/config中配置内网网段的全局代理规则,后续所有SSH/Ansible请求都会自动走堡垒机转发,无需在命令中携带任何代理参数:
Host 10.0.0.0/16 # 替换为你AWS VPC的内网网段 User ubuntu ProxyCommand ssh -W %h:%p ubuntu@<堡垒机公网IP> # 也可直接写固定的堡垒机公网IP IdentityFile ~/.ssh/id_rsa StrictHostKeyChecking no
配置完成后,local-exec的命令可以简化为:
provisioner "local-exec" { command = "sleep 30; ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -u ubuntu --private-key ~/.ssh/id_rsa -i '${self.private_ip},' main.yml" }
额外注意事项
- 确保堡垒机安全组放行本地公网IP的22端口入站规则
- 确保内网服务器
server1的安全组放行堡垒机私网IP的22端口入站规则 - 确保本地
~/.ssh/id_rsa文件权限为600,避免SSH拒绝读取密钥
内容的提问来源于stack exchange,提问作者Fresh
相关产品推荐
相关产品推荐

