From 313a46744df991588206d797fa5d0fd0860af9ce Mon Sep 17 00:00:00 2001 From: Antoine Pietri Date: Fri, 25 May 2018 17:52:53 +0200 Subject: [PATCH] Add a 'machinectl shell' become_method (#39826) * Add a 'machinectl shell' become_method * docs: add explanations for the machinectl become_method * docs: machinectl become_method: specify this part is specific to Linux+systemd setups --- docs/docsite/rst/user_guide/become.rst | 33 ++++++++++++++++++++++--- lib/ansible/constants.py | 4 ++- lib/ansible/modules/commands/command.py | 2 +- lib/ansible/playbook/play_context.py | 5 ++++ 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/docs/docsite/rst/user_guide/become.rst b/docs/docsite/rst/user_guide/become.rst index 7f2587f8f94..ae6d54a937d 100644 --- a/docs/docsite/rst/user_guide/become.rst +++ b/docs/docsite/rst/user_guide/become.rst @@ -11,7 +11,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 such as `sudo`, `su`, `pfexec`, `doas`, `pbrun`, `dzdo`, `ksu`, `runas` and others. +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 such as `sudo`, `su`, `pfexec`, `doas`, `pbrun`, `dzdo`, `ksu`, `runas`, `machinectl` and others. .. note:: Prior to version 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 and execute tasks and create resources with the second user's permissions. As of Ansible version 1.9, `become` supersedes the old sudo/su, while still being backwards compatible. This new implementation also makes it easier to add other privilege escalation tools, including `pbrun` (Powerbroker), `pfexec`, `dzdo` (Centrify), and others. @@ -31,7 +31,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`/`ksu`/`runas` + (at play or task level) overrides the default method set in ansible.cfg, set to `sudo`/`su`/`pbrun`/`pfexec`/`doas`/`dzdo`/`ksu`/`runas`/`machinectl` become_flags (at play or task level) permit the use of specific flags for the tasks or role. One common use is to change the user to nobody when the shell is set to no login. Added in Ansible 2.2. @@ -91,7 +91,7 @@ Command line options --become-method=BECOME_METHOD privilege escalation method to use (default=sudo), - valid choices: [ sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas ] + valid choices: [ sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas | machinectl ] --become-user=BECOME_USER run operations as this user (default=root), does not imply --become/-b @@ -208,6 +208,33 @@ or '/bin/chmod' as the allowed commands this will fail with ansible as those paths won't match with the temporary file that ansible creates to run the module. +Environment variables populated by pam_systemd +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For most Linux distributions using ``systemd`` as their init, the default +methods used by ``become`` do not open a new "session", in the sense of +systemd. Because the ``pam_systemd`` module will not fully initialize a new +session, you might have surprises compared to a normal session opened through +ssh: some environment variables set by ``pam_systemd``, most notably +``XDG_RUNTIME_DIR``, are not populated for the new user and instead inherited +or just emptied. + +This might cause trouble when trying to invoke systemd commands that depend on +``XDG_RUNTIME_DIR`` to access the bus: + +.. code-block:: console + + $ echo $XDG_RUNTIME_DIR + + $ systemctl --user status + Failed to connect to bus: Permission denied + +To force ``become`` to open a new systemd session that goes through +``pam_systemd``, you can use ``become_method: machinectl``. + +For more information, see `this systemd issue +`_. + .. _become-network: Become and Networks diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py index cdf2d5fff8e..e922b506e0e 100644 --- a/lib/ansible/constants.py +++ b/lib/ansible/constants.py @@ -59,7 +59,7 @@ def set_constant(name, value, export=vars()): # CONSTANTS ### yes, actual ones -BECOME_METHODS = ['sudo', 'su', 'pbrun', 'pfexec', 'doas', 'dzdo', 'ksu', 'runas', 'pmrun', 'enable'] +BECOME_METHODS = ['sudo', 'su', 'pbrun', 'pfexec', 'doas', 'dzdo', 'ksu', 'runas', 'pmrun', 'enable', 'machinectl'] BECOME_ERROR_STRINGS = { 'sudo': 'Sorry, try again.', 'su': 'Authentication failure', @@ -70,6 +70,7 @@ BECOME_ERROR_STRINGS = { 'ksu': 'Password incorrect', 'pmrun': 'You are not permitted to run this command', 'enable': '', + 'machinectl': '', } # FIXME: deal with i18n BECOME_MISSING_STRINGS = { 'sudo': 'sorry, a password is required to run sudo', @@ -81,6 +82,7 @@ BECOME_MISSING_STRINGS = { 'ksu': 'No password given', 'pmrun': '', 'enable': '', + 'machinectl': '', } # FIXME: deal with i18n BLACKLIST_EXTS = ('.pyc', '.pyo', '.swp', '.bak', '~', '.rpm', '.md', '.txt') BOOL_TRUE = BOOLEANS_TRUE diff --git a/lib/ansible/modules/commands/command.py b/lib/ansible/modules/commands/command.py index 694604a5d24..2f990e378a8 100644 --- a/lib/ansible/modules/commands/command.py +++ b/lib/ansible/modules/commands/command.py @@ -142,7 +142,7 @@ def check_command(module, commandline): 'mount': 'mount', 'rpm': 'yum, dnf or zypper', 'yum': 'yum', 'apt-get': 'apt', 'tar': 'unarchive', 'unzip': 'unarchive', 'sed': 'replace, lineinfile or template', 'dnf': 'dnf', 'zypper': 'zypper'} - become = ['sudo', 'su', 'pbrun', 'pfexec', 'runas', 'pmrun'] + become = ['sudo', 'su', 'pbrun', 'pfexec', 'runas', 'pmrun', 'machinectl'] if isinstance(commandline, list): command = commandline[0] else: diff --git a/lib/ansible/playbook/play_context.py b/lib/ansible/playbook/play_context.py index 0256045b3ce..a531deff22d 100644 --- a/lib/ansible/playbook/play_context.py +++ b/lib/ansible/playbook/play_context.py @@ -557,6 +557,11 @@ class PlayContext(Base): prompt = 'Enter UPM user password:' becomecmd = '%s %s %s' % (exe, flags, shlex_quote(command)) + elif self.become_method == 'machinectl': + + exe = self.become_exe or 'machinectl' + becomecmd = '%s shell -q %s %s@ %s' % (exe, flags, self.become_user, command) + else: raise AnsibleError("Privilege escalation method not found: %s" % self.become_method)