mirror of https://github.com/ansible/ansible.git
Fix local connection and become issues (#84700)
* Fixed various become-related issues in `local` connection plugin. * Fixed various issues in `sudo` and `su` become plugins. * Added unit and integration test coverage. Co-authored-by: Matt Clay <matt@mystile.com> Co-authored-by: Matt Davis <nitzmahone@redhat.com>pull/84727/head
parent
a4d4315d37
commit
5d7b8288f8
@ -0,0 +1,22 @@
|
||||
minor_changes:
|
||||
- local connection plugin - A new ``become_success_timeout`` operation-wide timeout config (default 10s) was added for ``become``.
|
||||
- local connection plugin - A new ``become_strip_preamble`` config option (default True) was added; disable to preserve diagnostic ``become`` output in task results.
|
||||
- local connection plugin - When a ``become`` plugin's ``prompt`` value is a non-string after the ``check_password_prompt`` callback has completed, no prompt stripping will occur on stderr.
|
||||
|
||||
bugfixes:
|
||||
- local connection plugin - Fixed silent ignore of ``become`` failures and loss of task output when data arrived concurrently on stdout and stderr during ``become`` operation validation.
|
||||
- local connection plugin - Fixed hang or spurious failure when data arrived concurrently on stdout and stderr during a successful ``become`` operation validation.
|
||||
- local connection plugin - Fixed task output header truncation when post-become data arrived before ``become`` operation validation had completed.
|
||||
- local connection plugin - Ensure ``become`` success validation always occurs, even when an active plugin does not set ``prompt``.
|
||||
- local connection plugin - Fixed cases where the internal ``BECOME-SUCCESS`` message appeared in task output.
|
||||
- local connection plugin - Fixed long timeout/hang for ``become`` plugins that repeat their prompt on failure (e.g., ``sudo``, some ``su`` implementations).
|
||||
- local connection plugin - Fixed hang when an active become plugin incorrectly signals lack of prompt.
|
||||
- local connection plugin - Fixed hang when a become plugin expects a prompt but a password was not provided.
|
||||
- local connection plugin - Fixed hang when an internal become read timeout expired before the password prompt was written.
|
||||
- local connection plugin - Fixed hang when only one of stdout or stderr was closed by the ``become_exe`` subprocess.
|
||||
- local connection plugin - Become timeout errors now include all received data. Previously, the most recently-received data was discarded.
|
||||
- sudo become plugin - The `sudo_chdir` config option allows the current directory to be set to the specified value before executing sudo to avoid permission errors when dropping privileges.
|
||||
- su become plugin - Ensure generated regex from ``prompt_l10n`` config values is properly escaped.
|
||||
- su become plugin - Ensure that password prompts are correctly detected in the presence of leading output. Previously, this case resulted in a timeout or hang.
|
||||
- su become plugin - Ensure that trailing colon is expected on all ``prompt_l10n`` config values.
|
||||
- ansible-test - Managed macOS instances now use the ``sudo_chdir`` option for the ``sudo`` become plugin to avoid permission errors when dropping privileges.
|
||||
@ -1,3 +1,9 @@
|
||||
destructive
|
||||
shippable/posix/group3
|
||||
context/controller
|
||||
shippable/posix/group1
|
||||
context/target
|
||||
gather_facts/no
|
||||
needs/target/setup_become_user_pair
|
||||
needs/target/setup_test_user
|
||||
setup/always/setup_passlib_controller # required for setup_test_user
|
||||
skip/macos # requires a TTY
|
||||
skip/freebsd # appears to require a TTY (ignores password input from stdin)
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
# A command wrapper that delegates to su after lowering privilege through an intermediate user (via sudo).
|
||||
# This allows forcing an environment that always requires a password prompt for su.
|
||||
|
||||
set -eu
|
||||
|
||||
args=("${@}")
|
||||
|
||||
for i in "${!args[@]}"; do
|
||||
case "${args[$i]}" in
|
||||
"--intermediate-user")
|
||||
intermediate_user_idx="${i}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
intermediate_user_name="${args[intermediate_user_idx+1]}"
|
||||
|
||||
unset "args[intermediate_user_idx]"
|
||||
unset "args[intermediate_user_idx+1]"
|
||||
|
||||
exec sudo -n -u "${intermediate_user_name}" su "${args[@]}"
|
||||
@ -1,6 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eux
|
||||
|
||||
# ensure we execute su with a pseudo terminal
|
||||
[ "$(ansible -a whoami --become-method=su localhost --become)" != "su: requires a terminal to execute" ]
|
||||
@ -0,0 +1,63 @@
|
||||
- name: create unprivileged user pair
|
||||
include_role:
|
||||
name: setup_become_user_pair
|
||||
public: true # this exports target_user_name, target_user_password, intermediate_user_name
|
||||
vars:
|
||||
intermediate_user_groups: "{{ 'staff,admin' if ansible_os_family == 'Darwin' else omit }}" # this works, but requires a TTY; disabled MacOS su testing in CI for now via aliases
|
||||
|
||||
- name: deploy su shim
|
||||
copy:
|
||||
src: sushim.sh
|
||||
dest: /tmp/sushim.sh
|
||||
mode: a+rx
|
||||
|
||||
- name: ensure su is setuid on Alpine
|
||||
file:
|
||||
path: /bin/su
|
||||
mode: +s
|
||||
when: ansible_os_family == 'Alpine'
|
||||
|
||||
- name: test su scenarios where a password prompt must be encountered
|
||||
vars:
|
||||
ansible_become: yes
|
||||
ansible_become_method: su
|
||||
ansible_become_exe: /tmp/sushim.sh
|
||||
ansible_become_flags: --intermediate-user {{ intermediate_user_name | quote }} # the default plugin flags are empty
|
||||
ansible_become_user: "{{ target_user_name }}"
|
||||
ansible_become_password: "{{ target_user_password }}"
|
||||
block:
|
||||
- name: basic success check
|
||||
raw: whoami
|
||||
register: success
|
||||
# NOTE: The ssh connection plugin does not properly strip noise from raw stdout, unlike the local connection plugin.
|
||||
# Once that is fixed, this can be changed to a comparison against stdout, not stdout_lines[-1].
|
||||
failed_when: success.stdout_lines[-1] != target_user_name
|
||||
|
||||
- name: validate that a password prompt is being used
|
||||
vars:
|
||||
ansible_become_password: BOGUSPASS
|
||||
raw: exit 99
|
||||
ignore_errors: yes
|
||||
register: bogus_password
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- | # account for different failure behavior between local and ssh
|
||||
bogus_password.msg is contains "Incorrect su password" or
|
||||
bogus_password.msg is contains "Premature end of stream waiting for become success." or
|
||||
(bogus_password.stdout | default('')) is contains "Sorry"
|
||||
|
||||
- name: test wrong su prompt expected
|
||||
raw: echo hi mom from $(whoami)
|
||||
register: wrong_su_prompt
|
||||
vars:
|
||||
ansible_su_prompt_l10n: NOT_A_VALID_PROMPT
|
||||
ansible_local_become_success_timeout: 3 # actual become success timeout
|
||||
ansible_ssh_timeout: 3 # connection timeout, which results in an N+2 second select timeout
|
||||
ignore_errors: yes
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- wrong_su_prompt is failed
|
||||
- ansible_connection != "local" or wrong_su_prompt.msg is contains "Timed out waiting for become success or become password prompt"
|
||||
- ansible_connection != "ssh" or wrong_su_prompt.msg is contains "waiting for privilege escalation prompt"
|
||||
@ -0,0 +1,7 @@
|
||||
destructive
|
||||
shippable/posix/group1
|
||||
context/target
|
||||
gather_facts/no
|
||||
needs/target/setup_become_user_pair
|
||||
needs/target/setup_test_user
|
||||
setup/always/setup_passlib_controller # required for setup_test_user
|
||||
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
# A command wrapper that delegates to sudo after lowering privilege through an intermediate user (via sudo).
|
||||
# This allows forcing an environment that always requires a password prompt for sudo.
|
||||
|
||||
set -eu
|
||||
|
||||
args=("${@}")
|
||||
|
||||
for i in "${!args[@]}"; do
|
||||
case "${args[$i]}" in
|
||||
"--intermediate-user")
|
||||
intermediate_user_idx="${i}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
intermediate_user_name="${args[intermediate_user_idx+1]}"
|
||||
|
||||
unset "args[intermediate_user_idx]"
|
||||
unset "args[intermediate_user_idx+1]"
|
||||
|
||||
exec sudo -n -u "${intermediate_user_name}" sudo -k "${args[@]}"
|
||||
@ -0,0 +1,84 @@
|
||||
- name: create unprivileged become user pair
|
||||
include_role:
|
||||
name: setup_become_user_pair
|
||||
public: true
|
||||
|
||||
- name: capture config values
|
||||
set_fact:
|
||||
# this needs to be looked up and stored before setting ansible_become_flags
|
||||
default_become_flags: "{{ lookup('config', 'become_flags', plugin_type='become', plugin_name='sudo') }}"
|
||||
intermediate_flags: --intermediate-user {{ intermediate_user_name | quote }}
|
||||
|
||||
- name: deploy sudo shim
|
||||
copy:
|
||||
src: sudoshim.sh
|
||||
dest: /tmp/sudoshim.sh
|
||||
mode: a+rx
|
||||
|
||||
- name: apply shared become vars to all tasks that use the sudo test shim
|
||||
vars:
|
||||
ansible_become: yes
|
||||
ansible_become_method: sudo
|
||||
ansible_become_user: '{{ target_user_name }}'
|
||||
ansible_become_password: '{{ intermediate_user_password }}'
|
||||
ansible_become_exe: /tmp/sudoshim.sh
|
||||
ansible_become_flags: '{{ default_become_flags }} {{ intermediate_flags }}'
|
||||
ansible_local_become_strip_preamble: true
|
||||
block:
|
||||
- name: basic success check
|
||||
raw: whoami
|
||||
register: success
|
||||
# NOTE: The ssh connection plugin does not properly strip noise from raw stdout, unlike the local connection plugin.
|
||||
# Once that is fixed, this can be changed to a comparison against stdout, not stdout_lines[-1].
|
||||
failed_when: success.stdout_lines[-1] != target_user_name
|
||||
|
||||
- name: validate that a password prompt is being used and that the shim is invalidating the sudo timestamp
|
||||
vars:
|
||||
ansible_become_password: BOGUSPASS
|
||||
raw: exit 99
|
||||
ignore_errors: true
|
||||
register: bogus_password
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- bogus_password.msg is contains "Incorrect sudo password" or bogus_password.msg is contains "Duplicate become password prompt encountered"
|
||||
|
||||
- name: request sudo chdir to a nonexistent root dir; expected failure
|
||||
raw: echo himom
|
||||
vars:
|
||||
ansible_sudo_chdir: /nonexistent_dir
|
||||
ignore_errors: true
|
||||
register: nonexistent_chdir
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- nonexistent_chdir is failed
|
||||
# deal with inconsistent failure behavior across different connection plugins
|
||||
- (nonexistent_chdir.msg ~ (nonexistent_chdir.stdout | default('')) ~ (nonexistent_chdir.stderr | default(''))) is search "cd.*/nonexistent_dir"
|
||||
|
||||
- name: request sudo chdir to /; cwd should successfully be / before sudo runs
|
||||
raw: echo "CWD IS <$(pwd)>"
|
||||
vars:
|
||||
ansible_sudo_chdir: /
|
||||
register: chdir_root
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- chdir_root.stdout is contains 'CWD IS </>'
|
||||
|
||||
- name: become with custom sudo `--` flags (similar to defaults)
|
||||
vars:
|
||||
ansible_become_flags: --set-home --stdin --non-interactive {{ intermediate_flags }}
|
||||
raw: whoami
|
||||
register: custom_flags
|
||||
|
||||
- name: become with no user
|
||||
vars:
|
||||
ansible_become_user: ""
|
||||
raw: whoami
|
||||
register: no_user
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- custom_flags.stdout.strip() == test_user_name
|
||||
- no_user.stdout.strip() == "root"
|
||||
@ -1,2 +1,6 @@
|
||||
shippable/posix/group5
|
||||
needs/target/connection
|
||||
needs/target/setup_become_user_pair
|
||||
needs/target/setup_test_user
|
||||
setup/once/setup_passlib_controller
|
||||
destructive
|
||||
|
||||
@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env bash
|
||||
# A wrapper around `sudo` that replaces the expected password prompt string (if given) with a bogus value.
|
||||
# This allows testing situations where the expected password prompt is not found.
|
||||
# This wrapper also supports becoming an intermediate user before executing sudo, to support testing as root.
|
||||
|
||||
set -eu
|
||||
|
||||
args=("${@}")
|
||||
intermediate_user_idx=''
|
||||
original_prompt=''
|
||||
shell_executable=''
|
||||
shell_command=''
|
||||
original_prompt_idx=''
|
||||
|
||||
# some args show up after others, but we need them before processing args that came before them
|
||||
for i in "${!args[@]}"; do
|
||||
case "${args[$i]}" in
|
||||
"-p")
|
||||
original_prompt="${args[i+1]}"
|
||||
original_prompt_idx="${i}"
|
||||
;;
|
||||
"-c")
|
||||
shell_executable="${args[i-1]}"
|
||||
shell_command="${args[i+1]}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
for i in "${!args[@]}"; do
|
||||
case "${args[$i]}" in
|
||||
"--inject-stdout-noise")
|
||||
echo "stdout noise"
|
||||
unset "args[i]"
|
||||
;;
|
||||
"--inject-stderr-noise")
|
||||
echo >&2 "stderr noise"
|
||||
unset "args[i]"
|
||||
;;
|
||||
"--bogus-prompt")
|
||||
args[original_prompt_idx+1]="BOGUSPROMPT"
|
||||
unset "args[i]"
|
||||
;;
|
||||
"--intermediate-user")
|
||||
intermediate_user_idx="${i}"
|
||||
;;
|
||||
"--close-stderr")
|
||||
>&2 echo "some injected stderr, EOF now"
|
||||
exec 2>&- # close stderr, doesn't seem to work on Ubuntu 24.04 (either not closed or not seen in Python?)
|
||||
unset "args[i]"
|
||||
;;
|
||||
"--sleep-before-sudo")
|
||||
sleep 3
|
||||
unset "args[i]"
|
||||
;;
|
||||
"--pretend-to-be-broken-passwordless-sudo")
|
||||
echo '{"hello":"not a module response"}'
|
||||
exit 0
|
||||
;;
|
||||
"--pretend-to-be-broken-sudo")
|
||||
echo -n "${original_prompt}"
|
||||
read -rs
|
||||
echo
|
||||
echo "success, but not invoking given command"
|
||||
exit 0
|
||||
;;
|
||||
"--pretend-to-be-sudo")
|
||||
echo -n "${original_prompt}"
|
||||
read -rs
|
||||
echo
|
||||
echo "success, invoking given command"
|
||||
"${shell_executable}" -c "${shell_command}"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "${intermediate_user_idx}" ]]; then
|
||||
# The current user can sudo without a password prompt, so delegate to an intermediate user first.
|
||||
intermediate_user_name="${args[intermediate_user_idx+1]}"
|
||||
|
||||
unset "args[intermediate_user_idx]"
|
||||
unset "args[intermediate_user_idx+1]"
|
||||
|
||||
exec sudo -n -u "${intermediate_user_name}" sudo -k "${args[@]}"
|
||||
else
|
||||
# The current user requires a password to sudo, so sudo can be used directly.
|
||||
exec sudo -k "${args[@]}"
|
||||
fi
|
||||
@ -0,0 +1,199 @@
|
||||
- hosts: testhost
|
||||
gather_facts: no
|
||||
tasks:
|
||||
- name: skip this test for non-root users
|
||||
block:
|
||||
- debug:
|
||||
msg: Skipping sudo test for non-root user.
|
||||
- meta: end_play
|
||||
when: lookup('pipe', 'whoami') != 'root'
|
||||
|
||||
- name: attempt root-to-root sudo become (no-op, should succeed)
|
||||
vars:
|
||||
ansible_become: yes
|
||||
ansible_become_user: root
|
||||
ansible_become_method: sudo
|
||||
raw: whoami
|
||||
register: root_noop_sudo
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- root_noop_sudo.stdout is contains "root"
|
||||
|
||||
- name: create an unprivileged become user pair
|
||||
include_role:
|
||||
name: setup_become_user_pair
|
||||
public: true
|
||||
|
||||
- name: deploy sudo shim
|
||||
copy:
|
||||
src: sudoshim.sh
|
||||
dest: /tmp/sudoshim.sh
|
||||
mode: u+x
|
||||
|
||||
- set_fact:
|
||||
default_sudo_flags: "{{ lookup('config', 'become_flags', plugin_type='become', plugin_name='sudo') }}"
|
||||
|
||||
- name: apply shared become vars to all tasks that use the sudo test shim
|
||||
vars:
|
||||
ansible_become: yes
|
||||
ansible_become_method: sudo
|
||||
ansible_become_user: '{{ target_user_name }}'
|
||||
ansible_become_password: '{{ target_user_password }}'
|
||||
ansible_become_exe: /tmp/sudoshim.sh
|
||||
ansible_local_become_strip_preamble: true
|
||||
intermediate: "{{ ((' --intermediate-user ' + intermediate_user_name) if intermediate_user_name is defined else '') }}"
|
||||
block:
|
||||
- name: verify stdout/stderr noise is present with preamble strip disabled
|
||||
raw: echo $(whoami) ran
|
||||
vars:
|
||||
ansible_become_flags: "{{ default_sudo_flags ~ intermediate ~ ' --inject-stdout-noise --inject-stderr-noise' }}"
|
||||
ansible_become_password: "{{ intermediate_user_password }}"
|
||||
ansible_local_become_strip_preamble: false
|
||||
ansible_pipelining: true
|
||||
register: preamble_visible
|
||||
|
||||
- name: verify stdout/stderr noise is stripped with preamble strip enabled
|
||||
raw: echo $(whoami) ran
|
||||
vars:
|
||||
ansible_become_flags: "{{ default_sudo_flags ~ intermediate ~ ' --inject-stdout-noise --inject-stderr-noise' }}"
|
||||
ansible_become_password: "{{ intermediate_user_password }}"
|
||||
ansible_pipelining: true
|
||||
register: preamble_stripped
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- preamble_visible.stdout is contains(target_user_name ~ " ran")
|
||||
- preamble_stripped.stdout is contains(target_user_name ~ " ran")
|
||||
- preamble_visible.stdout is contains "stdout noise"
|
||||
- preamble_stripped.stdout is not contains "stdout noise"
|
||||
- preamble_visible.stderr is contains "stderr noise"
|
||||
- preamble_stripped.stderr is not contains "stderr noise"
|
||||
|
||||
- name: verify sudo succeeds with a password (no PTY/pipelined)
|
||||
raw: echo $(whoami) ran
|
||||
vars:
|
||||
ansible_become_flags: "{{ default_sudo_flags ~ intermediate }}"
|
||||
ansible_become_password: "{{ intermediate_user_password }}"
|
||||
ansible_local_become_strip_preamble: false # allow prompt sniffing from the output
|
||||
ansible_pipelining: true
|
||||
register: success_pipelined
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- success_pipelined.stdout is contains(target_user_name ~ " ran")
|
||||
- success_pipelined.stderr is search 'sudo via ansible.*password\:'
|
||||
|
||||
- name: verify sudo works with a PTY allocated (pipelining disabled)
|
||||
raw: echo $(whoami) ran without pipelining
|
||||
vars:
|
||||
ansible_become_flags: "{{ default_sudo_flags ~ intermediate }}"
|
||||
ansible_become_password: "{{ intermediate_user_password }}"
|
||||
ansible_local_become_strip_preamble: false
|
||||
ansible_pipelining: no # a PTY is allocated by the local plugin only when pipelining is disabled
|
||||
register: pty_non_pipelined
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- pty_non_pipelined.stdout is contains(test_user_name ~ " ran without pipelining")
|
||||
|
||||
- name: verify early-closed stderr still sees success
|
||||
# this test triggers early EOF (which unregisters the associated selector) on most OSs, but not on Ubuntu 24.04
|
||||
vars:
|
||||
ansible_become_flags: --close-stderr --sleep-before-sudo --pretend-to-be-sudo
|
||||
ansible_local_become_success_timeout: 5
|
||||
raw: echo ran_ok
|
||||
register: stderr_closed
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- stderr_closed.stderr is contains "some injected stderr, EOF now"
|
||||
- stderr_closed.stdout is contains "ran_ok"
|
||||
|
||||
- name: verify timeout handling by setting a sudo prompt that won't trigger password send
|
||||
vars:
|
||||
ansible_become_flags: "{{ default_sudo_flags ~ intermediate }} --bogus-prompt"
|
||||
ansible_local_become_success_timeout: 2
|
||||
raw: exit 99
|
||||
ignore_errors: true
|
||||
register: prompt_timeout
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- prompt_timeout is failed
|
||||
- prompt_timeout.msg is contains "Timed out waiting for become success or become password prompt"
|
||||
- prompt_timeout.msg is contains "BOGUSPROMPT"
|
||||
- prompt_timeout.rc is not defined
|
||||
|
||||
- name: verify sub 1s timeout is always increased
|
||||
vars:
|
||||
ansible_become_flags: "{{ default_sudo_flags ~ ' --sleep-before-sudo' }}"
|
||||
ansible_local_become_success_timeout: 0 # a 0s timeout would always cause select to be skipped in the current impl, but added a 2s sleep in the shim in case that changes
|
||||
raw: whoami
|
||||
register: timeout_increased
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- timeout_increased.stdout is contains target_user_name
|
||||
|
||||
- name: verify handling of premature exit/stream closure
|
||||
vars:
|
||||
ansible_become_exe: /bogus
|
||||
raw: exit 99
|
||||
ignore_errors: true
|
||||
register: early_close
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- early_close is failed
|
||||
- early_close.msg is contains "Premature end of stream"
|
||||
|
||||
- name: verify lack of required password fails as expected
|
||||
raw: exit 99
|
||||
vars:
|
||||
ansible_become_flags: "{{ default_sudo_flags ~ intermediate }}"
|
||||
ansible_become_password: ~
|
||||
ignore_errors: true
|
||||
register: missing_required_password
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- missing_required_password is failed
|
||||
- missing_required_password.msg is contains "password is required"
|
||||
|
||||
- name: verify duplicate password prompts are handled (due to incorrect password)
|
||||
raw: echo hi mom
|
||||
vars:
|
||||
ansible_become_flags: "{{ default_sudo_flags ~ intermediate }}"
|
||||
ansible_become_password: not_the_correct_password
|
||||
ignore_errors: yes
|
||||
register: incorrect_password
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- incorrect_password is failed
|
||||
- incorrect_password.msg is contains "Duplicate become password prompt encountered"
|
||||
|
||||
- name: no error, but no become success message
|
||||
vars:
|
||||
ansible_become_flags: --pretend-to-be-broken-sudo # handle password prompt, but return no output
|
||||
raw: exit 99 # should never actually run anyway
|
||||
ignore_errors: true
|
||||
register: no_become_success
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- no_become_success is failed
|
||||
- no_become_success.msg is contains "Premature end of stream waiting for become success"
|
||||
|
||||
- name: test broken passwordless sudo
|
||||
raw: echo hi mom
|
||||
vars:
|
||||
ansible_become_flags: --pretend-to-be-broken-passwordless-sudo
|
||||
ignore_errors: yes
|
||||
register: broken_passwordless_sudo
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- broken_passwordless_sudo is failed
|
||||
- broken_passwordless_sudo.msg is contains "not a module response"
|
||||
@ -0,0 +1,2 @@
|
||||
target_user_name: ansibletest0 # target unprivileged user
|
||||
intermediate_user_name: ansibletest1 # an intermediate user
|
||||
@ -0,0 +1,24 @@
|
||||
- name: create an unprivileged user on target
|
||||
include_role:
|
||||
name: setup_test_user
|
||||
public: true
|
||||
vars:
|
||||
test_user_name: '{{ target_user_name }}'
|
||||
test_user_groups: '{{ target_user_groups | default(omit) }}'
|
||||
|
||||
- name: capture target user password
|
||||
set_fact:
|
||||
target_user_password: '{{ test_user_plaintext_password }}'
|
||||
|
||||
- name: create an intermediate user on target with password-required sudo ability
|
||||
include_role:
|
||||
name: setup_test_user
|
||||
public: true
|
||||
vars:
|
||||
test_user_name: "{{ intermediate_user_name }}"
|
||||
test_user_groups: '{{ intermediate_user_groups | default(omit) }}'
|
||||
test_user_allow_sudo: true
|
||||
|
||||
- name: capture config values, intermediate user password from role
|
||||
set_fact:
|
||||
intermediate_user_password: "{{ test_user_plaintext_password }}"
|
||||
@ -0,0 +1,5 @@
|
||||
# true/false/nopasswd
|
||||
test_user_allow_sudo: false
|
||||
test_user_name: ansibletest0
|
||||
test_user_group: ~
|
||||
test_user_groups: ~
|
||||
@ -1,6 +1,7 @@
|
||||
- name: delete test user
|
||||
user:
|
||||
name: "{{ test_user_name }}"
|
||||
name: "{{ item }}"
|
||||
state: absent
|
||||
remove: yes
|
||||
force: yes
|
||||
loop: "{{ delete_users }}"
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
- name: probe for sudoers config path
|
||||
shell: visudo -c
|
||||
ignore_errors: true
|
||||
register: visudo_result
|
||||
|
||||
- set_fact:
|
||||
sudoers_path: '{{ ((visudo_result.stdout ~ visudo_result.stderr) | regex_search("(/.*sudoers).*:", "\1"))[0] }}'
|
||||
|
||||
- name: allow the user to use sudo {{"with no password" if test_user_allow_sudo == "nopasswd" else "with a password"}}
|
||||
copy:
|
||||
content: |
|
||||
{{ test_user_name }} ALL=(ALL) {{"NOPASSWD: " if test_user_allow_sudo == "nopasswd" else ""}} ALL
|
||||
mode: '0440'
|
||||
dest: '{{ sudoers_path ~ ".d/" ~ test_user_name }}'
|
||||
Loading…
Reference in New Issue