ssh.dial()强制要求hostkeycallback,禁用ssh.insecureignorehostkey()生产环境;session需每次新建且非线程安全;命令执行用session.run()或output()自动wait;超时须用context.withtimeout;传文件应走sftp而非shell调scp。

ssh.Dial() 是连接入口,但 HostKeyCallback 不能写 ssh.InsecureIgnoreHostKey()
生产环境一用就踩坑:连接看似成功,实则中间人攻击风险敞口大。Go 的 ssh.Dial() 强制要求你提供 HostKeyCallback,它不是可选项——不填编译不过,填错等于放弃安全底线。
-
ssh.InsecureIgnoreHostKey()只能用于本地调试,CI/CD 或容器内运行时必须替换 - 推荐方案是
ssh.KnownHosts(knownHostsFile),自动加载~/.ssh/known_hosts(注意路径需显式展开,os.UserHomeDir()+ 手动拼接) - 若需预置可信密钥,用
ssh.FixedHostKey(pubKey),但得先用ssh.ParsePublicKey()解析远端ssh-keyscan -t rsa host拿到的公钥 - 错误现象:
ssh: handshake failed: ssh: unable to authenticate常被误判为认证问题,实际可能是 HostKeyCallback 拒绝了服务端公钥
执行命令别复用 *ssh.Session,每次都要 client.NewSession()
Session 不是线程安全的,也不是“连接池资源”——它是一次性会话对象。复用会导致 write tcp: broken pipe 或静默丢命令。
-
session.Run("ls")和session.Output("whoami")都是同步阻塞调用,内部已含Wait(),无需再手动session.Wait() - 需要交互(如输入密码、响应提示)才用
session.Start()+session.Wait(),且必须配session.StdinPipe()/session.StdoutPipe() - 超时控制不能靠
ClientConfig.Timeout(那只管握手),得用context.WithTimeout()包裹session.Run(),否则卡死无解 - 常见误写:
client.Do()—— 这个方法根本不存在,Go 的 crypto/ssh 没这封装,编译直接报client.Do undefined
传文件别碰 session.Run("scp ..."),改用 sftp.Client
用 shell 调 scp 是最典型的“看着能跑,上线必崩”。远端没 scp 命令、shell 被设为 /bin/false、路径含空格或中文,全都会跪。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- SFTP 是 SSH 协议内置子系统,不依赖 shell,权限更细(支持
Chmod、Chown)、错误更明确(比如permission denied直接定位到目录写权限) - 上传流程固定四步:
ssh.Dial()→sftp.NewClient(conn)→client.Create("/path/file")→io.Copy();记得file.Chmod(0644),否则默认是0600 - 目标目录不存在?
client.MkdirAll()在老旧 SFTP server(如 OpenSSH Mkdir() - 私钥格式陷阱:OpenSSH 8.8+ 默认生成新格式(
-----BEGIN OPENSSH PRIVATE KEY-----),老代码用ssh.ParsePrivateKey()会报错,需先转 PEM:ssh-keygen -p -f key -m pem
认证失败 90% 不是代码问题,先查三件事
看到 ssh: unable to authenticate 别急着翻 Go 代码——八成是 SSH 层配置没对齐,和 Go 本身无关。
- 用户权限:检查远端
/etc/ssh/sshd_config是否开了PermitRootLogin yes(如果连 root),或是否被AllowUsers拦截 - 密钥权限:私钥文件在本地必须是
0600,os.ReadFile()前建议加os.Chmod(keyPath, 0600)防 CI 环境继承宽松权限 - Agent 转发:要用
sshagent.NewClient()复用本地 ssh-agent,得确保启动 Go 程序的终端里SSH_AUTH_SOCK环境变量有效,Docker 容器里得显式挂载 socket 文件
远端目录写不了、命令没输出、连接秒断——先看日志里是不是 read tcp: i/o timeout 或 unexpected EOF,这类基本就是认证或网络策略挡在了 SSH 握手前,不是 Go 层能绕开的。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










