Ansible 2.11 使用 copy 模块报错 Permission denied 如何提权?

文章导读
遇到 Ansible copy 模块报 Permission denied 错误,通常是因为远程登录用户没有目标目录的写入权限,最推荐的处理方式是在任务或 Play 中启用 become 提权。
📋 目录
  1. 错误日志示例
  2. 命令速用版
  3. 为什么会这样
  4. 分步处理
  5. 怎么验证是否生效
  6. 常见坑
  7. 参考来源
A A

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 escalation
  copy:
    src: /local/path/file.conf
    dest: /etc/protected/file.conf
  become: yes
  become_user: root

如果整个 Play 都需要提权,可以在 play 层级设置。

- hosts: webservers
  become: yes
  tasks:
    - name: Copy config
      copy:
        src: file.conf
        dest: /etc/app/config

为什么会这样

Ansible 默认通过 SSH 使用当前登录用户连接远程主机。当 copy 模块尝试写入目标路径(例如 /etc/ 或属主为 root 的目录)时,Linux 内核会检查当前进程的有效用户 ID 是否有写权限。如果远程登录用户是普通用户,而目标路径需要 root 权限,系统就会拒绝写入并返回 Permission denied。

Ansible 2.11 使用 copy 模块报错 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 2.11 使用 copy 模块报错 Permission denied 如何提权?
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 报错。

Ansible 2.11 使用 copy 模块报错 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