You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过Go代码执行Terraform文件时遇SSH认证失败问题求助

排查Go调用Terraform时SSH认证失败问题

问题场景

通过Go代码调用Terraform执行部署时出现SSH认证失败错误:

timeout - last error: SSH authentication failed (ec2-user@3.142.149.63:22):
    ssh: handshake failed: ssh: unable to authenticate, attempted methods [none
    publickey], no supported methods remain
    
    Error: file provisioner error

但直接在Terraform工作目录手动执行terraform apply无任何报错,且确认密钥文件路径正确。

关联代码与配置

Go调用代码:

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/hashicorp/go-version"
    "github.com/hashicorp/hc-install/product"
    "github.com/hashicorp/hc-install/releases"
    "github.com/hashicorp/terraform-exec/tfexec"
)

func main() {
    installer := &releases.ExactVersion{
        Product: product.Terraform,
        Version: version.Must(version.NewVersion("1.0.6")),
        Timeout: 1000000000000000,
    }

    execPath, err := installer.Install(context.Background())
    if err != nil {
        log.Fatalf("error installing Terraform: %s", err)
    }

    workingDir := "C:/Users/XYZ/Learnings/Terraform JMeter/terraform-aws-jmeter-distributed-load-test-infra"
    tf, err := tfexec.NewTerraform(workingDir, execPath)
    if err != nil {
        log.Fatalf("error running NewTerraform: %s", err)
    }

    err = tf.Init(context.Background(), tfexec.Upgrade(true))
    if err != nil {
        log.Fatalf("error running Init: %s", err)
    }

    err = tf.Apply(context.Background())
    if err != nil {
        log.Fatalf("error running Apply: %s", err)
    }

    state, err := tf.Show(context.Background())
    if err != nil {
        log.Fatalf("error running Show: %s", err)
    }

    fmt.Println(state.FormatVersion) // "0.1"
}

Terraform连接与provisioner配置:

connection {
    type        = "ssh"
    user        = "ec2-user"
    private_key = file("C:/Users/XYZ/Learnings/GO/go-terraform.pem")
    host        = self.public_ip
}
 
provisioner "file" {
    source      = "Data98UserName.csv"
    destination = "/home/ec2-user/Data98UserName.csv"
}

排查步骤

1. 验证Go进程对密钥文件的访问权限

手动执行时使用当前用户权限,Go程序运行时可能因权限限制无法读取密钥文件。在Go代码中添加读取测试:

import "os"

// 在初始化Terraform实例后添加
content, err := os.ReadFile("C:/Users/XYZ/Learnings/GO/go-terraform.pem")
if err != nil {
    log.Fatalf("Failed to read key file: %v", err)
}
log.Printf("Key file content length: %d", len(content))

如果读取失败,需调整密钥文件权限或Go程序的运行身份。

2. 对齐Terraform执行环境变量

手动执行时的环境变量(如HOME、SSH代理相关变量)可能与Go程序运行环境不一致。可以:

  • 在Go代码中打印当前环境变量,对比手动执行时的环境:
    for _, env := range os.Environ() {
        log.Println(env)
    }
    
  • 显式为Terraform设置必要环境变量:
    tf.SetEnv(map[string]string{
        "HOME": os.Getenv("HOME"),
        // 若使用SSH代理,添加对应的环境变量
    })
    

3. 修复密钥文件换行格式

Windows下密钥文件默认使用\r\n换行,而SSH要求\n,可能导致密钥无效。修改Terraform配置替换换行符:

private_key = replace(file("C:/Users/XYZ/Learnings/GO/go-terraform.pem"), "\r\n", "\n")

4. 确认Terraform版本一致性

检查手动执行的Terraform版本与Go代码中安装的1.0.6是否一致:

# 手动执行环境运行
terraform version

若版本不一致,调整Go代码中的Version参数匹配手动版本。

5. 开启Terraform调试日志

在Go代码中开启调试日志,查看SSH认证的详细过程:

tf.SetLog(tfexec.LogLevelDebug)

从日志中可以确认密钥是否正确加载、认证请求的具体细节,定位问题根源。

内容的提问来源于stack exchange,提问作者Shady

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 11:25:15