ferama / rospo

🐸 Simple, reliable, persistent ssh tunnels with embedded ssh server

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

some questions

Forum1877621 opened this issue · comments

Hi, I was testing rospo and had some questions:

  • Are keys that are password protected not supported? I get an error "unable to authenticate" when trying to use a password protected key.
  • Is there a way to provide the server password as a command line arg?
  • How do you launch the UI?

also, is it possible to save logs to a text file, to see if anyone is attacking the server?

Password protected keys are not supported at the moment.
Some features are available using config file only.
For example to enable the webui you should use somthing like:

sshclient:
  server: 192.168.5.56
  identity: "~/.ssh/id_rsa"

web:
  listen_address: "127.0.0.1:8090"

Password protected keys are not supported at the moment.

are you planning to add support in a future update?

Also, is it possible to save logs to a text file?

I'm not planning to support protected keys at the moment, but it should not be too difficult to add it. Would you like to contribute?

Regarding logs, for my use cases I usually simply redirect console output to a log file, so no you cannot configure rospo to write to a log file directly.

I'm not planning to support protected keys at the moment, but it should not be too difficult to add it. Would you like to contribute?

I can try to take a look if you can give advice on what files need to be edited

Look at the sshc package here https://github.com/ferama/rospo/tree/main/pkg/sshc
The identity is loaded and the ssh connection is instantiated. You should start from there

I switched to using Python sshtunnel which supports key pw, will close this.
One question about the included server though, is there way to change the packet size to 256 KiB? I guess right now it's 32 KiB?

I tried sshtunnel but the performance is too bad, so I went back to this program.

@ferama I have never used golang before did some research and got it working. The file that was changed was keys.go. Here are the changes, can you incorporate this feature in the next release?

Add this to the imports

"syscall"
"golang.org/x/crypto/ssh/terminal"

Change LoadIdentityFile and add the helper function

func isKeyEncryptedWithPassphrase(keyPath string) (bool, error) {
	// Read the private key file
	keyData, err := ioutil.ReadFile(keyPath)
	if err != nil {
		return false, err
	}

	// Parse the private key
	_, err = ssh.ParsePrivateKey(keyData)
	if err != nil {
		// If the key is encrypted with a passphrase, ssh.ParsePrivateKey will return an
		// error indicating that the key is encrypted. In this case, we can conclude that
		// the key has a passphrase.
		log.Printf("key at %s is encrypted", keyPath)
		return true, nil
	}

	log.Printf("key at %s is not encrypted", keyPath)

	// If the key was successfully parsed, it means that the key does not have a passphrase
	return false, nil
}

// LoadIdentityFile reads a public key file and loads the keys to
// an ssh.PublicKeys object
func LoadIdentityFile(file string) (ssh.AuthMethod, error) {
	path, _ := ExpandUserHome(file)

	usr, _ := user.Current()
	// no path is set, try with a reasonable default
	if path == "" {
		path = filepath.Join(usr.HomeDir, ".ssh", "id_rsa")
	}

	isKeyEncrypted, err := isKeyEncryptedWithPassphrase(file)
	if err != nil {
		return nil, err
	}

	if isKeyEncrypted {
		fmt.Print("Enter passphrase for SSH key: \n")
		password, err := terminal.ReadPassword(int(syscall.Stdin))
		fmt.Print("\n")

		if err != nil {
			return nil, err
		}
		buffer, err := ioutil.ReadFile(path)
		if err != nil {
			return nil, fmt.Errorf("cannot read SSH identity key file %s", path)
		}

		key, err := ssh.ParsePrivateKeyWithPassphrase(buffer, password)
		if err != nil {
			return nil, fmt.Errorf("cannot parse SSH identity key file %s", file)
		}
		return ssh.PublicKeys(key), nil
	} else {
		buffer, err := ioutil.ReadFile(path)
		if err != nil {
			return nil, fmt.Errorf("cannot read SSH identity key file %s", path)
		}

		key, err := ssh.ParsePrivateKey(buffer)
		if err != nil {
			return nil, fmt.Errorf("cannot parse SSH identity key file %s", file)
		}
		return ssh.PublicKeys(key), nil
	}
}

Here's some changes that allows for key passphrase caching

Uses a new file cache.go

package cache

var CachedKeyPw []byte

LoadIdentityFile

func LoadIdentityFile(file string) (ssh.AuthMethod, error) {
	path, _ := ExpandUserHome(file)

	usr, _ := user.Current()
	// no path is set, try with a reasonable default
	if path == "" {
		path = filepath.Join(usr.HomeDir, ".ssh", "id_rsa")
	}

	isKeyEncrypted, err := isKeyEncryptedWithPassphrase(file)
	if err != nil {
		return nil, err
	}

	if isKeyEncrypted {
		password := []byte(cache.CachedKeyPw)

		if string(cache.CachedKeyPw) == "" {
			fmt.Println("Enter passphrase for SSH key")
			password, err = terminal.ReadPassword(int(syscall.Stdin))
			if err != nil {
				return nil, err
			}

			for {
				fmt.Println("Cache the key password? (y/n) (insecure, stored as an array of bytes in RAM)")
				cacheInput, err := terminal.ReadPassword(int(syscall.Stdin))
				if err != nil {
					return nil, err
				}

				if string(cacheInput) == "y" {
					cache.CachedKeyPw = password
					break
				} else if string(cacheInput) == "n" {
					cache.CachedKeyPw = []byte("")
					break
				}

				fmt.Println("invalid option (pick y/n)")
			}
		}

		buffer, err := ioutil.ReadFile(path)
		if err != nil {
			return nil, fmt.Errorf("cannot read SSH identity key file %s", path)
		}

		key, err := ssh.ParsePrivateKeyWithPassphrase(buffer, password)
		if err != nil {
			return nil, fmt.Errorf("cannot parse SSH identity key file %s", file)
		}

		return ssh.PublicKeys(key), nil
	} else {
		buffer, err := ioutil.ReadFile(path)
		if err != nil {
			return nil, fmt.Errorf("cannot read SSH identity key file %s", path)
		}

		key, err := ssh.ParsePrivateKey(buffer)
		if err != nil {
			return nil, fmt.Errorf("cannot parse SSH identity key file %s", file)
		}
		return ssh.PublicKeys(key), nil
	}
}

Thanks for your work. I can evaluate your edits and include them in next release. You should make a proper pull request with your commits to the rospo main branch.

Hi @ferama ,

You will add the suggested patches provided by @Forum1877621 ? They aren't in the current repo.

In addition, I suggest to add a simple XOR to the cached password (using a typdef master key). And instead of caching only the password key, you can cache the certificate too. Then you can remove the certificate from the disk after starting the tool and it will work with all in ram.

I hope it helps.
Regards.