ssh

前言

日常运维、批量服务器管理、自动化运维脚本开发中,SSH 远程操作是必备能力。Go 生态中最标准、使用最广泛的 SSH 客户端库就是 golang.org/x/crypto/ssh,支持密码登录、SSH 私钥登录、远程命令执行、交互式终端等常用能力。

本文从零带你快速入门,梳理核心用法、完整可运行代码、常用场景封装,拿来就能直接用到项目中。

一、安装依赖

Go 标准库未内置 SSH 相关能力,需要安装官方扩展加密包:

go get golang.org/x/crypto/ssh

二、SSH 核心使用流程

使用 Go ssh 包,固定遵循三步流程,记住即可上手:

  1. 组装客户端配置:用户名、认证方式(密码/私钥)、连接超时、主机密钥校验策略
  2. 建立 TCP+SSH 连接
  3. 创建 Session 会话,执行远程命令、获取标准输出与错误输出

三、方式一:密码登录 + 执行远程命令

最简单常用的方式,适合测试环境、内网服务器运维。

完整示例代码

package main

import (
	"bytes"
	"fmt"
	"log"
	"time"

	"golang.org/x/crypto/ssh"
)

func main() {
	// 1. 构造SSH客户端配置
	sshConfig := &ssh.ClientConfig{
		User:            "root",
		Timeout:         5 * time.Second,
		HostKeyCallback: ssh.InsecureIgnoreHostKey(), // 测试环境忽略主机密钥校验
		Auth: []ssh.AuthMethod{
			ssh.Password("你的服务器密码"),
		},
	}

	// 2. 建立SSH连接
	client, err := ssh.Dial("tcp", "192.168.1.100:22", sshConfig)
	if err != nil {
		log.Fatalf("SSH连接失败: %v", err)
	}
	defer client.Close()
	fmt.Println("SSH 连接成功")

	// 3. 创建会话
	session, err := client.NewSession()
	if err != nil {
		log.Fatalf("创建会话失败: %v", err)
	}
	defer session.Close()

	// 绑定标准输出、标准错误
	var stdout, stderr bytes.Buffer
	session.Stdout = &stdout
	session.Stderr = &stderr

	// 执行远程命令
	cmd := "ls -l /home && uptime"
	if err := session.Run(cmd); err != nil {
		log.Fatalf("命令执行失败: %v\n错误信息: %s", err, stderr.String())
	}

	// 打印结果
	fmt.Println("===== 命令执行结果 =====")
	fmt.Println(stdout.String())
}

关键说明

  • HostKeyCallback: ssh.InsecureIgnoreHostKey():跳过服务器公钥校验,仅测试环境使用
  • session.Run():阻塞执行命令,命令结束后自动返回
  • 通过 bytes.Buffer 接收标准输出和错误输出,方便业务解析

四、方式二:SSH 私钥登录(生产推荐)

生产环境禁止密码明文登录,优先使用 SSH 私钥免密登录,兼容服务器默认 id_rsa 密钥。

完整示例代码

package main

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"time"

	"golang.org/x/crypto/ssh"
)

func main() {
	// 1. 读取本地私钥文件
	keyPath := "/home/用户/.ssh/id_rsa"
	privateKeyBytes, err := os.ReadFile(keyPath)
	if err != nil {
		log.Fatalf("读取私钥失败: %v", err)
	}

	// 2. 解析私钥
	signer, err := ssh.ParsePrivateKey(privateKeyBytes)
	if err != nil {
		log.Fatalf("解析私钥失败: %v", err)
	}

	// 3. 组装SSH配置
	sshConfig := &ssh.ClientConfig{
		User:            "root",
		Timeout:         5 * time.Second,
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
		Auth: []ssh.AuthMethod{
			ssh.PublicKeys(signer),
		},
	}

	// 4. 连接服务器
	client, err := ssh.Dial("tcp", "192.168.1.100:22", sshConfig)
	if err != nil {
		log.Fatalf("SSH连接失败: %v", err)
	}
	defer client.Close()

	// 5. 执行命令
	session, _ := client.NewSession()
	defer session.Close()

	var stdout bytes.Buffer
	session.Stdout = &stdout
	_ = session.Run("df -h")

	fmt.Println("磁盘信息:")
	fmt.Println(stdout.String())
}

扩展:加密私钥

如果私钥设置了密码,使用带密码解析方法:

ssh.ParsePrivateKeyWithPassphrase(privateKeyBytes, []byte("私钥密码"))

五、常用高阶用法

1. 异步执行长耗时命令

适合 sleep、后台任务等长时间运行的命令,不阻塞等待:

session.Start("sleep 10 && echo 任务完成")
// 后续可做其他业务逻辑
session.Wait()

2. 开启伪终端(支持交互式命令)

执行 sudo、mysql 等交互式命令时,必须开启 PTY:

// 申请伪终端
session.RequestPty("xterm", 80, 40, ssh.TerminalModes{})

3. 拆解连接与命令执行

可封装成工具函数,复用 SSH 连接,批量执行多台服务器命令。

六、生产环境安全注意事项

  1. 禁止使用 ssh.InsecureIgnoreHostKey(),会跳过服务器身份校验,存在中间人攻击风险;
  2. 密码登录不要硬编码在代码中,建议配置文件、环境变量读取;
  3. 优先使用 SSH 私钥登录,关闭服务器密码登录功能;
  4. 连接务必使用 defer client.Close()、defer session.Close() 释放资源,避免连接泄露。

七、总结

  1. 依赖安装:go get golang.org/x/crypto/ssh;
  2. 固定流程:配置 → 连接 → Session 会话 → 执行命令;
  3. 两种认证:密码登录适合测试,私钥登录适合生产;
  4. 核心 API:ssh.Dial 建连、client.NewSession 创建会话、session.Run 执行命令。
posted @ 2026-05-09 16:42  ZovoeY  阅读(62)  评论(0)    收藏  举报