You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ubuntu24.04下Ansible嵌套sudo执行失败的原因及解决方案咨询

Ansible跨版本sudo嵌套调用失败问题排查与解决

问题复现

涉及文件

  1. child.py(要求不能用sudo直接执行):
# child.py
# This program must NOT been executed with sudo

import subprocess

subprocess.run(['sudo', 'apt-get', 'update'], check=True)
  1. Ansible角色任务文件 playbooks/roles/debug_role/tasks/main.yml:
- name: Debug sudo in child process
   command: >-
     sudo -E -H -u {{ ansible_user }} \
     /bin/bash -lc "python3 child.py"
   become: yes
  1. Ansible剧本 playbooks/playbook.yml:
- hosts: all
  roles: [debug_role]

执行差异

  • Ubuntu 20.04 + Ansible core 2.12.10:执行以下命令后任务成功,apt-get update正常在目标机器运行:
ansible-playbook -i inventory.yml -u ubuntu --ask-become-pass playbooks/playbook.yml
  • Ubuntu 24.04 + Ansible core 2.17.8:执行同一命令,输入正确become密码后仍报错:
stderr: 'sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper'
  stderr_lines: <omitted>
  stdout: ''
  stdout_lines: <omitted>

原因分析

问题核心是Ansible版本对sudo执行环境的处理变化:

  • 旧版Ansible(2.12)在become: yes的root环境中,切换回普通用户时,默认保留了sudo的免密上下文,或者对非交互式环境的sudo嵌套调用限制较松;
  • 新版Ansible(2.17)严格遵循sudo的安全规范:Ansible任务默认运行在非交互式终端环境,当普通用户在这个环境下再次调用sudo时,没有TTY终端用于输入密码,直接触发报错。
    Ubuntu 24.04默认的sudo配置更严格,进一步凸显了这个差异,但本质是Ansible新版本对执行环境的管控更规范。

解决办法(满足child.py不被sudo直接执行的前提)

方案1:给子进程sudo传递密码

通过环境变量把Ansible的become密码传递给child.py,让sudo从标准输入读取密码:

  1. 修改Ansible任务,传递密码并开启日志隐藏:
- name: Debug sudo in child process
   command: >-
     sudo -E -H -u {{ ansible_user }} \
     /bin/bash -lc "export SUDO_PASS='{{ ansible_become_pass }}'; python3 child.py"
   become: yes
   no_log: true  # 必须添加,防止密码泄露到日志
  1. 修改child.py,使用sudo -S选项读取密码:
# child.py
# This program must NOT been executed with sudo

import subprocess
import os

sudo_pass = os.environ.get('SUDO_PASS', '').encode('utf-8')
# 用-S让sudo从标准输入读密码,同时重定向输出避免干扰
subprocess.run(
    ['sudo', '-S', 'apt-get', 'update'],
    input=sudo_pass,
    check=True,
    stderr=subprocess.PIPE,
    stdout=subprocess.PIPE
)

方案2:配置目标用户sudo免密(针对特定命令)

在目标机器上配置sudoers,允许普通用户无需密码执行apt-get update:
添加Ansible任务配置sudo规则(需谨慎操作,避免破坏系统安全):

- name: Allow ansible user to run apt-get update without password
   lineinfile:
     path: /etc/sudoers.d/ansible_apt_update
     line: "{{ ansible_user }} ALL=(ALL) NOPASSWD: /usr/bin/apt-get update"
     state: present
     mode: 0440
     validate: '/usr/sbin/visudo -cf %s'  # 验证sudoers配置正确性
   become: yes

配置完成后,原child.py和Ansible任务无需修改即可正常执行。

方案3:用runuser替代sudo切换用户

既然Ansible已经处于root环境,使用runuser切换到普通用户,它比sudo -u更适合root环境下的用户切换,且能保留足够上下文让sudo免密执行:
修改Ansible任务为:

- name: Debug sudo in child process
   command: >-
     runuser -l {{ ansible_user }} -c "python3 child.py"
   become: yes

注意:此方案依赖目标用户的sudo配置允许免密执行对应命令,或Ansible的become上下文传递了相关权限。


内容的提问来源于stack exchange,提问作者furushchev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 03:58:16