Ansible执行postgresql_query模块切换postgres用户报chmod错误
编写的Ansible Playbook代码如下:
- name: Check if postgres is running community.postgresql.postgresql_ping: db: "{{ stl_database }}" port: "{{ stl_postgres_port }}" login_host: "{{ db_host }}" login_password: "{{ postgres_password }}" register: postgres_availabe - name: Check the database versions postgresql_query: db: "{{ stl_database }}" port: "{{ stl_postgres_port }}" login_host: "{{ db_host }}" login_user: postgres login_password: "{{ postgres_password }}" query: "{{ get_db_version }}" become: yes become_user: postgres register: db_version_return when: postgres_availabe.is_available == true
已通过ansible-galaxy collection install community.postgresql命令安装依赖的社区集合。其中第一个任务用于检测远程服务器{{ db_host }}上的PostgreSQL服务是否正常运行,第二个任务调用postgresql_query模块,配置become: yes切换为postgres用户,执行{{ get_db_version }}定义的查询语句获取数据库版本,任务设置为仅在PostgreSQL服务可用时触发。
执行Playbook时第一个任务运行正常,第二个任务执行失败,报错信息如下:
fatal: [localhost]: FAILED! => {"msg": "Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user (rc: 1, err: chmod: invalid mode: ‘A+user:postgres:rx:allow’\nTry 'chmod --help' for more information.\n}). For information on working around this, see https://docs.ansible.com/ansible-core/2.12/user_guide/become.html#risks-of-becoming-an-unprivileged-user"}
添加-vvv参数查看详细执行日志,可发现Ansible在上传模块临时文件后,依次尝试执行setfacl赋权、chmod加执行权限、chown修改文件属主为postgres后,额外尝试执行chmod +a 'postgres allow read,execute'、chmod A+user:postgres:rx:allow命令为临时文件配置权限,最终在执行该chmod命令时失败。手动在服务器上执行相同chmod命令,同样返回chmod: invalid mode: ‘A+user:postgres:rx:allow’错误。
完全相同的Playbook代码在旧Ansible服务器上可长期正常运行,仅在新部署的、刚安装完community.postgresql集合的Ansible服务器上执行时出现上述错误。
- 报错中提到的
chmod A+user:postgres:rx:allow和chmod +a 'postgres allow read,execute'分别是AIX系统、BSD/macOS系统的chmod ACL语法,Linux系统默认使用的GNU版本chmod不支持这两种语法,直接执行必然报错。 - Ansible切换到非特权用户执行任务时,会按固定优先级顺序尝试多种方式给上传的临时模块文件赋权:优先使用setfacl配置POSIX ACL给目标用户授权,若setfacl执行失败,则依次尝试BSD风格chmod ACL、AIX风格chmod ACL,所有方式都失败就抛出上述错误。
- 新部署的服务器多为最小化安装环境,默认未安装提供
setfacl命令的acl工具包,导致Ansible第一步setfacl赋权失败,才会回退到后续不兼容的chmod语法分支,最终报错。旧服务器可正常运行是因为环境中已预装acl包,Ansible直接通过setfacl完成赋权,不会走到后续错误分支。
按优先级从高到低可选以下方案:
- 方案1(推荐,无安全风险):在被管理的目标服务器上安装acl工具包,对应不同发行版的安装命令:
- Debian/Ubuntu系列:执行
apt update && apt install -y acl - RHEL/CentOS/Rocky/AlmaLinux系列:执行
dnf install -y acl(CentOS 7等老版本用yum install -y acl)
安装完成后重新执行Playbook即可,Ansible会优先调用setfacl完成临时文件赋权,不会再触发不兼容的chmod命令。
- Debian/Ubuntu系列:执行
- 方案2(适合无法安装软件包的场景,有轻微安全风险):修改Ansible控制节点的ansible.cfg配置,在
[defaults]段添加如下配置,关闭ACL赋权逻辑,允许临时文件设为全局可读:
该配置会让Ansible直接给临时文件加全局可读权限,无需单独给postgres用户赋权,仅适合服务器全为可信内网主机的场景使用,避免多用户主机上的临时文件信息泄露。allow_world_readable_tmpfiles = True - 方案3(针对当前PostgreSQL场景的最优解,完全规避become逻辑):去掉第二个任务中的
become: yes和become_user: postgres配置。第一个任务未切换用户、仅通过密码连接PostgreSQL已经执行成功,说明数据库已允许对应账号通过TCP方式认证,第二个任务同样可以直接通过传入的连接参数完成查询,不需要切换到系统的postgres用户,从根源上避开临时文件赋权逻辑。
内容的提问来源于stack exchange,提问作者Philip Shangguan

