From d54f5277d50748abb4117a29b9e5cff338cfea09 Mon Sep 17 00:00:00 2001 From: Will Thames Date: Fri, 2 Sep 2016 06:54:31 +1000 Subject: [PATCH] Add ksu privilege escalation (#17340) Allow ksu privilege escalation to be used as a standard become_method https://web.mit.edu/kerberos/krb5-1.12/doc/user/user_commands/ksu.html --- CHANGELOG.md | 1 + docsite/rst/become.rst | 6 +++--- docsite/rst/intro_configuration.rst | 2 +- lib/ansible/constants.py | 6 +++--- lib/ansible/playbook/play_context.py | 7 +++++++ test/units/playbook/test_play_context.py | 6 ++++++ 6 files changed, 21 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b256e467f7..4774b209d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ Ansible Changes By Release * Added a new `meta` option: `end_play`, which can be used to skip to the end of a play. * `meta` tasks can now use conditionals. * `raw` now returns `changed: true` to be consistent with shell/command/script modules. Add `changed_when: false` to `raw` tasks to restore the pre-2.2 behavior if necessary. +* New privilege escalation become method `ksu` ####New Modules: - archive diff --git a/docsite/rst/become.rst b/docsite/rst/become.rst index 96de2827c7..82a63a8ce4 100644 --- a/docsite/rst/become.rst +++ b/docsite/rst/become.rst @@ -8,7 +8,7 @@ Ansible can use existing privilege escalation systems to allow a user to execute Become `````` Ansible allows you to 'become' another user, different from the user that logged into the machine (remote user). This is done using existing -privilege escalation tools, which you probably already use or have configured, like `sudo`, `su`, `pfexec`, `doas`, `pbrun`, `dzdo`, and others. +privilege escalation tools, which you probably already use or have configured, like `sudo`, `su`, `pfexec`, `doas`, `pbrun`, `dzdo`, `ksu` and others. .. note:: Before 1.9 Ansible mostly allowed the use of `sudo` and a limited use of `su` to allow a login/remote user to become a different user @@ -29,7 +29,7 @@ become_user set to user with desired privileges — the user you 'become', NOT the user you login as. Does NOT imply `become: yes`, to allow it to be set at host level. become_method - (at play or task level) overrides the default method set in ansible.cfg, set to `sudo`/`su`/`pbrun`/`pfexec`/`doas`/`dzdo` + (at play or task level) overrides the default method set in ansible.cfg, set to `sudo`/`su`/`pbrun`/`pfexec`/`doas`/`dzdo`/`ksu` become_flags (at play or task level) permit to use specific flags for the tasks or role. One common use is to change user to nobody when the shell is set to no login @@ -89,7 +89,7 @@ New command line options --become-method=BECOME_METHOD privilege escalation method to use (default=sudo), - valid choices: [ sudo | su | pbrun | pfexec | doas | dzdo ] + valid choices: [ sudo | su | pbrun | pfexec | doas | dzdo | ksu ] --become-user=BECOME_USER run operations as this user (default=root), does not imply --become/-b diff --git a/docsite/rst/intro_configuration.rst b/docsite/rst/intro_configuration.rst index 1a0402b2b5..0028dcd74a 100644 --- a/docsite/rst/intro_configuration.rst +++ b/docsite/rst/intro_configuration.rst @@ -824,7 +824,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``, ``doas``:: +Set the privilege escalation method. The default is ``sudo``, other options are ``su``, ``pbrun``, ``pfexec``, ``doas``, ``ksu``:: become_method=su diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py index f29728e639..04d2c5e989 100644 --- a/lib/ansible/constants.py +++ b/lib/ansible/constants.py @@ -213,9 +213,9 @@ 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': '', 'doas': 'Permission denied', 'dzdo': ''} #FIXME: deal with i18n -BECOME_MISSING_STRINGS = {'sudo': 'sorry, a password is required to run sudo', 'su': '', 'pbrun': '', 'pfexec': '', 'runas': '', 'doas': 'Authorization required', 'dzdo': ''} #FIXME: deal with i18n -BECOME_METHODS = ['sudo','su','pbrun','pfexec','runas','doas','dzdo'] +BECOME_ERROR_STRINGS = {'sudo': 'Sorry, try again.', 'su': 'Authentication failure', 'pbrun': '', 'pfexec': '', 'runas': '', 'doas': 'Permission denied', 'dzdo': '', 'ksu': 'Password incorrect'} #FIXME: deal with i18n +BECOME_MISSING_STRINGS = {'sudo': 'sorry, a password is required to run sudo', 'su': '', 'pbrun': '', 'pfexec': '', 'runas': '', 'doas': 'Authorization required', 'dzdo': '', 'ksu': 'No password given'} #FIXME: deal with i18n +BECOME_METHODS = ['sudo','su','pbrun','pfexec','runas','doas','dzdo','ksu'] BECOME_ALLOW_SAME_USER = get_config(p, 'privilege_escalation', 'become_allow_same_user', 'ANSIBLE_BECOME_ALLOW_SAME_USER', False, boolean=True) 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) diff --git a/lib/ansible/playbook/play_context.py b/lib/ansible/playbook/play_context.py index a28111c689..b03d47d371 100644 --- a/lib/ansible/playbook/play_context.py +++ b/lib/ansible/playbook/play_context.py @@ -522,6 +522,13 @@ class PlayContext(Base): prompt='assword:' becomecmd = '%s -b %s -u %s %s' % (exe, flags, self.become_user, success_cmd) + elif self.become_method == 'ksu': + def detect_ksu_prompt(data): + return re.match("Kerberos password for .*@.*:", data) + + prompt = detect_ksu_prompt + becomecmd = '%s %s %s -e %s' % (exe, self.become_user, flags, command) + elif self.become_method == 'pfexec': # No user as it uses it's own exec_attr to figure it out diff --git a/test/units/playbook/test_play_context.py b/test/units/playbook/test_play_context.py index 1f52fc1678..9e94f615bb 100644 --- a/test/units/playbook/test_play_context.py +++ b/test/units/playbook/test_play_context.py @@ -131,6 +131,8 @@ class TestPlayContext(unittest.TestCase): pfexec_flags = '' doas_exe = 'doas' doas_flags = ' -n -u foo ' + ksu_exe = 'ksu' + ksu_flags = '' dzdo_exe = 'dzdo' cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe) @@ -164,6 +166,10 @@ class TestPlayContext(unittest.TestCase): cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash") self.assertEqual(cmd, """%s %s echo %s && %s %s env ANSIBLE=true %s""" % (doas_exe, doas_flags, play_context.success_key, doas_exe, doas_flags, default_cmd)) + play_context.become_method = 'ksu' + cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash") + self.assertEqual(cmd, """%s %s %s -e %s -c 'echo %s; %s'""" % (ksu_exe, play_context.become_user, ksu_flags, default_exe, play_context.success_key, default_cmd)) + play_context.become_method = 'bad' self.assertRaises(AnsibleError, play_context.make_become_cmd, cmd=default_cmd, executable="/bin/bash")