Ansible 使用 copy 模块报错 Permission denied 如何提权?
遇到 Ansible copy 模块报 Permission denied 错误,通常是因为远程登录用户没有目标目录的写入权限,最推荐的处理方式是在任务或 Play 中启用 become 提权。
先说结论:这不是 Ansible 软件缺陷,而是 Linux 权限控制机制的正常表现,通过配置 become 即可解决。
- 先确认远程登录用户与目标路径的归属关系
- 先处理 playbook 中的 become 参数配置
- 再验证文件生成后的所有者是否正确
错误日志示例
执行任务时,若权限不足,Ansible 输出中会明确显示 FAILED 及 Permission denied 信息,典型报错如下:
FAILED! => {"changed": false, "msg": "Failed to copy file from /tmp/ansible_temp_file to /etc/protected/file.conf: [Errno 13] Permission denied: b'/etc/protected/file.conf'"}
看到此类报错,首先检查目标路径权限,确认是否需要提权。
命令速用版
在 task 级别添加 become: yes,这是最小权限原则下的推荐写法。
- name: Copy file with privilege escalationcopy:src: /local/path/file.confdest: /etc/protected/file.confbecome: yesbecome_user: root
如果整个 Play 都需要提权,可以在 play 层级设置。
- hosts: webserversbecome: yestasks:- name: Copy configcopy:src: file.confdest: /etc/app/config
为什么会这样
Ansible 默认通过 SSH 使用当前登录用户连接远程主机。当 copy 模块尝试写入目标路径(例如 /etc/ 或属主为 root 的目录)时,Linux 内核会检查当前进程的有效用户 ID 是否有写权限。如果远程登录用户是普通用户,而目标路径需要 root 权限,系统就会拒绝写入并返回 Permission denied。
become 机制的作用是让 Ansible 在执行特定任务时,临时切换到更高权限的用户(通常是 root),类似于手动执行 sudo。Ansible 中,become 插件机制已经成熟,支持 sudo、su、pbis 等多种方式,默认使用 sudo。
分步处理
1. 确认远程用户权限
先登录目标机器,检查当前用户身份和目标路径权限。
whoami
ls -ld /etc/protected/
如果显示用户非 root 且路径属主为 root,则必须提权。
2. 配置 become 参数
在 playbook 对应任务中加入 become: yes。如果远程用户不在 sudoers 列表中,需要先联系运维添加权限,或修改 Ansible 配置使用其他提权用户。
3. 处理 sudo 密码提示
如果远程用户执行 sudo 需要密码,运行 ansible-playbook 时需加上 -K 参数(注意是大写 K),这会提示输入远程用户的 sudo 密码。
ansible-playbook site.yml -K
生产环境建议配置免密码 sudo,避免交互式输入导致自动化中断。
4. 注意 SELinux 影响
如果目标系统是 CentOS/RHEL 且开启了 SELinux,即使提权成功,也可能因上下文不对导致服务无法读取。必要时配合 selevel 或 selinux 模块调整。
怎么验证是否生效
1. 检查文件归属
任务执行完成后,登录远程主机查看文件所有者。
ls -l /etc/protected/file.conf
所有者应变为 root 或 become_user 指定的用户。
2. 查看 Ansible verbose 日志
运行命令时增加 -v 或 -vvv,观察任务执行阶段的连接用户和提权信息。
ansible-playbook site.yml -vvv
日志中应出现 become 相关的切换记录,且无 Permission denied 报错。
3. 使用 adhoc 命令测试
不运行 playbook,直接用 copy 模块测试单条命令。
ansible all -m copy -a "src=/tmp/test dest=/etc/test" `--become`
常见坑
1. become_user 混淆
become: yes 默认切换到 root。如果目标文件需要属于特定用户(如 nginx),需显式指定 become_user: nginx,否则文件属主可能是 root 导致服务读取失败。
2. 环境变量丢失
提权后,远程用户的环境变量(如 PATH)可能会重置。如果 copy 后的脚本需要执行,注意确认环境变量是否符合预期。
3. 临时文件权限
copy 模块在远程会先创建临时文件再移动。如果远程用户的 /tmp 目录挂载了 noexec 或权限受限,也可能报错,这与目标路径无关,需检查远程临时目录权限。
4. 不要全局滥用提权
尽量在需要写系统目录的任务上单独加 become,而不是整个 Play 都提权,以减少误操作风险。
参考来源
- Ansible 官方文档 - Becoming Unprivileged User: https://docs.ansible.com/ansible/latest/user_guide/become.html
- Ansible 官方文档 - Copy Module: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/copy_module.html
- Ansible Release Notes (关于 become 插件的通用性说明): https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html
原文链接:https://www.zjcp.cc/ask/11063.html
