ansible-collections / community.general

Ansible Community General Collection
https://galaxy.ansible.com/ui/repo/published/community/general/
GNU General Public License v3.0
822 stars 1.52k forks source link

Become with doas on local connections doesn't work #7678

Open vaygr opened 10 months ago

vaygr commented 10 months ago

Summary

Become with doas works fine on ssh connections, but using local connection it doesn't, forcing a password prompt for every task in the playbook.

Issue Type

Bug Report

Component Name

doas

Ansible Version

$$ ansible --version
ansible [core 2.16.0]
  executable location = /usr/bin/ansible
  python version = 3.11.6 (main, Nov 14 2023, 09:36:21) [GCC 13.2.1 20230801] (/usr/bin/python)
  jinja version = 3.1.2
  libyaml = True

Community.general Version

$ ansible-galaxy collection list community.general
Collection        Version
----------------- -------
community.general 8.0.2

Configuration

N/A

OS / Environment

Manjaro Linux

Steps to Reproduce

---
- name: PoC
  hosts: localhost
  connection: local
  become: true
  tasks:
    - debug:
        msg: "Test"
    - command:
        cmd: id
      register: id
    - debug:
        msg: "{{ id.stdout }}"

Expected Results

$$ ansible-playbook -K local.yml
BECOME password:

PLAY [PoC] ******************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************
ok: [localhost]

TASK [debug] ****************************************************************************************************************************************
ok: [localhost] => {
    "msg": "Test"
}

TASK [command] **************************************************************************************************************************************
changed: [localhost]

TASK [debug] ****************************************************************************************************************************************
ok: [localhost] => {
    "msg": "uid=0(root) gid=0(root) groups=0(root)"
}

PLAY RECAP ******************************************************************************************************************************************
localhost                  : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Actual Results

$$ ansible-playbook -K --become-method doas local.yml
BECOME password:

PLAY [PoC] ******************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************
doas (user@host) password:
ok: [localhost]

TASK [debug] ****************************************************************************************************************************************
ok: [localhost] => {
    "msg": "Test"
}

TASK [command] **************************************************************************************************************************************
doas (user@host) password:
changed: [localhost]

TASK [debug] ****************************************************************************************************************************************
ok: [localhost] => {
    "msg": "uid=0(root) gid=0(root) groups=0(root)"
}

PLAY RECAP ******************************************************************************************************************************************
localhost                  : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Code of Conduct

ansibullbot commented 10 months ago

Files identified in the description:

If these files are incorrect, please update the component name section of the description or use the !component bot command.

click here for bot help

ansibullbot commented 10 months ago

Files identified in the description:

If these files are incorrect, please update the component name section of the description or use the !component bot command.

click here for bot help

ansibullbot commented 10 months ago

cc @JoergFiedler @MacLemon @bcoca @dch @eest @jasperla @mekanix @opoplawski @overhacked @tuxillo click here for bot help

felixfontein commented 10 months ago

!component =plugins/become/doas.py

ansibullbot commented 10 months ago

Files identified in the description:

If these files are incorrect, please update the component name section of the description or use the !component bot command.

click here for bot help

ansibullbot commented 10 months ago

cc @None click here for bot help

bcoca commented 10 months ago

is 'persist' set in the doas config?

vaygr commented 10 months ago

Yes.

vaygr commented 10 months ago

It also doesn't matter. As the password should be handed over transparently. It works fine over SSH even without persist. As it does with sudo and su become methods.

bcoca commented 10 months ago

~im going to guess doas changed and is not using stdout/stderr to prompt?~

bcoca commented 10 months ago

doas (user@host) password: is exactly what you are getting?

code matches: 'doas \(' 'Password:

try setting the prompt_l10n option

vaygr commented 10 months ago

Tried that, same issue. Played around with that option for su as well, works as expected.

As I mentioned, the same version of doas over SSH works just fine.

vaygr commented 10 months ago

b_output is empty on a local connection, and not when connected via SSH. Checked it with:

$ ansible -Kb --become-method doas -m command -a "id" …
vaygr commented 10 months ago

Also yes, unlike su it's not using stdout/stderr to prompt on a local connection.

bcoca commented 10 months ago

that was not the case before, iirc it used to use stderr, but if it is bypassing that the local plugin won't be able to see the prompt. ssh plugin sees it cause even if they bypass stdout/stderr on the remote, once tunneled through ssh it appears the same as if they didn't.

vaygr commented 10 months ago

I think this use-case was never tested. https://github.com/Duncaen/OpenDoas/issues/33#issuecomment-691025263 suggests doas never supported std I/O.

How can it be solved in Ansible?

vaygr commented 10 months ago

i.e. is it possible to simulate non-tty behavior without touching code in https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/connection/local.py#L117-L150 ?

bcoca commented 10 months ago

Not the same, Ansible is working more like 'expect' in this case than a pipe, it writes directly to the file descriptor.

This was tested and working at one point, at least when doas was in core, though it was only tested against FreeBSD at the time.

bcoca commented 10 months ago

can you check if this patch fixes it?

index 69e730aad..3bc568d81 100644
--- a/plugins/become/doas.py
+++ b/plugins/become/doas.py
@@ -89,6 +89,7 @@ from ansible.plugins.become import BecomeBase
 class BecomeModule(BecomeBase):

     name = 'community.general.doas'
+    require_tty = True

     # messages for detecting prompted password issues
     fail = ('Permission denied',)
vaygr commented 10 months ago

Tried that back then, unfortunately no.