From dffb7832f364718138a3bc1070cdacc031129437 Mon Sep 17 00:00:00 2001 From: Michael Quigley Date: Mon, 16 Sep 2024 14:21:23 -0400 Subject: [PATCH] infrastructure for private sharing commands (#463) --- agent/privateShare.go | 66 ++++++++++++++ agent/publicShare.go | 5 +- agent/share.go | 6 ++ cmd/zrok/agentSharePrivate.go | 164 ++++++++++++++++++++++++++++++++++ cmd/zrok/sharePrivate.go | 3 - 5 files changed, 239 insertions(+), 5 deletions(-) create mode 100644 agent/privateShare.go create mode 100644 cmd/zrok/agentSharePrivate.go diff --git a/agent/privateShare.go b/agent/privateShare.go new file mode 100644 index 00000000..b04a5351 --- /dev/null +++ b/agent/privateShare.go @@ -0,0 +1,66 @@ +package agent + +import ( + "context" + "errors" + "github.com/openziti/zrok/agent/agentGrpc" + "github.com/openziti/zrok/agent/proctree" + "github.com/openziti/zrok/environment" + "github.com/openziti/zrok/sdk/golang/sdk" + "github.com/sirupsen/logrus" + "os" +) + +func (i *agentGrpcImpl) PrivateShare(_ context.Context, req *agentGrpc.PrivateShareRequest) (*agentGrpc.PrivateShareReply, error) { + root, err := environment.LoadRoot() + if err != nil { + return nil, err + } + + if !root.IsEnabled() { + return nil, errors.New("unable to load environment; did you 'zrok enable'?") + } + + shrCmd := []string{os.Args[0], "share", "private", "--agent", "-b", req.BackendMode} + shr := &share{ + shareMode: sdk.PrivateShareMode, + backendMode: sdk.BackendMode(req.BackendMode), + bootComplete: make(chan struct{}), + a: i.a, + } + + if req.Insecure { + shrCmd = append(shrCmd, "--insecure") + } + shr.insecure = req.Insecure + + if req.Closed { + shrCmd = append(shrCmd, "--closed") + } + shr.closed = req.Closed + + for _, grant := range req.AccessGrants { + shrCmd = append(shrCmd, "--access-grant", grant) + } + shr.accessGrants = req.AccessGrants + + shrCmd = append(shrCmd, req.Target) + shr.target = req.Target + + logrus.Infof("executing '%v'", shrCmd) + + shr.process, err = proctree.StartChild(shr.tail, shrCmd...) + if err != nil { + return nil, err + } + + go shr.monitor() + <-shr.bootComplete + + if shr.bootErr == nil { + i.a.inShares <- shr + return &agentGrpc.PrivateShareReply{Token: shr.token}, nil + } + + return nil, shr.bootErr +} diff --git a/agent/publicShare.go b/agent/publicShare.go index 5253b85b..f72325dc 100644 --- a/agent/publicShare.go +++ b/agent/publicShare.go @@ -75,7 +75,7 @@ func (i *agentGrpcImpl) PublicShare(_ context.Context, req *agentGrpc.PublicShar shr.process, err = proctree.StartChild(shr.tail, shrCmd...) if err != nil { - return &agentGrpc.PublicShareReply{}, err + return nil, err } go shr.monitor() @@ -88,5 +88,6 @@ func (i *agentGrpcImpl) PublicShare(_ context.Context, req *agentGrpc.PublicShar FrontendEndpoints: shr.frontendEndpoints, }, nil } - return &agentGrpc.PublicShareReply{}, shr.bootErr + + return nil, shr.bootErr } diff --git a/agent/share.go b/agent/share.go index d1f74d97..5debc70f 100644 --- a/agent/share.go +++ b/agent/share.go @@ -7,6 +7,7 @@ import ( "github.com/michaelquigley/pfxlog" "github.com/openziti/zrok/agent/proctree" "github.com/openziti/zrok/sdk/golang/sdk" + "github.com/sirupsen/logrus" "strings" "time" ) @@ -44,6 +45,11 @@ func (s *share) monitor() { } func (s *share) tail(data []byte) { + defer func() { + if r := recover(); r != nil { + logrus.Errorf("recovering: %v", r) + } + }() s.readBuffer.Write(data) if line, err := s.readBuffer.ReadString('\n'); err == nil { line = strings.Trim(line, "\n") diff --git a/cmd/zrok/agentSharePrivate.go b/cmd/zrok/agentSharePrivate.go new file mode 100644 index 00000000..8021c04f --- /dev/null +++ b/cmd/zrok/agentSharePrivate.go @@ -0,0 +1,164 @@ +package main + +import ( + "context" + "fmt" + "github.com/openziti/zrok/agent/agentClient" + "github.com/openziti/zrok/agent/agentGrpc" + "github.com/openziti/zrok/endpoints/vpn" + "github.com/openziti/zrok/environment" + "github.com/openziti/zrok/tui" + "github.com/spf13/cobra" + "net" + "path/filepath" +) + +func init() { + agentShareCmd.AddCommand(newAgentSharePrivateCommand().cmd) +} + +type agentSharePrivateCommand struct { + backendMode string + headless bool + insecure bool + closed bool + accessGrants []string + cmd *cobra.Command +} + +func newAgentSharePrivateCommand() *agentSharePrivateCommand { + cmd := &cobra.Command{ + Use: "private ", + Short: "Create a private share in the zrok Agent", + Args: cobra.RangeArgs(0, 1), + } + command := &agentSharePrivateCommand{cmd: cmd} + cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode {proxy, web, tcpTunnel, udpTunnel, caddy, drive, socks, vpn}") + cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless") + cmd.Flags().BoolVar(&command.insecure, "insecure", false, "Enable insecure TLS certificate validation for ") + cmd.Flags().BoolVar(&command.closed, "closed", false, "Enable closed permission mode (see --access-grant)") + cmd.Flags().StringArrayVar(&command.accessGrants, "access-grant", []string{}, "zrok accounts that are allowed to access this share (see --closed)") + cmd.Run = command.run + return command +} + +func (cmd *agentSharePrivateCommand) run(_ *cobra.Command, args []string) { + var target string + + switch cmd.backendMode { + case "proxy": + if len(args) != 1 { + tui.Error("the 'proxy' backend mode expects a ", nil) + } + v, err := parseUrl(args[0]) + if err != nil { + if !panicInstead { + tui.Error("invalid target endpoint URL", err) + } + panic(err) + } + target = v + + case "web": + if len(args) != 1 { + tui.Error("the 'web' backend mode expects a ", nil) + } + v, err := filepath.Abs(args[0]) + if err != nil { + if !panicInstead { + tui.Error("invalid target endpoint URL", err) + } + panic(err) + } + target = v + + case "tcpTunnel": + if len(args) != 1 { + tui.Error("the 'tcpTunnel' backend mode expects a ", nil) + } + target = args[0] + + case "udpTunnel": + if len(args) != 1 { + tui.Error("the 'udpTunnel' backend mode expects a ", nil) + } + target = args[0] + + case "caddy": + if len(args) != 1 { + tui.Error("the 'caddy' backend mode expects a ", nil) + } + v, err := filepath.Abs(args[0]) + if err != nil { + if !panicInstead { + tui.Error("invalid target endpoint URL", err) + } + panic(err) + } + target = v + + case "drive": + if len(args) != 1 { + tui.Error("the 'drive' backend mode expects a ", nil) + } + v, err := filepath.Abs(args[0]) + if err != nil { + if !panicInstead { + tui.Error("invalid target endpoint URL", err) + } + panic(err) + } + target = v + + case "socks": + if len(args) != 0 { + tui.Error("the 'socks' backend mode does not expect ", nil) + } + target = "socks" + + case "vpn": + if len(args) == 1 { + _, _, err := net.ParseCIDR(args[0]) + if err != nil { + tui.Error("the 'vpn' backend expect valid CIDR ", err) + } + target = args[0] + } else { + target = vpn.DefaultTarget() + } + + default: + tui.Error(fmt.Sprintf("invalid backend mode '%v'", cmd.backendMode), nil) + } + + root, err := environment.LoadRoot() + if err != nil { + if !panicInstead { + tui.Error("unable to load environment", err) + } + panic(err) + } + + if !root.IsEnabled() { + tui.Error("unable to load environment; did you 'zrok enable'?", nil) + } + + client, conn, err := agentClient.NewClient(root) + if err != nil { + tui.Error("error connecting to agent", err) + } + defer conn.Close() + + shr, err := client.PrivateShare(context.Background(), &agentGrpc.PrivateShareRequest{ + Target: target, + BackendMode: cmd.backendMode, + Insecure: cmd.insecure, + Closed: cmd.closed, + AccessGrants: cmd.accessGrants, + }) + if err != nil { + tui.Error("error creating share", err) + } + + fmt.Println(shr) +} diff --git a/cmd/zrok/sharePrivate.go b/cmd/zrok/sharePrivate.go index fe71eb2a..304a7a6f 100644 --- a/cmd/zrok/sharePrivate.go +++ b/cmd/zrok/sharePrivate.go @@ -27,7 +27,6 @@ func init() { } type sharePrivateCommand struct { - basicAuth []string backendMode string headless bool insecure bool @@ -43,7 +42,6 @@ func newSharePrivateCommand() *sharePrivateCommand { Args: cobra.RangeArgs(0, 1), } command := &sharePrivateCommand{cmd: cmd} - cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (,...") cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode {proxy, web, tcpTunnel, udpTunnel, caddy, drive, socks, vpn}") cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless") cmd.Flags().BoolVar(&command.insecure, "insecure", false, "Enable insecure TLS certificate validation for ") @@ -145,7 +143,6 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { req := &sdk.ShareRequest{ BackendMode: sdk.BackendMode(cmd.backendMode), ShareMode: sdk.PrivateShareMode, - BasicAuth: cmd.basicAuth, Target: target, } if cmd.closed {