首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Go 企业级堡垒机:用少量代码搭一个最小 SSH 审计网关

Go 企业级堡垒机:用少量代码搭一个最小 SSH 审计网关

原创
作者头像
资源shanxueit.com
发布2026-09-23 11:32:48
发布2026-09-23 11:32:48
80
举报

企业运维最怕两件事:权限失控和操作无痕。 一台生产服务器,如果谁都能直连,出了事故根本查不到人;如果每次操作都要审批,效率又会被拖垮。堡垒机的价值,就是在“安全”和“效率”之间架一座桥:统一入口、身份认证、权限控制、全程审计。

Go 语言天生适合做这件事:高并发、网络编程强、编译后单二进制部署,没有虚拟机包袱。下面我们用少量代码,搭一个最小 SSH 审计网关的骨架,理解堡垒机的核心链路。

企业级堡垒机的核心能力

一个能进企业采购清单的堡垒机,通常包含:

  • 统一资产入口:SSH、RDP、数据库、K8s 统一接入
  • 身份认证:LDAP、OIDC、MFA、临时令牌
  • 权限模型:RBAC、资产分组、命令黑白名单
  • 会话审计:完整录像、命令记录、实时阻断
  • 审批流程:高危命令二次确认、工单联动
  • 高可用与合规:双机热备、日志不可篡改、等保对接

但所有复杂能力,都建立在一条最基础的链路上:用户连堡垒机 → 堡垒机认证 → 堡垒机连目标 → 执行操作 → 记录审计

少量代码实战:最小 SSH 审计网关

下面代码用 golang.org/x/crypto/ssh 实现一个简化版堡垒机。它接受客户端 SSH 连接,认证后把 exec 命令转发到目标服务器,并记录命令。删去了错误处理和完整会话支持,只为展示核心逻辑。

代码语言:javascript
复制
package main

import (
	"fmt"
	"log"
	"net"
	"os"

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

func main() {
	// 1. 读取目标服务器私钥,用于堡垒机免密登录目标
	key, _ := os.ReadFile("/root/.ssh/id_rsa")
	signer, _ := ssh.ParsePrivateKey(key)

	// 2. 读取堡垒机自身 HostKey
	hostKey, _ := os.ReadFile("/etc/ssh/ssh_host_rsa_key")
	hk, _ := ssh.ParsePrivateKey(hostKey)

	config := &ssh.ServerConfig{
		PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
			if c.User() == "admin" && string(pass) == "secret" {
				return nil, nil
			}
			return nil, fmt.Errorf("认证失败")
		},
	}
	config.AddHostKey(hk)

	// 3. 监听堡垒机端口
	ln, _ := net.Listen("tcp", ":2222")
	log.Println("堡垒机监听 :2222")

	for {
		conn, _ := ln.Accept()
		go handle(conn, config, signer)
	}
}

func handle(conn net.Conn, config *ssh.ServerConfig, signer ssh.Signer) {
	defer conn.Close()
	sshConn, chans, reqs, err := ssh.NewServerConn(conn, config)
	if err != nil {
		return
	}
	defer sshConn.Close()
	go ssh.DiscardRequests(reqs)

	// 4. 连接目标服务器
	target, err := ssh.Dial("tcp", "10.0.0.10:22", &ssh.ClientConfig{
		User:            "root",
		Auth:            []ssh.AuthMethod{ssh.PublicKeys(signer)},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	})
	if err != nil {
		log.Println("目标连接失败:", err)
		return
	}
	defer target.Close()

	// 5. 处理会话,记录命令并转发
	for newChan := range chans {
		if newChan.ChannelType() != "session" {
			newChan.Reject(ssh.UnknownChannelType, "仅支持 session")
			continue
		}
		ch, requests, _ := newChan.Accept()
		go func() {
			for req := range requests {
				if req.Type == "exec" {
					cmd := string(req.Payload[4:])
					log.Printf("[审计] 用户=%s 命令=%s", sshConn.User(), cmd)

					session, _ := target.NewSession()
					out, _ := session.CombinedOutput(cmd)
					ch.Write(out)
					ch.SendRequest("exit-status", false, ssh.Marshal(struct{ Status uint32 }{0}))
					ch.Close()
					session.Close()
				}
			}
		}()
	}
}

运行方式:

代码语言:javascript
复制
go mod init bastion
go get golang.org/x/crypto/ssh
go run main.go

然后客户端连接:

代码语言:javascript
复制
ssh -p 2222 admin@127.0.0.1 "whoami"

堡垒机日志会记录:

代码语言:javascript
复制
[审计] 用户=admin 命令=whoami

这个 Demo 很粗糙,但它把堡垒机最核心的“代理 + 审计”跑通了。

从 Demo 到企业级,还差什么?

上面的代码只能算玩具,离企业级堡垒机还有巨大差距:

  1. 认证与授权:需要接入 LDAP/OIDC、MFA、RBAC,按用户和资产下发权限。
  2. 协议解析:要完整支持 shell、sftp、端口转发,而不只是 exec。
  3. 会话录制:需要录制完整终端流,支持回放、搜索、实时阻断。
  4. 命令审计:要解析命令语义,识别 rm -rfDROP TABLE 等高危操作。
  5. 高可用与合规:日志不可篡改、双机热备、审计报表、等保对接。
  6. 安全加固:HostKey 校验、加密存储、防重放、防越权。

真正企业级堡垒机,代码量远不止几十行。但所有复杂系统,都是从这条最小链路长出来的。

结语

Go 做企业级堡垒机,优势不在“代码少”,而在“部署快、并发强、易维护”。 上面这几十行,不是让你直接上线,而是帮你理解堡垒机的骨架:认证、代理、审计。 把这条链路跑通,再逐步叠加权限、录像、审批、高可用,才是一条务实的工程路径。

安全无小事,堡垒机尤其如此。示例代码仅用于学习,生产环境请使用成熟方案或经过严格安全评审。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 企业级堡垒机的核心能力
  • 少量代码实战:最小 SSH 审计网关
  • 从 Demo 到企业级,还差什么?
  • 结语
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档