Bolt command run should work with restrictive sudo rules
Describe the Bug
bolt command run <command> --run-as root -u <user> wants a password for sudo, even if sudo on the target has been set up to allow 'user' to run 'command' without the need to enter a password. I.e. the sudoers configuration on the target reads <user> ALL=(ALL) NOPASSWD: <command>. The current response is Sudo password for user <user> was not provided for <target>.
Expected Behavior
I would expect command to run without interaction, including prompting for a password.
Steps to Reproduce
Steps to reproduce the behavior:
- set up 'user' on a target system, and configure sudo on the target system to allow 'user' to run 'command' as root without prompting for a password.
- from another system, run
echo <target> | bolt command run <command> --transport ssh --targets - -u <user> --run-as root.
Environment
- target: Ubuntu 16.04
- bolt: 2.4.0 on macOS 10.14.6
Additional Context
This is my first attempt to get bolt working, maybe I'm missing something obvious.
In our network, all tools require a system user (if possible), without password. Ssh access can then be configured to this system user. If the system user requires root access, we configure sudo to allow root access to specific commands, but without password. Ssh access directly to root is not allowed. Both rules 'system users have no password' and 'no ssh access to root' cannot be lifted in my environment.
I first verified the sudo was configured correctly:
echo <target> | bolt command run sudo <command> --transport ssh --targets - -u <user>, this returns "Successful on 1 target: 'target'".
Then I tried a fake password: echo <target> | bolt command run <command> --transport ssh --targets - -u <user> --run-as root --sudo-password 'fake', which resulted in "sudo: a password is required".
I tried 'run-as-command', but that flag is not recognised: "Unknown argument '--run-as-command'".
Finally I tried 'sudo-executable': echo <target> | bolt command run <command> --transport ssh --targets - -u <user> --run-as root --sudo-executable 'sudo -n', but that also doesn't work: "bash: sudo -n: command not found".
While I can currently get away with prepending 'sudo' to 'command', I think (but correct me if I'm mistaken) that won't work when I'll be trying to run tasks and plans (which is my ultimate goal). How can I run as root when a password is not needed?
https://github.com/bolt/blob/master/lib/bolt/shell/bash.rb#L129-L147 This error should only be raised if Bolt is prompted for a password. I have a few theories about what might be happening.
- The actual command we run to escalate to the run-as user is
sudo -k -S -u $USER -p \[sudo\]\ Bolt\ needs\ to\ run\ as\ another\ user,\ password:\ $COMMAND. I wonder if the-Sis causing it to prompt? - We only check stdout for the prompt we pass in, but I wonder if your sudo invocation is actually raising a real error that happens to contain the prompt, so we fail saying we were prompted for a password. I'm not sure that there's a good way to test that besides manually running our sudo command (above) and seeing if it fails, but I think that's worth a try.
A few other notes: the run-as-command can be configured in a file bolt.yaml that's in the same directory you're running Bolt from, it just doesn't have a command line flag. Setting that will override the entire sudo command above, so you could try setting that to sudo -n:
# bolt.yaml
ssh:
run-as-command:
- "sudo"
- "-n"
- "-u"
I think with the way we escape shellwords, sudo -n is interpreted as a single executable unit instead of an executable and a flag, so I'm not sure that will work. But run-as-command should.
Adding run-as-command to bolt.yaml does unfortunately not help, I get:
Started on <target>...
Failed on <target>:
The command failed with exit code 1
STDERR:
sudo: a password is required
Failed on 1 target: <target>
The auth.log on 'target' has the following log line:
<target> sudo: <user> : command not allowed ; TTY=unknown ; PWD=/home/<user> ; USER=root ; COMMAND=root sh -c cd && <command>
Admitted I'm not entirely familiar with sudo's logs, but the 'COMMAND=root sh...' strikes me as a bit odd.
Ah, that's because run-as-command was set to an empty string. The command we build if you set run-as-command is <run-as-command> <run-as user> sh -c cd && <command>. You're seeing root sh -c... because you set run-as: root but run-as-command didn't get set. Can you post what your bolt.yaml file looks like? It should have:
ssh:
run-as-command:
- "sudo"
- "-n"
- "-u"
My bolt.yaml looks like this:
# bolt.yaml
ssh:
run-as-command:
- "sudo"
- "-n"
- "-u"
(I copy/pasted it from your second post to be certain it was correct). The bolt result is still the same ('sudo: a password is required'), but the log entry in auth.log now reads
<target> sudo: <user> : TTY=pts/1 ; PWD=/home/<user> ; USER=root ; COMMAND=/bin/sh -c cd && <command>
So I think I now see what's going on: sudo is not called on 'command', but on '/bin/sh', and my sudo configuration didn't allow 'user' to do that. After I fixed that, 'command' does run under sudo, and the file bolt.yaml appears to be no longer needed too.
The command I was trying to run is actually puppet, I was trying something along the lines of "puppet resource <custom type> 'resource name with blanks in it' ensure=present..." (i.e. the command contained single quotes, and I wrapped it in double quotes in the 'bolt command run' command line). It looks like the single quotes do not make it to command line that is executed on the target, so when I use my original command line, I get a puppet error. I fixed this by wrapping the 'puppet resource' command in a script on the target, and then run bolt with that script, i.e. bolt command run <script> --run-as root -u <user> (also no bolt.yaml present). This returns success: 'Successful on 1 target:
This works perfectly fine for me. Do you consider the quotes disappearing from 'command' a bug, and should I make a new bug report for that?
Which quotes? In general quotes are disappearing when your shell parses the bolt command or in yaml parsing and is not a bug.
The single quotes in the puppet command, like so:
echo <target> | bolt command run "/opt/puppetlabs/bin/puppet resource <custom type> '<resource name>' ensure=present ..." --transport ssh --targets - -u <user> --run-as root
'resource name' has whitespace in it, so I need to somehow make sure it's quoted (I realise I could perhaps also make sure the resource name doesn't have whitespace, but for this custom type things are not that simple, unfortunately).
However, in the mean time I found out that escaped double quotes, or escaping the whitespace work just fine:
echo <target> | bolt command run "/opt/puppetlabs/bin/puppet resource <custom type> \"<resource name>\" ensure=present ..." --transport ssh --targets - -u <user> --run-as root
works.
echo <target> | bolt command run "/opt/puppetlabs/bin/puppet resource <custom type> <resource\ name> ensure=present ..." --transport ssh --targets - -u <user> --run-as root
also works.
In summary:
- sudo on
/bin/shinstead of 'command' - no single quotes in 'command'
Works for me, I'm fine with closing this ticket.
fwiw, I encountered an error similar to this when trying to check for processes on remote machines, since the password prompt for bolt shows up in the process listing that bolt is scanning for.. e.g.
$ bolt --targets=@target-list command run --run-as=root 'ps auwwx|grep something'
Fails on most targets
$ bolt --targets=@target-list command run --run-as=root 'ps auwwx|grep something|grep -v password:'
Succeeds.
Perhaps it should be a little more restrictive in how it finds that prompt (as the last bit of output, bind match to start, end of line, etc)
fwiw, running manually, one sees:
root 210330 0.0 0.0 273472 4792 ? Ss 13:37 0:00 sudo -S -H -u root -p [sudo] Bolt needs to run as another user, password: sh -c cd; ps auwwx|grep something
root 210423 0.0 0.0 113280 1360 ? S 13:37 0:00 sh -c cd; ps auwwx|grep something
root 210425 0.0 0.0 112808 952 ? S 13:37 0:00 grep something
Another workaround often used with ps | grep is to square-bracket a single character, this has the added benefit to also exclude the grep command as well:
$ bolt --targets=@target-list command run --run-as=root 'ps auwwx|grep [s]omething'
This issue has not had activity for 60 days and will be marked as stale. If this issue continues to have no activity for 7 days, it will be closed.
Not stale.. Still issue.
This issue has not had activity for 60 days and will be marked as stale. If this issue continues to have no activity for 7 days, it will be closed.
This issue is stale and has been closed. If you believe this is in error, or would like the Bolt team to reconsider it, please reopen the issue.