Skip to content

SSHKit - Non-passwordless sudo command support #176

@thbar

Description

@thbar

Hello! I would like to discuss an enhancement ; this is a bit of a follow-up of:

Situation

If one connects to a remote server, then issues a command that requires sudo, on a system where the user is not a password less sudo user (for improved security), there is no logic in SSHKit (if I understand) to transmit the user password to the command generation.

This can be reproduced when one comments this line before running mix test:

RUN echo "%passwordless-sudoers ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoers.d/yolo

mix test
❯ mix test
Running ExUnit with seed: 657181, max_cases: 32
#SNIP

  1) test run/2 with group (SSHKitFunctionalTest)
     test/sshkit_functional_test.exs:103
     Assertion with == failed
     code:  assert status == 0
     left:  1
     right: 0
     stacktrace:
       test/sshkit_functional_test.exs:118: (test)

  2) test run/2 with user (SSHKitFunctionalTest)
     test/sshkit_functional_test.exs:86
     ** (ArgumentError) argument error
     code: IO.puts output
     stacktrace:
       (stdlib 6.2.2.1) io.erl:203: :io.put_chars(:standard_io, [[stderr: "sudo: a password is required\n"], 10])
       test/sshkit_functional_test.exs:97: (test)

  3) test run/2 with path, umask, user, group and env (SSHKitFunctionalTest)
     test/sshkit_functional_test.exs:123
     Assertion with == failed
     code:  assert status == 0
     left:  1
     right: 0
     stacktrace:
       test/sshkit_functional_test.exs:141: (test)

Finished in 22.3 seconds (22.3s async, 0.00s sync)
2 doctests, 159 tests, 3 failures

What is happening (IMO)

My understanding is that there is an implicit requirement that the user (as soon as a user is passed to the context) is passwordless-sudoer, and we go "non interactive" here with -n in that case:

"sudo -H -n -u me -- sh -c '/usr/bin/env whoami'"

Proposal

Passing the password via a specific variable, making sure we obfuscate things properly in case of exception, and inject it interactively when requested, would let users like me cover more scenarios.

Prior art: ServerSpec core SpecInfra does this:

https://github.com/mizzy/specinfra/blob/master/lib/specinfra/backend/ssh.rb#L131-L132

(a lot of other automation tools also do something similar).

A solution similar to this could be to:

  • pass a :sudo_password extra config flag
  • run the command, but watch for the prompt for some time on STDIN
  • reply to the prompt (or timeout)

I do not think it is possible to achieve this right now, without forking (but only had a quick first look).

What do you think?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions