diff --git a/pkg/cmd/remoteaccess/connect/run/run.manual.go b/pkg/cmd/remoteaccess/connect/run/run.manual.go index 25d3fcf0d..56e6eee44 100644 --- a/pkg/cmd/remoteaccess/connect/run/run.manual.go +++ b/pkg/cmd/remoteaccess/connect/run/run.manual.go @@ -3,6 +3,7 @@ package run import ( "context" "fmt" + "os" "os/exec" "strings" "time" @@ -66,6 +67,9 @@ func NewCmdRun(f *cmdutil.Factory) *CmdRun { Example: heredoc.Doc(` $ c8y remoteaccess connect run --device 12345 -- ssh -p %p root@%h Start an interactive SSH session on the device with a given ssh user + + $ c8y remoteaccess connect run --device rpi5-abcdef01 --configuration passthrough -- ssh -p %p -L 1885:127.0.0.1:1883 -o ServerAliveInterval=120 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@127.0.0.1 + Start an SSH session to setup port-forwarding to map the remote's 127.0.0.1:1883 port to your machine's 1885 port `), RunE: ccmd.RunE, } @@ -189,6 +193,7 @@ func (n *CmdRun) RunE(cmd *cobra.Command, args []string) error { } runCmd := exec.CommandContext(context.Background(), run, runArgs...) + runCmd.Env = append(runCmd.Env, os.Environ()...) // Add target and port to the environment variables so it can be easily accessed from more // complex scripts diff --git a/pkg/cmd/remoteaccess/connect/ssh/ssh.manual.go b/pkg/cmd/remoteaccess/connect/ssh/ssh.manual.go index a57b4151e..fda493aec 100644 --- a/pkg/cmd/remoteaccess/connect/ssh/ssh.manual.go +++ b/pkg/cmd/remoteaccess/connect/ssh/ssh.manual.go @@ -24,10 +24,11 @@ import ( ) type CmdSSH struct { - device []string - listen string - user string - configuration string + device []string + listen string + user string + configuration string + portForwarding string *subcommand.SubCommand @@ -62,6 +63,15 @@ func NewCmdSSH(f *cmdutil.Factory) *CmdSSH { $ c8y remoteaccess connect ssh --device 12345 --user admin Start an interactive SSH session on the device with a given ssh user + $ c8y remoteaccess connect ssh --device 12345 --user admin -L 1883:127.0.0.1:1883 + Start an interactive SSH session and configure port-forward by mapping the remote's 127.0.0.1:1883 to your machine's port 1883 + + $ c8y remoteaccess connect ssh --device 12345 --user admin -L 1883 + Start an interactive SSH session and configure port-forward: 127.0.0.11883 (remote) => 1883 (local) + + $ c8y remoteaccess connect ssh --device 12345 --user admin -L 1884:1883 + Start an interactive SSH session and configure port-forward: 127.0.0.11883 (remote) => 1884 (local) + $ c8y remoteaccess connect ssh --device 12345 --user admin -- systemctl status Use a non-interactive session to execute a single command and print the result @@ -76,6 +86,7 @@ func NewCmdSSH(f *cmdutil.Factory) *CmdSSH { cmd.Flags().StringVar(&ccmd.listen, "listen", "127.0.0.1:0", "Listener address. unix:///run/example.sock") cmd.Flags().StringVar(&ccmd.user, "user", "", "Default ssh user") cmd.Flags().StringVar(&ccmd.configuration, "configuration", "", "Remote Access Configuration") + cmd.Flags().StringVarP(&ccmd.portForwarding, "port-forward", "L", "", "SSH Port-Forwarding option in the format [bind_address:]port:host:hostport. It also accepts a custom short form, [:]. The value is passed to the ssh -L option, so read the ssh man page for more info") completion.WithOptions( cmd, @@ -93,6 +104,20 @@ func NewCmdSSH(f *cmdutil.Factory) *CmdSSH { return ccmd } +func (n *CmdSSH) GetPortForwarding() string { + // convenience functions to mirror docker port mapping options + portMapping := n.portForwarding + portForwardingParts := strings.Split(portMapping, ":") + switch len(portForwardingParts) { + case 1: + // -L 1883 => -L 1883:127.0.0.1:1883 + portMapping = fmt.Sprintf("%s:127.0.0.1:%s", portForwardingParts[0], portForwardingParts[0]) + case 2: + // -L 1884:1883 => -L 1884:127.0.0.1:1883 + portMapping = fmt.Sprintf("%s:127.0.0.1:%s", portForwardingParts[0], portForwardingParts[1]) + } + return portMapping +} func (n *CmdSSH) RunE(cmd *cobra.Command, args []string) error { client, err := n.factory.Client() if err != nil { @@ -185,6 +210,11 @@ func (n *CmdSSH) RunE(cmd *cobra.Command, args []string) error { } sshArgs = append(sshArgs, "-p", port, sshTarget) + portForwarding := n.GetPortForwarding() + if portForwarding != "" { + sshArgs = append(sshArgs, "-L", portForwarding) + } + dashIdx := cmd.ArgsLenAtDash() if dashIdx > -1 { sshArgs = append(sshArgs, "--") @@ -198,7 +228,11 @@ func (n *CmdSSH) RunE(cmd *cobra.Command, args []string) error { log.Infof("Executing command: ssh %s\n", strings.Join(sshArgs, " ")) cs := n.factory.IOStreams.ColorScheme() - fmt.Fprintln(n.factory.IOStreams.ErrOut, cs.Green(fmt.Sprintf("Starting interactive ssh session with %s (%s)\n", device, strings.TrimRight(client.BaseURL.String(), "/")))) + if portForwarding != "" { + fmt.Fprintln(n.factory.IOStreams.ErrOut, cs.Green(fmt.Sprintf("Starting interactive ssh session with %s (%s) with port-forwarding %s\n", device, strings.TrimRight(client.BaseURL.String(), "/"), portForwarding))) + } else { + fmt.Fprintln(n.factory.IOStreams.ErrOut, cs.Green(fmt.Sprintf("Starting interactive ssh session with %s (%s)\n", device, strings.TrimRight(client.BaseURL.String(), "/")))) + } start := time.Now() sshErr := sshCmd.Run() diff --git a/pkg/cmd/remoteaccess/server/server.manual.go b/pkg/cmd/remoteaccess/server/server.manual.go index fb24a01d6..990a52b1c 100644 --- a/pkg/cmd/remoteaccess/server/server.manual.go +++ b/pkg/cmd/remoteaccess/server/server.manual.go @@ -39,25 +39,25 @@ func NewCmdServer(f *cmdutil.Factory) *CmdServer { cmd := &cobra.Command{ Use: "server", Short: "Start a local proxy server", - Long: ` - Start a local proxy server - - You can add use the remote access local proxy within your ssh config file, to use it to - connect to your device with ssh without having to manually launch the proxy yourself! - - To do this add the following configuration to your device. - - --- - Host - User - PreferredAuthentications publickey - IdentityFile - ServerAliveInterval 120 - StrictHostKeyChecking no - UserKnownHostsFile /dev/null - ProxyCommand c8y remoteaccess server --device %n --listen - - --- - `, + Long: heredoc.Doc(` + Start a local proxy server + + You can add use the remote access local proxy within your ssh config file, to use it to + connect to your device with ssh without having to manually launch the proxy yourself! + + To do this add the following configuration to your device. + + --- + Host + User + PreferredAuthentications publickey + IdentityFile + ServerAliveInterval 120 + StrictHostKeyChecking no + UserKnownHostsFile /dev/null + ProxyCommand c8y remoteaccess server --device %n --listen - + --- + `), Example: heredoc.Doc(` $ c8y remoteaccess server --device 12345 Start a local proxy server on a random local port