Ansible Permission Denied (Errno 13): Fix File Access Errors
By Luca Berton · Published 2024-01-01 · Category: installation
Fix Ansible Permission denied [Errno 13] errors. Resolve file permission, become/sudo, SELinux, and directory access issues with troubleshooting steps.

Introduction
Welcome to another episode of Ansible Pilot! I'm Luca Berton, and today we're delving into Ansible troubleshooting, focusing on the pesky "Permission Denied Errno 13" error. Join me as we explore the intricacies of this issue, reproduce it in a live Playbook, and learn how to effectively resolve it using privilege escalation in Ansible Playbooks.
See also: Ansible 'fatal: template error while templating string' Fix (Guide)
The Demo
Let's jump right into a live Playbook to understand how to troubleshoot the Ansible fatal error [Errno 13] Permission denied and fix it in an Ansible Playbook.
Error Code
# permissiondenied_error.yml
---
- name: set environment Playbook
hosts: all
gather_facts: false
vars:
os_environment:
- key: EDITOR
value: vi
tasks:
- name: customize /etc/environment
ansible.builtin.lineinline:
dest: "/etc/environment"
state: present
regexp: "^{{ item.key }}="
line: "{{ item.key }}={{ item.value }}"
with_items: "{{ os_environment }}"
Error Execution
ansible-pilot $ ansible-playbook -i virtualmachines/demo/inventory troubleshooting/permissiondenied_error.yml
PLAY [set environment Playbook] ***********************************************************************
TASK [customize /etc/environment] *****************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: PermissionError: [Errno 13] Permission denied: b'/home/devops/.ansible/tmp/ansible-tmp-1645543127.772594-89712-144540003805636/tmpvhoh4q83' -> b'/etc/environment'
failed: [demo.example.com] (item={'key': 'EDITOR', 'value': 'vi'}) => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "ansible_loop_var": "item", "changed": false, "item": {"key": "EDITOR", "value": "vi"}, "msg": "The destination directory (/etc) is not writable by the current user. Error was: [Errno 13] Permission denied: b'/etc/.ansible_tmp_hwdwg3denvironment'"}
PLAY RECAP ****************************************************************************************
demo.example.com : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
ansible-pilot $
Fix Code
# permissiondenied_fix.yml
---
- name: set environment Playbook
hosts: all
gather_facts: false
become: true
vars:
os_environment:
- key: EDITOR
value: vi
tasks:
- name: customize /etc/environment
ansible.builtin.lineinline:
dest: "/etc/environment"
state: present
regexp: "^{{ item.key }}="
line: "{{ item.key }}={{ item.value }}"
with_items: "{{ os_environment }}"
Fix Execution
ansible-pilot $ ansible-playbook -i virtualmachines/demo/inventory troubleshooting/permissiondenied_fix.yml
PLAY [set environment Playbook] ***********************************************************************
TASK [customize /etc/environment] *****************************************************************
changed: [demo.example.com] => (item={'key': 'EDITOR', 'value': 'vi'})
PLAY RECAP ****************************************************************************************
demo.example.com : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ansible-pilot $
Conclusion
In this tutorial, we've successfully troubleshooted the Ansible [Errno 13] Permission Denied error and implemented a fix in an Ansible Playbook. By leveraging privilege escalation, we overcame the Permission Denied hurdle and ensured seamless execution.
I hope this guide proves valuable in unraveling similar challenges during your Ansible automation endeavors. If you found this information helpful, consider subscribing for more Ansible insights.
See also: Ansible 'Failure Downloading' Error: Fix get_url & uri Module Issues
Common Causes and Fixes
Missing become (sudo)
# WRONG - no privilege escalation
- ansible.builtin.copy:
src: config.yml
dest: /etc/myapp/config.yml
# CORRECT
- ansible.builtin.copy:
src: config.yml
dest: /etc/myapp/config.yml
become: true
Directory doesn't exist
- name: Create directory first
ansible.builtin.file:
path: /opt/myapp/config
state: directory
owner: appuser
mode: '0755'
become: true
- name: Then copy file
ansible.builtin.copy:
src: config.yml
dest: /opt/myapp/config/config.yml
owner: appuser
become: true
Wrong file ownership
- name: Fix ownership
ansible.builtin.file:
path: /opt/myapp
state: directory
owner: appuser
group: appgroup
recurse: true
become: true
SELinux blocking access
# Check SELinux status
- command: getenforce
register: selinux_status
# Restore SELinux context
- ansible.builtin.command: restorecon -Rv /opt/myapp
become: true
# Or set correct context
- community.general.sefcontext:
target: '/opt/myapp(/.*)?'
setype: httpd_sys_content_t
state: present
become: true
Debugging Steps
# Check current permissions
- ansible.builtin.stat:
path: /etc/myapp/
register: dir_info
- debug:
msg: |
Mode: {{ dir_info.stat.mode }}
Owner: {{ dir_info.stat.pw_name }}
Group: {{ dir_info.stat.gr_name }}
# Check who you're running as
- command: whoami
register: current_user
- command: id
register: current_id
See also: Ansible 'Missing Required Arguments' Error: Fix Missing Module Parameters
Common Permission Patterns
| Path | Typical Owner | Mode | Needs become |
|------|--------------|------|-------------|
| /etc/ | root | 644/755 | Yes |
| /opt/app/ | appuser | 755 | Usually |
| /var/log/ | syslog/root | 640 | Yes |
| /tmp/ | any | 1777 | No |
| ~/ | user | 755 | No |
Temporary Directory Issues
# Ansible uses /tmp for module execution
# If /tmp is mounted noexec, override:
# ansible.cfg
[defaults]
remote_tmp = /var/tmp/.ansible/tmp
FAQ
Errno 13 on "copy" module but file exists?
Check the parent directory permissions. You need write permission on the directory to create/modify files in it.
Works with SSH but fails with Ansible?
Ansible may run as a different user or without a login shell. Check ansible_user and become settings.
"Permission denied" during package install?
- apt:
name: nginx
become: true # Package management requires root
How do I debug permission issues?
ansible-playbook site.yml -vvvv
# Shows exact command and user context
The Error
fatal: [web1]: FAILED! => {"msg": "[Errno 13] Permission denied: '/etc/myapp/config.conf'"}
Quick Fixes
Add become (sudo)
# WRONG — running as unprivileged user
- copy:
src: config.conf
dest: /etc/myapp/config.conf
# CORRECT — use become for privileged paths
- ansible.builtin.copy:
src: config.conf
dest: /etc/myapp/config.conf
become: true
Fix File Permissions
- ansible.builtin.file:
path: /opt/myapp/data
state: directory
mode: '0755'
owner: deploy
recurse: true
become: true
Fix Parent Directory Permissions
# Often the DIRECTORY permissions matter, not the file
- file:
path: /opt/myapp
state: directory
mode: '0755'
become: true
- copy:
src: app.conf
dest: /opt/myapp/app.conf
become: true
Common Causes
1. Missing become
# Writing to system paths requires sudo
- hosts: all
become: true # Apply to all tasks in play
tasks:
- copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
2. Wrong become_user
# Run as specific user
- copy:
src: app.conf
dest: /home/deploy/app.conf
become: true
become_user: deploy
3. Ansible tmp Directory
# Remote user can't write to /tmp/.ansible/tmp
# Fix in ansible.cfg:
[defaults]
remote_tmp = /tmp/.ansible-${USER}/tmp
4. SELinux Blocking
# Check SELinux denials
ausearch -m AVC -ts recent
# Fix context
restorecon -rv /opt/myapp/
# Or set context with Ansible
- community.general.sefcontext:
target: '/opt/myapp(/.*)?'
setype: httpd_sys_content_t
become: true
5. NFS/Mounted Filesystem
# NFS with root_squash prevents root access
# In ansible.cfg, use become_user matching NFS export:
[privilege_escalation]
become_user = nfsuser
Debugging
# Check current user and permissions
- command: whoami
register: current_user
- command: ls -la /etc/myapp/
register: dir_perms
become: true
- debug:
msg: |
Running as: {{ current_user.stdout }}
Directory: {{ dir_perms.stdout }}
# Verbose mode shows permission details
ansible-playbook site.yml -vvv
Common Permission Patterns
# System config files
- template:
src: app.conf.j2
dest: /etc/myapp/app.conf
mode: '0644'
owner: root
group: root
become: true
# Application files
- copy:
src: app.jar
dest: /opt/myapp/app.jar
mode: '0755'
owner: appuser
group: appuser
become: true
# SSH keys
- copy:
content: "{{ vault_ssh_key }}"
dest: /home/deploy/.ssh/id_rsa
mode: '0600'
owner: deploy
become: true
no_log: true
# Log directories
- file:
path: /var/log/myapp
state: directory
mode: '0755'
owner: appuser
become: true
FAQ
"Permission denied" but I'm using become?
Check if become_method is correct (default is sudo). Verify the remote user has sudo privileges: sudo -l.
Permission denied on the Ansible controller?
# Local file permissions — use delegate_to or local_action
- copy:
src: /restricted/file
dest: /tmp/file
delegate_to: localhost
become: true # Needs sudo on controller
How to debug SELinux issues?
# Check for denials
sudo audit2why < /var/log/audit/audit.log
# Generate policy
sudo audit2allow -a -M mypolicy
Related Articles
• how Ansible become works under the hood • how Ansible inventory works • loop_control in AnsibleCategory: installation
Watch the video: Ansible Permission Denied (Errno 13): Fix File Access Errors — Video Tutorial