feat: add command ssh

This commit is contained in:
fengcaiwen
2023-09-28 10:48:49 +08:00
committed by naison
parent a340ae3d8d
commit 075c736279
2 changed files with 159 additions and 0 deletions

50
cmd/kubevpn/cmds/ssh.go Normal file
View File

@@ -0,0 +1,50 @@
package cmds
import (
"os"
"github.com/spf13/cobra"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
"github.com/wencaiwulue/kubevpn/pkg/config"
"github.com/wencaiwulue/kubevpn/pkg/handler"
"github.com/wencaiwulue/kubevpn/pkg/util"
)
// CmdSSH
// 设置本地的IP是223.254.0.1/32 ,记得一定是掩码 32位
// 这样别的路由不会走到这里来
func CmdSSH(_ cmdutil.Factory) *cobra.Command {
var sshConf = &util.SshConfig{}
cmd := &cobra.Command{
Use: "ssh",
Hidden: true,
Short: "Ssh to jump server",
Long: `Ssh to jump server`,
Example: templates.Examples(i18n.T(`
# Jump to server behind of bastion host or ssh jump host
kubevpn ssh --ssh-addr 192.168.1.100:22 --ssh-username root --ssh-keyfile ~/.ssh/ssh.pem
# it also support ProxyJump, like
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌────────┐
│ pc ├────►│ ssh1 ├────►│ ssh2 ├────►│ ssh3 ├─────►... ─────► │ server │
└──────┘ └──────┘ └──────┘ └──────┘ └────────┘
kubevpn ssh --ssh-alias <alias>
`)),
PreRun: func(*cobra.Command, []string) {
if !util.IsAdmin() {
util.RunWithElevated()
os.Exit(0)
}
},
RunE: func(cmd *cobra.Command, args []string) error {
_ = os.Setenv(config.EnvKubeVPNTransportEngine, string(config.EngineGvisor))
err := handler.SSH(cmd.Context(), sshConf)
return err
},
}
addSshFlags(cmd, sshConf)
return cmd
}

109
pkg/handler/ssh.go Normal file
View File

@@ -0,0 +1,109 @@
package handler
import (
"context"
"errors"
"fmt"
"golang.org/x/crypto/ssh"
"net"
"net/netip"
"strconv"
log "github.com/sirupsen/logrus"
"github.com/wencaiwulue/kubevpn/pkg/core"
"github.com/wencaiwulue/kubevpn/pkg/util"
)
// SSH
// 0) remote server install kubevpn if not found
// 1) start remote kubevpn server
// 2) start local tunnel
// 3) ssh terminal
func SSH(ctx context.Context, config *util.SshConfig) error {
cancel, cancelFunc := context.WithCancel(ctx)
defer cancelFunc()
err := portMap(ctx, config)
if err != nil {
return err
}
go func() {
stdout, stderr, err := util.RemoteRun(config, fmt.Sprintf(`kubevpn serve -L "tcp://:10800" -L "tun://127.0.0.1:8422?net=223.254.0.123/32"`), nil)
if err != nil {
log.Errorf("run error: %v", err)
log.Errorf("run stdout: %v", string(stdout))
log.Errorf("run stderr: %v", string(stderr))
cancelFunc()
}
}()
r := core.Route{
ServeNodes: []string{
fmt.Sprintf("tun:/127.0.0.1:8422?net=%s&route=%s", "223.254.0.124/32", "223.254.0.124/32"),
},
ChainNode: "tcp://172.17.64.35:10800",
Retries: 5,
}
servers, err := Parse(r)
if err != nil {
log.Errorf("parse route error: %v", err)
return err
}
go func() {
log.Error(Run(cancel, servers))
}()
log.Info("tunnel connected")
<-cancel.Done()
return err
}
func portMap(ctx context.Context, conf *util.SshConfig) (err error) {
port := 10800
var remote netip.AddrPort
remote, err = netip.ParseAddrPort(net.JoinHostPort("127.0.0.1", strconv.Itoa(port)))
if err != nil {
return
}
var local netip.AddrPort
local, err = netip.ParseAddrPort(net.JoinHostPort("127.0.0.1", strconv.Itoa(port)))
if err != nil {
return
}
// pre-check network ip connect
var cli *ssh.Client
cli, err = util.DialSshRemote(conf)
if err != nil {
return
} else {
_ = cli.Close()
}
errChan := make(chan error, 1)
readyChan := make(chan struct{}, 1)
go func() {
for {
select {
case <-ctx.Done():
return
default:
}
err := util.Main(ctx, remote, local, conf, readyChan)
if err != nil {
if !errors.Is(err, context.Canceled) {
log.Errorf("ssh forward failed err: %v", err)
}
select {
case errChan <- err:
default:
}
}
}
}()
select {
case <-readyChan:
return
case err = <-errChan:
log.Errorf("ssh proxy err: %v", err)
return
}
}