AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible chmod: Change File Permissions with file Module (Guide)

By Luca Berton · Published 2024-01-01 · Category: windows-automation

How to change file permissions (chmod) in Ansible with the file module. Set mode, owner, group, recursive permissions on files and directories.

Ansible chmod: Change File Permissions with file Module (Guide)

How to change file or directory permission with Ansible?

I'm going to show you a live Playbook and some simple Ansible code. I'm Luca Berton and welcome to today's episode of Ansible Pilot.

See also: Ansible Set File Permissions 755: chmod with file Module Guide

Ansible change file/directory permission

Today we're talking about the Ansible module file. The full name is ansible.builtin.file, which means that is part of the collection of modules "builtin" with ansible and shipped with it. It's a module pretty stable and out for years. It works in a different variety of operating systems. It manages files and file properties. For Windows targets, use the ansible.windows.win_file module instead.

Main Parameters

• path _string_ (dest, name) - file path • owner _string_ - user • group _string_ - group • mode _raw_ - Ex: '0644' or 'u=rw,g=r,o=r' • state _string_ - file/absent/directory/hard/link/touch • setype/seuser/selevel - SELinux

This module has some parameters to perform any tasks. The only required is "path", where you specify the filesystem path of the file you're going to edit. The parameter "owner" sets the user that should own the file/directory. The parameter "group" sets the group that should own the file/directory. The parameter "mode" sets the permissions in the UNIX way of the file/directory. The state defines the type of object we are modifying, the default is "file" but we could handle also directories, hardlink, symlink, or only update the access time with the "touch" option. Let me also highlight that we could also specify the SELinux properties.

## Playbook Let's jump in a real-life playbook to change file permission with Ansible.

code

• file.yml
---
- name: file module demo
  hosts: all
  vars:
    myfile: "/home/devops/test.txt"
  become: false
  tasks:
    - name: check permission
      ansible.builtin.file:
        path: "{{ myfile }}"
        owner: "devops"
        group: "users"
        mode: '0777'

code with ❤️ in GitHub

See also: Ansible Create User Account: user Module Complete Guide

Conclusion

Now you know how to change file or directory permission with Ansible.

Permission Format Options

Ansible accepts permissions in two formats:

Octal notation (recommended)

- name: Set file to 644
  ansible.builtin.file:
    path: /etc/myapp/config.yml
    mode: '0644'  # Always quote and include leading 0
  become: true

Symbolic notation

- name: Set file permissions symbolically
  ansible.builtin.file:
    path: /etc/myapp/config.yml
    mode: 'u=rw,g=r,o=r'  # Same as 0644
  become: true

See also: Ansible Remove User Account: Delete Users with user Module

Common Permission Patterns

| Octal | Symbolic | Meaning | Use Case | |-------|----------|---------|----------| | 0644 | u=rw,g=r,o=r | Owner read/write, others read | Config files | | 0755 | u=rwx,g=rx,o=rx | Owner full, others read/execute | Scripts, directories | | 0600 | u=rw,g=,o= | Owner only | Secrets, SSH keys | | 0700 | u=rwx,g=,o= | Owner only (executable) | Private scripts | | 0444 | u=r,g=r,o=r | Read-only for everyone | Reference files | | 0775 | u=rwx,g=rwx,o=rx | Owner+group full | Shared directories |

Advanced Examples

Change ownership and permissions together

- name: Set ownership and permissions
  ansible.builtin.file:
    path: /var/www/html
    owner: www-data
    group: www-data
    mode: '0755'
    recurse: true  # Apply to all files/dirs inside
  become: true

Set different permissions for files vs directories

- name: Find all files
  ansible.builtin.find:
    paths: /var/www/html
    file_type: file
    recurse: true
  register: website_files

- name: Set file permissions to 644 ansible.builtin.file: path: "{{ item.path }}" mode: '0644' loop: "{{ website_files.files }}" become: true

- name: Find all directories ansible.builtin.find: paths: /var/www/html file_type: directory recurse: true register: website_dirs

- name: Set directory permissions to 755 ansible.builtin.file: path: "{{ item.path }}" mode: '0755' loop: "{{ website_dirs.files }}" become: true

Make a script executable

- name: Deploy and make executable
  ansible.builtin.copy:
    src: scripts/deploy.sh
    dest: /usr/local/bin/deploy.sh
    owner: root
    group: root
    mode: '0755'  # rwxr-xr-x
  become: true

Set SELinux context

- name: Set SELinux context for web content
  ansible.builtin.file:
    path: /var/www/custom
    setype: httpd_sys_content_t
    recurse: true
  become: true

Set sticky bit, setuid, setgid

# Sticky bit on shared directory (only owner can delete their files)
- name: Set sticky bit on /tmp-style directory
  ansible.builtin.file:
    path: /shared/uploads
    mode: '1777'  # Leading 1 = sticky bit
  become: true

# Setgid on group directory (new files inherit group) - name: Set setgid on project directory ansible.builtin.file: path: /projects/teamwork mode: '2775' # Leading 2 = setgid group: developers become: true

