如果你希望不仅通过 Vue3 的界面访问 SSH,还希望在其他地方使用普通的 SSH 客户端通过临时设置的密码登录,可以在 Windows 跳板机上实现一个中间代理,接收 SSH 连接并将其转发到内部的 Linux 机器。以下是如何实现这一目标的详细步骤:
后端(Go 语言实现)
这个 Go 程序将充当 SSH 代理服务器,它会接收来自外部的 SSH 连接,验证临时密码,并将连接转发到内部的 Linux 机器上。
1. 安装依赖
使用 Go 编写后端程序之前,需要安装一些依赖包:
go get -u golang.org/x/crypto/ssh
go get -u github.com/gin-gonic/gin2. 编写 Go 程序
下面是一个简单的 Go 程序示例,它通过 HTTP API 接收请求,设置临时密码,并建立 SSH 会话。
package main
import (
"bytes"
"fmt"
"io"
"log"
"net"
"net/http"
"time"
"github.com/gin-gonic/gin"
"golang.org/x/crypto/ssh"
)
type SSHRequest struct {
Username string `json:"username"`
Password string `json:"password"`
Host string `json:"host"`
}
var tempPassword string
func main() {
r := gin.Default()
r.POST("/set-temp-password", func(c *gin.Context) {
var req SSHRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
tempPassword = req.Password
c.JSON(http.StatusOK, gin.H{"status": "temporary password set"})
})
go startSSHProxy(":2222", "root", "actual-root-password", "internal-linux-host:22")
r.Run(":8080")
}
func startSSHProxy(listenAddr, username, actualPassword, targetAddr string) {
listener, err := net.Listen("tcp", listenAddr)
if err != nil {
log.Fatalf("failed to listen on %s: %v", listenAddr, err)
}
log.Printf("Listening on %s...", listenAddr)
for {
conn, err := listener.Accept()
if err != nil {
log.Printf("failed to accept connection: %v", err)
continue
}
go handleSSHConnection(conn, username, actualPassword, targetAddr)
}
}
func handleSSHConnection(conn net.Conn, username, actualPassword, targetAddr string) {
defer conn.Close()
config := &ssh.ServerConfig{
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
if string(pass) == tempPassword {
return nil, nil
}
return nil, fmt.Errorf("password rejected for %q", c.User())
},
}
privateBytes, err := ssh.GenerateKey("rsa", 2048)
if err != nil {
log.Fatalf("failed to generate private key: %v", err)
}
private, err := ssh.ParsePrivateKey(privateBytes)
if err != nil {
log.Fatalf("failed to parse private key: %v", err)
}
config.AddHostKey(private)
sshConn, chans, reqs, err := ssh.NewServerConn(conn, config)
if err != nil {
log.Printf("failed to handshake: %v", err)
return
}
defer sshConn.Close()
go ssh.DiscardRequests(reqs)
for newChannel := range chans {
go handleChannel(newChannel, username, actualPassword, targetAddr)
}
}
func handleChannel(newChannel ssh.NewChannel, username, actualPassword, targetAddr string) {
if newChannel.ChannelType() != "session" {
newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
return
}
channel, requests, err := newChannel.Accept()
if err != nil {
log.Printf("could not accept channel: %v", err)
return
}
defer channel.Close()
conn, err := ssh.Dial("tcp", targetAddr, &ssh.ClientConfig{
User: username,
Auth: []ssh.AuthMethod{ssh.Password(actualPassword)},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Timeout: 5 * time.Second,
})
if err != nil {
log.Printf("failed to dial target: %v", err)
return
}
defer conn.Close()
session, err := conn.NewSession()
if err != nil {
log.Printf("failed to create session: %v", err)
return
}
defer session.Close()
go io.Copy(channel, session.Stdout)
go io.Copy(channel.Stderr, session.Stderr)
go io.Copy(session.Stdin, channel)
go ssh.DiscardRequests(requests)
if err := session.Shell(); err != nil {
log.Printf("failed to start shell: %v", err)
return
}
session.Wait()
}前端(Vue3 实现)
前端程序使用 Vue3 创建用户界面,允许管理员设置临时密码,并通过 HTTP 请求发送到后端。
1. 创建 Vue 项目并安装依赖
如果没有 Vue CLI,可以先安装:
npm install -g @vue/cli创建新的 Vue 项目:
vue create ssh-client
cd ssh-client2. 创建 Vue 组件
编辑 src/components/SetTempPassword.vue,创建一个表单,让管理员设置临时密码:
<template>
<div>
<h1>Set Temporary Password</h1>
<form @submit.prevent="setTempPassword">
<div>
<label for="username">Username:</label>
<input type="text" v-model="username" id="username" required>
</div>
<div>
<label for="password">Temporary Password:***
<input type="password" v-model="password" id="password" required>
</div>
<div>
<label for="host">Host:</label>
<input type="text" v-model="host" id="host" required>
</div>
<button type="submit">Set Password</button>
</form>
<div v-if="status">
<h2>Status:</h2>
<pre>{{ status }}</pre>
</div>
</div>
</template>
<script>
export default {
data() {
return {
username: '',
password: '',
host: '',
status: ''
};
},
methods: {
async setTempPassword() {
const response = await fetch('http://localhost:8080/set-temp-password', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: this.username,
password: ***,
host: this.host
})
});
const data = await response.json();
if (response.ok) {
this.status = data.status;
} else {
this.status = `Error: ${data.error}`;
}
}
}
};
</script>
<style>
/* Add some basic styling */
form div {
margin-bottom: 10px;
}
</style>2.2. 配置 Vue 路由
编辑 src/router/index.js,添加路由配置:
import { createRouter, createWebHistory } from 'vue-router';
import SetTempPassword from '../components/SetTempPassword.vue';
const routes = [
{
path: '/',
name: 'SetTempPassword',
component: SetTempPassword
}
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
});
export default router;2.3. 在 App.vue 中添加路由视图
编辑 src/App.vue,添加路由视图:
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>2.4. 运行 Vue 项目
启动 Vue 开发服务器:
npm run serve使用和验证
- 启动 Go 后端程序,这将开启 HTTP 服务器监听端口 8080 以及 SSH 代理服务器监听端口 2222。
- 通过浏览器访问 Vue 应用(通常是
http://localhost:8080),通过界面设置临时密码。 - 通过 SSH 客户端连接到跳板机的 SSH 代理端口,使用临时密码登录:
ssh -p 2222 tempuser@<bastion-host-ip>这样,跳板机将验证临时密码,并将连接转发到目标 Linux 机器的 root 账号。
总结
通过上述步骤,你可以在 Windows 跳板机上实现一个 SSH 代理程序,并通过 Vue3 前端界面设置临时密码,从而安全地管理对内部 Linux 机器的访问。用户只能通过临时密码登录,root 账号的真实密码不会被暴露。如果有任何进一步的问题或需要更多的配置指导,请告诉我!