diff --git a/docs/man/man1/ansible-playbook.1 b/docs/man/man1/ansible-playbook.1 index 0c820b72e37..cfc33d1744b 100644 --- a/docs/man/man1/ansible-playbook.1 +++ b/docs/man/man1/ansible-playbook.1 @@ -60,7 +60,7 @@ Run operations with become (nopasswd implied) .PP \fB\-\-become\-method=BECOME_METHOD\fR .RS 4 -Privilege escalation method to use (default=sudo), valid choices: [ sudo | su | pbrun | pfexec | runas ] +Privilege escalation method to use (default=sudo), valid choices: [ sudo | su | pbrun | pfexec | runas | doas ] .RE .PP \fB\-\-become\-user=BECOME_USER\fR diff --git a/docs/man/man1/ansible-playbook.1.asciidoc.in b/docs/man/man1/ansible-playbook.1.asciidoc.in index 8b8ba9c4688..00682567e84 100644 --- a/docs/man/man1/ansible-playbook.1.asciidoc.in +++ b/docs/man/man1/ansible-playbook.1.asciidoc.in @@ -51,7 +51,7 @@ Run operations with become (nopasswd implied) *--become-method=BECOME_METHOD*:: Privilege escalation method to use (default=sudo), -valid choices: [ sudo | su | pbrun | pfexec | runas ] +valid choices: [ sudo | su | pbrun | pfexec | runas | doas ] *--become-user=BECOME_USER*:: diff --git a/docs/man/man1/ansible.1 b/docs/man/man1/ansible.1 index 83bfc0500dd..7c6e79da8d2 100644 --- a/docs/man/man1/ansible.1 +++ b/docs/man/man1/ansible.1 @@ -84,7 +84,7 @@ seconds\&. .PP \fB\-\-become\-method=\fR\fIBECOME_METHOD\fR .RS 4 -Privilege escalation method to use (default=sudo), valid choices: [ sudo | su | pbrun | pfexec | runas ] +Privilege escalation method to use (default=sudo), valid choices: [ sudo | su | pbrun | pfexec | runas | doas ] .RE .PP \fB\-\-become\-user=\fR\fIBECOME_USER\fR diff --git a/docs/man/man1/ansible.1.asciidoc.in b/docs/man/man1/ansible.1.asciidoc.in index 26bd0144d4e..aaaac33c2af 100644 --- a/docs/man/man1/ansible.1.asciidoc.in +++ b/docs/man/man1/ansible.1.asciidoc.in @@ -65,7 +65,7 @@ Run commands in the background, killing the task after 'NUM' seconds. *--become-method=*'BECOME_METHOD':: Privilege escalation method to use (default=sudo), -valid choices: [ sudo | su | pbrun | pfexec | runas ] +valid choices: [ sudo | su | pbrun | pfexec | runas | doas ] *--become-user=*'BECOME_USER':: diff --git a/docsite/rst/become.rst b/docsite/rst/become.rst index 0d09e4116ed..c8738ef08a9 100644 --- a/docsite/rst/become.rst +++ b/docsite/rst/become.rst @@ -23,7 +23,7 @@ become_user equivalent to adding 'sudo_user:' or 'su_user:' to a play or task, set to user with desired privileges become_method - at play or task level overrides the default method set in ansible.cfg, set to 'sudo'/'su'/'pbrun'/'pfexec' + at play or task level overrides the default method set in ansible.cfg, set to 'sudo'/'su'/'pbrun'/'pfexec'/'doas' New ansible\_ variables @@ -54,7 +54,7 @@ New command line options --become-method=BECOME_METHOD privilege escalation method to use (default=sudo), - valid choices: [ sudo | su | pbrun | pfexec ] + valid choices: [ sudo | su | pbrun | pfexec | doas ] --become-user=BECOME_USER run operations as this user (default=root) diff --git a/docsite/rst/intro_configuration.rst b/docsite/rst/intro_configuration.rst index 60b89b7436c..2cf03a70d2d 100644 --- a/docsite/rst/intro_configuration.rst +++ b/docsite/rst/intro_configuration.rst @@ -651,7 +651,7 @@ The equivalent of adding sudo: or su: to a play or task, set to true/yes to acti become_method ============= -Set the privilege escalation method. The default is ``sudo``, other options are ``su``, ``pbrun``, ``pfexec``:: +Set the privilege escalation method. The default is ``sudo``, other options are ``su``, ``pbrun``, ``pfexec``, ``doas``:: become_method=su diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py index 37030276e8e..708058e6c5f 100644 --- a/lib/ansible/constants.py +++ b/lib/ansible/constants.py @@ -162,8 +162,8 @@ DEFAULT_SUDO_FLAGS = get_config(p, DEFAULTS, 'sudo_flags', 'ANSIBLE_SUDO_ DEFAULT_ASK_SUDO_PASS = get_config(p, DEFAULTS, 'ask_sudo_pass', 'ANSIBLE_ASK_SUDO_PASS', False, boolean=True) # Become -BECOME_ERROR_STRINGS = {'sudo': 'Sorry, try again.', 'su': 'Authentication failure', 'pbrun': '', 'pfexec': '', 'runas': ''} #FIXME: deal with i18n -BECOME_METHODS = ['sudo','su','pbrun','pfexec','runas'] +BECOME_ERROR_STRINGS = {'sudo': 'Sorry, try again.', 'su': 'Authentication failure', 'pbrun': '', 'pfexec': '', 'runas': '', 'doas': 'Permission denied'} #FIXME: deal with i18n +BECOME_METHODS = ['sudo','su','pbrun','pfexec','runas','doas'] DEFAULT_BECOME_METHOD = get_config(p, 'privilege_escalation', 'become_method', 'ANSIBLE_BECOME_METHOD','sudo' if DEFAULT_SUDO else 'su' if DEFAULT_SU else 'sudo' ).lower() DEFAULT_BECOME = get_config(p, 'privilege_escalation', 'become', 'ANSIBLE_BECOME',False, boolean=True) DEFAULT_BECOME_USER = get_config(p, 'privilege_escalation', 'become_user', 'ANSIBLE_BECOME_USER', 'root') diff --git a/lib/ansible/playbook/play_context.py b/lib/ansible/playbook/play_context.py index 6246419da3b..e57648d24e4 100644 --- a/lib/ansible/playbook/play_context.py +++ b/lib/ansible/playbook/play_context.py @@ -387,6 +387,20 @@ class PlayContext(Base): flags = self.become_flags or '' becomecmd = '%s %s /user:%s "%s"' % (exe, flags, self.become_user, success_cmd) + elif self.become_method == 'doas': + + prompt = 'Password:' + exe = self.become_exe or 'doas' + flags = self.become_flags or '' + + if not self.become_pass: + flags += ' -n ' + + if self.become_user: + flags += ' -u %s ' % self.become_user + + becomecmd = '%s %s echo %s && %s %s env ANSIBLE=true %s' % (exe, flags, success_key, exe, flags, cmd) + else: raise AnsibleError("Privilege escalation method not found: %s" % self.become_method) diff --git a/test/units/playbook/test_play_context.py b/test/units/playbook/test_play_context.py index 358e49f2187..0672ed38483 100644 --- a/test/units/playbook/test_play_context.py +++ b/test/units/playbook/test_play_context.py @@ -123,6 +123,8 @@ class TestPlayContext(unittest.TestCase): pbrun_flags = '' pfexec_exe = 'pfexec' pfexec_flags = '' + doas_exe = 'doas' + doas_flags = ' -n -u foo ' cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe) self.assertEqual(cmd, default_cmd) @@ -146,6 +148,10 @@ class TestPlayContext(unittest.TestCase): cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash") self.assertEqual(cmd, """%s -c '%s %s "'"'"'echo %s; %s'"'"'"'""" % (default_exe, pfexec_exe, pfexec_flags, play_context.success_key, default_cmd)) + play_context.become_method = 'doas' + cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash") + self.assertEqual(cmd, """%s -c '%s %s echo %s && %s %s env ANSIBLE=true %s'""" % (default_exe, doas_exe, doas_flags, play_context.success_key, doas_exe, doas_flags, default_cmd)) + play_context.become_method = 'bad' self.assertRaises(AnsibleError, play_context.make_become_cmd, cmd=default_cmd, executable="/bin/bash")