FAQ

Why must I quote the mode value?

Without quotes, YAML interprets 0644 as the integer 644 (octal 01204), which gives wrong permissions. Always use mode: '0644' with quotes.

How do I check current permissions?

- name: Get current permissions
  ansible.builtin.stat:
    path: /etc/myapp/config.yml
  register: file_info

- name: Show permissions ansible.builtin.debug: msg: "Mode: {{ file_info.stat.mode }}, Owner: {{ file_info.stat.pw_name }}"

What does recurse: true do?

Applies the same owner/group/mode to all files AND directories inside the path. Be careful — files and directories often need different permissions (644 vs 755).

How do I change permissions on Windows?

Use ansible.windows.win_acl for Windows ACL permissions:

- name: Set Windows permissions
  ansible.windows.win_acl:
    path: C:\inetpub\wwwroot
    user: IIS_IUSRS
    rights: ReadAndExecute
    type: allow

Basic Permission Change

- ansible.builtin.file:
    path: /opt/myapp/start.sh
    mode: '0755'
  become: true

Change Owner and Group

- file:
    path: /var/www/html
    owner: www-data
    group: www-data
    recurse: true
  become: true

Common Permission Patterns

# Executable script
- file:
    path: /opt/scripts/deploy.sh
    mode: '0755'
    owner: deploy

# Private key - file: path: /home/deploy/.ssh/id_rsa mode: '0600' owner: deploy group: deploy

# Config file (read-only) - file: path: /etc/myapp/config.yml mode: '0644' owner: root group: root

# Shared directory - file: path: /opt/shared state: directory mode: '0775' owner: root group: developers

# Sensitive config - file: path: /etc/myapp/secrets.yml mode: '0600' owner: root group: root

Symbolic Mode

# Add execute for owner
- file:
    path: /opt/script.sh
    mode: u+x

# Add read/write for group - file: path: /opt/shared/data mode: g+rw recurse: true

# Remove world read - file: path: /etc/myapp/secrets mode: o-rwx

Recursive Permissions

# All files and directories
- file:
    path: /var/www/mysite
    owner: www-data
    group: www-data
    recurse: true
  become: true

# Different permissions for files vs directories - shell: | find /var/www/mysite -type d -exec chmod 755 {} \; find /var/www/mysite -type f -exec chmod 644 {} \; become: true

SUID, SGID, Sticky Bit

# SGID on directory (new files inherit group)
- file:
    path: /opt/shared
    state: directory
    mode: '2775'
    group: developers
  become: true

# Sticky bit (only owner can delete) - file: path: /tmp/shared state: directory mode: '1777' become: true

ACLs (Extended Permissions)

- ansible.posix.acl:
    path: /opt/myapp
    entity: deploy
    etype: user
    permissions: rwx
    state: present
  become: true

# Default ACL for new files - ansible.posix.acl: path: /opt/myapp entity: developers etype: group permissions: rx default: true state: present become: true

Batch Permission Changes

- file:
    path: "{{ item.path }}"
    mode: "{{ item.mode }}"
    owner: "{{ item.owner | default('root') }}"
  loop:
    - { path: /opt/myapp/bin/start.sh, mode: '0755' }
    - { path: /opt/myapp/etc/config.yml, mode: '0644' }
    - { path: /opt/myapp/etc/secrets.yml, mode: '0600' }
    - { path: /opt/myapp/log, mode: '0755' }
  become: true

Verify Permissions

- stat:
    path: /etc/myapp/config.yml
  register: file_info

- debug: msg: "Mode: {{ file_info.stat.mode }}, Owner: {{ file_info.stat.pw_name }}"

- assert: that: - file_info.stat.mode == '0644' - file_info.stat.pw_name == 'root'

Permission Reference

| Mode | Meaning | |------|---------| | 0755 | rwxr-xr-x (executables, directories) | | 0644 | rw-r--r-- (config files) | | 0600 | rw------- (secrets, private keys) | | 0700 | rwx------ (private directories) | | 0775 | rwxrwxr-x (shared directories) | | 0666 | rw-rw-rw- (shared files, rarely used) | | 2775 | rwxrwsr-x (SGID directory) | | 1777 | rwxrwxrwt (sticky bit, like /tmp) |

FAQ

Octal string vs integer?

Always quote mode as a string: mode: '0755'. Without quotes, YAML may interpret it as an integer (493), which causes unexpected permissions.

How do I change permissions without changing content?

The file module only changes metadata (permissions, owner, timestamps). It never modifies file content.

recurse doesn't set different perms for files vs dirs?

Correct — recurse applies the same mode to everything. Use find + shell for different file vs directory permissions.

Related Articles

Ansible become guiderole-based playbook organization in Ansiblefile ownership and modes via ansible.builtin.fileAnsible Windows administration walkthrough

Category: windows-automation

Watch the video: Ansible chmod: Change File Permissions with file Module (Guide) — Video Tutorial

Browse all Ansible tutorials · AnsiblePilot Home