Giter VIP home page Giter VIP logo

rig's People

Contributors

cr1cr1 avatar dependabot[bot] avatar emosbaugh avatar erdii avatar jadolg avatar james-nesbitt avatar jasmingacic avatar jnummelin avatar kke avatar quadespresso avatar rtsp avatar twz123 avatar weakpixel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rig's Issues

Consider implementing `client.Dialer()`

It would be pretty neat to have all protocols have a way to return a net.Dialer for forwarding traffic.

On SSH it comes pretty much out-of-the-box, on localhost it can just return it from stdlib net. On openssh it's probably easy-ish, but on WinRM it needs some kind of powershell scriptlet that opens a System.Net.Sockets.TcpClient and streams stdin/stdout.

This could be used for bastion and for communicating to APIs.

Something wrong with KnownHosts file handling

In my ~/.ssh/config I have:

Host 127.0.0.1
  UserKnownHostsFile=/dev/null

Still, I get hostkey mismatch errors when connecting to VMs on localhost unless I set SSH_KNOWN_HOSTS=/dev/null.

Could be #87

Encrypted Key at Default Location, but unlocked in SSH Agent fails

Due to changes in #68, the behaviour with ssh key & agents is now broken for us.

We have an encrypted .ssh/id_rsa. The code now fails with this private key is passphrase protected. But the key would be in the ssh agent. Currently only the password callback is checked, and if none is set, the error is returned.
The code should query ssh agent in such a case

sudo with password support

Split up from a closed/related issue for better tracking. I do plan to attempt an implementation of this.

I do have a question in terms of sudo, do you plan/want to support sudo with a password? probably injected through stdin?

Originally posted by @kaplan-michael in #195 (comment)

Connection issue with keys

Hey ๐Ÿ‘‹ - first off, wanted to say thanks for rig. I found it super nice to work with when I automated a couple checks.

There's one issue I ran into, when I try connecting the first time, it seems to expect the key to be loaded in the ssh-agent. So once I manually ssh in using the key it works.

Is there a way to not rely on the agent?

SSH auth with password?

Hello, I was wondering if there are plans to support ssh/& openssh connections with password(without keys)

Is it intentionally not supported?
I suppose I can build my own AuthMethod to patch that in, but it would be nice to have it in the core config.

edit: without keys(missed that)

SSH config resolving for host:port is flawed

Rig is trying to be too clever with getting host settings from the ssh config by first querying for host:port and if that fails, by trying host only.

The alias/pattern/key in ssh config is not host:port. In fact, you can have something like:

Host 127.0.0.1:33
  HostName 127.0.0.1
  Port 45

==>

$ ssh -v 127.0.0.1:33
debug1: Reading configuration data /Users/kimmo/.ssh/config
debug1: /Users/kimmo/.ssh/config line 7: Applying options for 127.0.0.1:33
debug1: /Users/kimmo/.ssh/config line 18: Applying options for *
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 47: Applying options for *
debug1: Connecting to 127.0.0.1 [127.0.0.1] port 45.

The port is only parsed from -p:

$ ssh -v [email protected]:33 -p 2222
debug1: Reading configuration data /Users/kimmo/.ssh/config
debug1: /Users/kimmo/.ssh/config line 7: Applying options for 127.0.0.1:33
debug1: /Users/kimmo/.ssh/config line 13: Applying options for *
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 47: Applying options for *
debug1: Connecting to 127.0.0.1 port 2222.

$ ssh -v 127.0.0.1:12345 -p33
debug1: Reading configuration data /Users/kimmo/.ssh/config
debug1: /Users/kimmo/.ssh/config line 13: Applying options for *
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 47: Applying options for *
debug1: resolve_canonicalize: hostname 127.0.0.1:12345 is an unrecognised address
debug1: Connecting to 127.0.0.1:12345 port 33.

So, in the case of config like this:

ssh:
  address: 127.0.0.1
  port: 40
  user: bob

And ssh config like this:

Host 127.0.0.1
  Port 45
