mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
* Add support for `sudo su -` using password auth
Allow users to run Ansible tasks through `sudo su -` using password auth
- Feature Pull Request
sudosu
So I have been using this at various customers for bootstrapping Ansible mostly.
Often you have an existing setup where there is a user that has root-access enabled through sudo, but only to run `su` to log using the user's password.
In these specific cases the root password is unique to the system and therefore not an easy way to automate bootstrapping.
Having a `sudo su -` become option **with password prompt** is not possible with the existing become methods (neither sudo nor su can be used) by abusing `become_exe` or `become_flags`.
This fixes ansible/ansible#12686
* Fix all reported issues
* Add unit tests
* Apply suggestions from code review
* Update plugins/become/sudosu.py
Co-authored-by: Felix Fontein <felix@fontein.de>
* Update tests/unit/plugins/become/test_sudosu.py
Co-authored-by: Felix Fontein <felix@fontein.de>
* Update tests/unit/plugins/become/test_sudosu.py
Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit db26514bf1
)
Co-authored-by: Dag Wieers <dag@wieers.com>
This commit is contained in:
parent
6d2d364a00
commit
eccc8d88b6
2 changed files with 136 additions and 0 deletions
91
plugins/become/sudosu.py
Normal file
91
plugins/become/sudosu.py
Normal file
|
@ -0,0 +1,91 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright: (c) 2021, Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = """
|
||||
become: sudosu
|
||||
short_description: Run tasks using sudo su -
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user via the C(sudo) and C(su) utilities combined.
|
||||
author:
|
||||
- Dag Wieers (@dagwieers)
|
||||
version_added: 2.4.0
|
||||
options:
|
||||
become_user:
|
||||
description: User you 'become' to execute the task.
|
||||
default: root
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: sudo_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_sudo_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_SUDO_USER
|
||||
become_flags:
|
||||
description: Options to pass to C(sudo).
|
||||
default: -H -S -n
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: sudo_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_sudo_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_SUDO_FLAGS
|
||||
become_pass:
|
||||
description: Password to pass to C(sudo).
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_become_password
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_sudo_pass
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_SUDO_PASS
|
||||
ini:
|
||||
- section: sudo_become_plugin
|
||||
key: password
|
||||
"""
|
||||
|
||||
|
||||
from ansible.plugins.become import BecomeBase
|
||||
|
||||
|
||||
class BecomeModule(BecomeBase):
|
||||
|
||||
name = 'community.general.sudosu'
|
||||
|
||||
# messages for detecting prompted password issues
|
||||
fail = ('Sorry, try again.',)
|
||||
missing = ('Sorry, a password is required to run sudo', 'sudo: a password is required')
|
||||
|
||||
def build_become_command(self, cmd, shell):
|
||||
super(BecomeModule, self).build_become_command(cmd, shell)
|
||||
|
||||
if not cmd:
|
||||
return cmd
|
||||
|
||||
becomecmd = 'sudo'
|
||||
|
||||
flags = self.get_option('become_flags') or ''
|
||||
prompt = ''
|
||||
if self.get_option('become_pass'):
|
||||
self.prompt = '[sudo via ansible, key=%s] password:' % self._id
|
||||
if flags: # this could be simplified, but kept as is for now for backwards string matching
|
||||
flags = flags.replace('-n', '')
|
||||
prompt = '-p "%s"' % (self.prompt)
|
||||
|
||||
user = self.get_option('become_user') or ''
|
||||
if user:
|
||||
user = '%s' % (user)
|
||||
|
||||
return ' '.join([becomecmd, flags, prompt, 'su -l', user, self._build_success_command(cmd, shell)])
|
45
tests/unit/plugins/become/test_sudosu.py
Normal file
45
tests/unit/plugins/become/test_sudosu.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
|
||||
# (c) 2021 Ansible Project
|
||||
#
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# Make coding more python3-ish
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import re
|
||||
|
||||
from ansible import context
|
||||
from ansible.playbook.play_context import PlayContext
|
||||
from ansible.plugins.loader import become_loader
|
||||
|
||||
|
||||
def test_sudosu(mocker, parser, reset_cli_args):
|
||||
options = parser.parse_args([])
|
||||
context._init_global_context(options)
|
||||
play_context = PlayContext()
|
||||
|
||||
default_cmd = "/bin/foo"
|
||||
default_exe = "/bin/bash"
|
||||
sudo_exe = 'sudo'
|
||||
sudo_flags = '-H -s -n'
|
||||
|
||||
cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
|
||||
assert cmd == default_cmd
|
||||
|
||||
success = 'BECOME-SUCCESS-.+?'
|
||||
|
||||
play_context.become = True
|
||||
play_context.become_user = 'foo'
|
||||
play_context.set_become_plugin(become_loader.get('community.general.sudosu'))
|
||||
play_context.become_flags = sudo_flags
|
||||
cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
|
||||
|
||||
assert (re.match("""%s %s su -l %s %s -c 'echo %s; %s'""" % (sudo_exe, sudo_flags, play_context.become_user,
|
||||
default_exe, success, default_cmd), cmd) is not None)
|
||||
|
||||
play_context.become_pass = 'testpass'
|
||||
cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
|
||||
assert (re.match("""%s %s -p "%s" su -l %s %s -c 'echo %s; %s'""" % (sudo_exe, sudo_flags.replace('-n', ''),
|
||||
r"\[sudo via ansible, key=.+?\] password:", play_context.become_user,
|
||||
default_exe, success, default_cmd), cmd) is not None)
|
Loading…
Reference in a new issue