Skip to content

Commit

Permalink
Merge pull request #419 from reubenmiller/feat-cra-improvements
Browse files Browse the repository at this point in the history
feat(remoteaccess): support easier ssh port-forwarding for users
  • Loading branch information
reubenmiller authored Jan 13, 2025
2 parents 58f41f9 + 9c8f88a commit 5405187
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 24 deletions.
5 changes: 5 additions & 0 deletions pkg/cmd/remoteaccess/connect/run/run.manual.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package run
import (
"context"
"fmt"
"os"
"os/exec"
"strings"
"time"
Expand Down Expand Up @@ -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 [email protected]
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,
}
Expand Down Expand Up @@ -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
Expand Down
44 changes: 39 additions & 5 deletions pkg/cmd/remoteaccess/connect/ssh/ssh.manual.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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, <local>[:<remote>]. The value is passed to the ssh -L option, so read the ssh man page for more info")

completion.WithOptions(
cmd,
Expand All @@ -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 {
Expand Down Expand Up @@ -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, "--")
Expand All @@ -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()
Expand Down
38 changes: 19 additions & 19 deletions pkg/cmd/remoteaccess/server/server.manual.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 <device>
User <device_username>
PreferredAuthentications publickey
IdentityFile <identify_file>
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 <device>
User <device_username>
PreferredAuthentications publickey
IdentityFile <identify_file>
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
Expand Down

0 comments on commit 5405187

Please sign in to comment.