Host local
  Port 40
  HostName 127.0.0.1
  User foo

What should rig do?

  1. query for 127.0.0.1 in the config and discard anything found in there unless port is 40 and user is bob also in ssh config?
  2. query for 127.0.0.1 in the config and overwrite any rig settings with the ones from ssh config?
  3. query for 127.0.0.1 in the config and overwrite any ssh config values with what is in rig config?
  4. query for 127.0.0.1 in the config and error out if there's a mismatch between rig and ssh config?
  5. query for all hosts, find one with HostName 127.0.0.1, user bob and port 40?
  6. introduce something like ssh.host and overwrite anything received with what is in rig config?

I think the best choice is number 3. It's pretty close to what command line ssh does without losing any ssh config functionality unless specifically using the host field in 6.

Support for dry runs?

Do you plan/intend to have a support for something like a dry run? so that rig doesn't perform anything and just returns the command it is about to perform?

Fsys incorrectly uses filepath.FromSlash

The code has entries like:

// Delete removes the named file or (empty) directory.
func (fsys *WinFsys) Delete(name string) error {
	if err := fsys.conn.Exec(fmt.Sprintf("del %s", ps.DoubleQuote(filepath.FromSlash(name)))); err != nil {
		return fmt.Errorf("%w: delete %s: %w", ErrCommandFailed, name, err)
	}
	return nil
}

The filepath.FromSlash returns a new path separated with the local separator:

const (
	Separator     = os.PathSeparator
)

// FromSlash returns the result of replacing each slash ('/') character
// in path with a separator character. Multiple slashes are replaced
// by multiple separators.
func FromSlash(path string) string {
	if Separator == '/' {
		return path
	}
	return strings.ReplaceAll(path, "/", string(Separator))
}

This makes the local OS effect how remote paths are formatted, it should be the other way around.

LineIntoFile needs exec.Sudo(h)

Hi,

I'm using v0.13.0-rc.2 of the k0sctl installer.

Installing k0s with k0sctl via ssh with a non-root user fails with:

DEBU[0000] [ssh] host:22: executing /bin/bash -c -- 'file=/etc/environment; match='^NO_PROXY='; line=NO_PROXY=xyz; grep -q "${match}" "$file" && sed -i "/${match}/c ${line}" -- "$file" || (echo "$line" | tee -a -- "$file" > /dev/null)'
DEBU[0000] [ssh] host:22: (stderr) tee: /etc/environment: Permission denied

I think the problem is that it's not called with sudo here:

rig/os/linux.go

Line 238 in 2c26742

err := h.Exec(fmt.Sprintf(`/bin/bash -c -- 'file=%s; match=%s; line=%s; grep -q "${match}" "$file" && sed -i "/${match}/c ${line}" -- "$file" || (echo "$line" | tee -a -- "$file" > /dev/null)'`, escape.Quote(path), escape.Quote(matcher), escape.Quote(newLine)))

adding , exec.Sudo(h) to the end will probably fix the problem.

thanks,
Alex.

Some wrapped errors are not working

Anything returned from NewClientConn in crypto/ssh will "flatten" wrapped errors. There is an issue and a PR at golang/go#61309 golang/crypto#266

This makes some of rig's error wrapping lose all meaning and for example makes k0sctl's retry not give up before the timeout, because using errors.Is(err, rig.ErrCantConnect) is never true.

rigfs: invalid json when call readdir

DEBUG [ssh] 127.0.0.1:63685: executing `sh -s -- dir /tmp/test`
DEBUG [ssh] 127.0.0.1:63685: writing 2416 bytes to command stdin
DEBUG [ssh] 127.0.0.1:63685: {"dir":[{"size":,"unixMode":0,"modTime":,"isDir":false,"name":"/tmp/test/.*"},{"size":,"unixMode":0,"modTime":,"isDir":false,"name":"/tmp/test/*"}]}
(*fmt.wrapErrors)(0x140001fa030)(command failed: helper response unmarshal: invalid character ',' looking for beginning of value)

Problems while using SSH agent without key file

Problem

