Terraform的remote-exec中使用file()写入authorized_keys崩溃如何解决
问题根因
- 命令语法错误:
adduser语句中/home/username与后续--gecos参数之间缺失空格,会导致用户创建命令直接执行失败。 - 重定向权限问题:
sudo echo ${xxx} > 目标路径的写法本身不生效,sudo仅对echo命令提权,文件写入的重定向操作由当前普通用户权限的shell执行,无权限写入其他用户的.ssh目录。 - 字符串转义冲突:多层双引号嵌套+公钥内容插值的组合,会让Terraform解析阶段或远端shell执行阶段出现语法错误,严重时触发崩溃。
- 路径不严谨:使用
~/../username的相对路径依赖执行环境的当前用户目录,存在解析失败的风险。
修复方案
方案1:直接修正现有写法
采用tee替代echo+重定向,配合heredoc避免转义冲突,修改后的inline代码块如下:
inline = [ # 修正adduser参数空格,用绝对路径指定用户home目录 "sudo adduser --quiet --disabled-password --shell /bin/bash --home /home/username --gecos \"Firstname Lastname\" username", "sudo mkdir -p /home/username/.ssh", "sudo chmod 700 /home/username/.ssh", # heredoc包裹公钥写入逻辑,避免转义问题,tee自带提权写入能力 <<EOT sudo tee /home/username/.ssh/authorized_keys <<'EOF' ${file("userKeys/username.pub")} EOF EOT, "sudo chmod 600 /home/username/.ssh/authorized_keys", # 修正用户组语法,用:替代.兼容所有Linux版本 "sudo chown -R username:username /home/username/.ssh" ]
方案2:更稳定的环境变量传参方案
把公钥内容提前注入到remote-exec的环境变量中,彻底避免插值和转义冲突:
provisioner "remote-exec" { environment = { USER_SSH_PUB_KEY = file("userKeys/username.pub") } inline = [ "sudo adduser --quiet --disabled-password --shell /bin/bash --home /home/username --gecos \"Firstname Lastname\" username", "sudo mkdir -p /home/username/.ssh", "sudo chmod 700 /home/username/.ssh", "echo \"$USER_SSH_PUB_KEY\" | sudo tee /home/username/.ssh/authorized_keys", "sudo chmod 600 /home/username/.ssh/authorized_keys", "sudo chown -R username:username /home/username/.ssh" ] }
file()函数在remote-exec中使用的合理性
是合理方案。file()是Terraform本地执行的函数,会在apply阶段提前读取本地指定路径的文件内容,插值到命令中后再传给远端虚拟机执行,公钥这种小体积文本完全适用,仅需注意不要用file()读取MB级以上的大文件,避免命令过长导致执行失败。
内容的提问来源于stack exchange,提问作者ToolKiD
相关产品推荐
相关产品推荐