When using a key that's only in the SSH agent, but other key(s) are present in the environment and agent, the configuration will only try to use these keys and ignore the ones in the agent.

How to reproduce

  • Create a new pair of keys and do NOT place them in the .ssh directory
  • Deploy a host that can only be accessed with these keys
  • Make sure there are other key(s) in the .ssh directory
  • Add your newly created key to the ssh agent using ssh-add
  • Try to use ssh (my specific problem is with k0sctl)

Result:

failed to connect: ssh dial: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain

Expected result

The connection uses the valid credentials that already are stored in the ssh agent.

Observations

This is what I believe is the issue:

rig/ssh.go

Lines 435 to 441 in f0c372b

if len(config.Auth) == 0 {
if len(signers) == 0 {
return nil, fmt.Errorf("%w: no usable authentication method found", ErrCantConnect)
}
log.Debugf("%s: using all keys (%d) from ssh agent because a keypath was not explicitly given", c, len(signers))
config.Auth = append(config.Auth, ssh.PublicKeys(signers...))
}

In this code, config.Auth = append(config.Auth, ssh.PublicKeys(signers...)) only happens if no other authentication method is found and this could lead to false positive auth.
I would like to have all the keys from the ssh agent available no matter if other keys are provided and maybe only restrict this if a specific key file is passed.

rig.SSH.Upload requires sudo binary even if the remote user is root

Consider following snippet of code

			SSH: &rig.SSH{
				User:    "root",
				Port:    22,
				Address: anyaddress,
			},
		}

        if err := h.Upload(localPath, remotePath); err != nil {
				return err
		}

If the remote system doesn't have sudo binary installed, than the output would be

DEBUG [ssh] 127.0.0.1:57019: executing `sudo install -D /tmp/tmp.ZY3Zwx8Pyt /remote/file/path`

while we can still use install command, because the connection user is "root"

SSH config hostnames should be accepted as "address"

For example, if you run vagrant boxes, you can do:

$ vagrant ssh-config core-02                                                                                    
Host core-02
  HostName 127.0.0.1
  User core
  Port 2200
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/kimmo/Projects/go/src/github.com/k0sproject/k0sctl/.vagrant/machines/core-02/virtualbox/private_key
  IdentitiesOnly yes
  LogLevel FATAL

If you put this into your ~/.ssh/config, it would be nice if you could do something like this in rig-using apps:

hosts:
  - ssh:
      address: core-02

As an alternative, something like this could be nice too:

hosts:
  - ssh:
      config: |
        Host core-02
        HostName 127.0.0.1
        User core
        Port 2200

Creating a Sudo() Client copy leads to nil pointer dereference

I create the connections like this. yet when I check with a debugger, the SudoClient seems to have nil as it's connection. I'm guessing it should either have a pointer to the original, or a copy of the original one? Is it a bug or am I doing something wrong?

// setupHost configures and connects to a single host
func setupHost(hostConfig *HostConfig) (*Host, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	conn, err := createConnection(hostConfig)
	if err != nil {
		return nil, err
	}
	client, err := rig.NewClient(rig.WithConnection(conn), rig.WithLogger(logger.Slog))
	if err != nil {
		return nil, fmt.Errorf("failed to create rig client: %w", err)
	}

	err = client.Connect(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to connect: %w", err)
	}

	// Initialize sudo client at the same time
	sudoClient := client.Sudo()
	if sudoClient == nil {
		return nil, fmt.Errorf("failed to initialize sudo client")
	}

	return &Host{Client: client, Sudo: sudoClient, Vars: hostConfig.Vars, Fs: remotefs.NewFS(client)}, nil
}

Connection.Upload() doesn't honor exec.Sudo()

Since v0.11.0-beta.1, there's a plain Fsys() call in Connection.Upload() here:

fsys := c.Fsys()

This makes the following pseudo-code fail when executed as regular user with sudo rights:

var c *rig.Connection = connectAsRegularUserWithSudoRights()
c.Upload("foo", "/root/foo", exec.Sudo(c))

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.