Introduction
Ansible is a powerful automation tool that simplifies infrastructure management and configuration. The Ansible script module allows you to execute custom scripts within your playbooks, extending Ansible's functionality beyond its built-in modules. However, users often encounter the 'Permission denied' error when using this module, which can impede automation workflows.
This lab will guide you through understanding and resolving permission-related issues in Ansible's script module. You will learn how to identify the causes of permission errors and implement various solutions to ensure your Ansible scripts run successfully.
Installing Ansible and Setting Up the Environment
Before we can explore permission issues with Ansible scripts, we need to set up our environment. Let's install Ansible and create a basic structure for our test environment.
Installing Ansible
First, let's update the package index and install Ansible:
sudo apt update
sudo apt install -y ansible
Once the installation is complete, verify that Ansible is installed correctly:
ansible --version
You should see output similar to this, showing the Ansible version and configuration details:
ansible [core 2.12.x]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/labex/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3/dist-packages/ansible
ansible collection location = /home/labex/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.10.x (default, Mar 01 2023, 12:34:56) [GCC 11.2.0]
jinja version = 3.0.3
libyaml = True
Setting Up the Project Structure
Now, let's create a project directory structure for our Ansible playbook and scripts:
mkdir -p ~/project/ansible-lab/{playbooks,scripts}
cd ~/project/ansible-lab
In this structure:
playbooks/will contain our Ansible playbooksscripts/will contain our shell scripts to be executed by Ansible
Creating a Simple Script
Let's create a simple shell script that we'll use with Ansible. Create a file named hello.sh in the scripts directory:
cd ~/project/ansible-lab/scripts
touch hello.sh
Open the hello.sh file in the editor and add the following content:
#!/bin/bash
echo "Hello from $(hostname)!"
echo "Current time: $(date)"
echo "Current user: $(whoami)"
This script will output the hostname, current time, and the user that executed the script.
Creating an Inventory File
Next, let's create a simple inventory file for Ansible. In Ansible, an inventory file defines the hosts and groups that Ansible will manage:
cd ~/project/ansible-lab
touch inventory.ini
Open the inventory.ini file and add the following:
[local]
localhost ansible_connection=local
This inventory file tells Ansible to run commands on the local machine.
Creating a Basic Playbook
Now, let's create a basic Ansible playbook that uses the script module:
cd ~/project/ansible-lab/playbooks
touch run_script.yml
Open the run_script.yml file and add the following content:
---
- name: Run a script
hosts: local
tasks:
- name: Execute the hello script
script: ../scripts/hello.sh
This playbook will try to execute our hello.sh script on the local machine.
With this basic setup, we're ready to explore permission issues with Ansible scripts in the next steps.
Encountering the Permission Denied Error
Now that we have set up our environment, let's try to run our Ansible playbook and understand what happens when we encounter a permission denied error.
Running the Playbook
Let's try to run our playbook:
cd ~/project/ansible-lab
ansible-playbook -i inventory.ini playbooks/run_script.yml
You will likely encounter an error message similar to this:
TASK [Execute the hello script] *******************************
fatal: [localhost]: FAILED! => {"changed": false, "msg": "failed to execute the script: /bin/sh: 1: /home/labex/.ansible/tmp/ansible-tmp-1234567890.12-123456789012345/AnsiballZ_script.py: Permission denied"}
This is a common permission denied error when using the Ansible script module. The error occurs because our script doesn't have the execute permission, which is required for it to run.
Understanding File Permissions in Linux
In Linux, every file has permissions that determine who can read, write, or execute it. There are three types of permissions:
- Read (r): Allows reading the file's contents
- Write (w): Allows modifying the file
- Execute (x): Allows executing the file as a program
These permissions are assigned to three different user categories:
- User (owner): The file's owner
- Group: Users who are members of the file's group
- Others: All other users
You can view a file's permissions using the ls -l command:
ls -l ~/project/ansible-lab/scripts/hello.sh
You might see output like this:
-rw-rw-r-- 1 labex labex 95 Jun 10 12:34 /home/labex/project/ansible-lab/scripts/hello.sh
In this output, the first set of characters (-rw-rw-r--) represents the file's permissions:
- The first character (
-) indicates this is a regular file - The next three characters (
rw-) are the owner's permissions (read, write, no execute) - The next three (
rw-) are the group's permissions - The final three (
r--) are permissions for others
Notice that the execute permission (x) is missing for all user categories, which is why we're getting the permission denied error.
Checking the Current Permissions
Let's examine the current permissions of our script:
ls -l ~/project/ansible-lab/scripts/hello.sh
You'll see that the script is missing the execute permission, which is needed for Ansible to run it.
In the next step, we'll learn how to fix this permission issue and successfully run our Ansible playbook.
Fixing Permission Issues with chmod
The most common way to fix the "Permission denied" error is to add execute permissions to the script file. We can do this using the chmod command.
Understanding the chmod Command
The chmod command is used to change the permissions of files or directories in Linux. The command has several ways to specify permissions:
- Symbolic mode: Uses letters (r, w, x) to represent permissions
- Numeric mode: Uses numbers (4, 2, 1) to represent permissions
For our purpose, we'll use the symbolic mode to add execute permissions.
Adding Execute Permissions to the Script
Let's add execute permissions to our script:
chmod +x ~/project/ansible-lab/scripts/hello.sh
The +x option adds execute permission for all user categories (user, group, and others).
Let's verify that the permissions have been updated:
ls -l ~/project/ansible-lab/scripts/hello.sh
You should now see output similar to this:
-rwxrwxr-x 1 labex labex 95 Jun 10 12:34 /home/labex/project/ansible-lab/scripts/hello.sh
Notice the x in the permissions string, indicating that the execute permission has been added.
Running the Playbook Again
Now that we've added execute permissions to our script, let's run the Ansible playbook again:
cd ~/project/ansible-lab
ansible-playbook -i inventory.ini playbooks/run_script.yml
This time, the playbook should execute successfully:
PLAY [Run a script] ******************************************
TASK [Gathering Facts] ***************************************
ok: [localhost]
TASK [Execute the hello script] *****************************
changed: [localhost]
PLAY RECAP *************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Viewing the Script Output
Let's check the output of our script. Ansible captures the script's output and includes it in the task results. To see the detailed output, let's modify our playbook to register and display the output:
cd ~/project/ansible-lab/playbooks
Edit the run_script.yml file to include the register and debug tasks:
---
- name: Run a script
hosts: local
tasks:
- name: Execute the hello script
script: ../scripts/hello.sh
register: script_output
- name: Display script output
debug:
var: script_output.stdout_lines
Now let's run the playbook again:
cd ~/project/ansible-lab
ansible-playbook -i inventory.ini playbooks/run_script.yml
You should see output like this:
PLAY [Run a script] ******************************************
TASK [Gathering Facts] ***************************************
ok: [localhost]
TASK [Execute the hello script] *****************************
changed: [localhost]
TASK [Display script output] ********************************
ok: [localhost] => {
"script_output.stdout_lines": [
"Hello from localhost!",
"Current time: Wed Jun 10 12:34:56 UTC 2023",
"Current user: labex"
]
}
PLAY RECAP *************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Now you can see the full output of our script. The script ran as the labex user, which is our current user.
By adding execute permissions with chmod +x, we've successfully fixed the "Permission denied" error and can now run our script through Ansible.
Using Become for Privilege Escalation
Sometimes, you need to run scripts with elevated privileges, such as running commands that require root access. In these cases, simply adding execute permissions to the script might not be enough. Ansible provides the become directive to run tasks with privilege escalation.
Understanding the Become Directive
The become directive in Ansible allows you to execute tasks as a different user, typically with elevated privileges. This is similar to using sudo in the command line.
Key options for the become directive include:
become: yes: Enables privilege escalationbecome_user: <username>: Specifies which user to become (default is root)become_method: <method>: Specifies how to become the user (default is sudo)
Creating a Script That Requires Root Privileges
Let's create a script that requires root privileges to execute successfully:
cd ~/project/ansible-lab/scripts
touch system_info.sh
Add the following content to the system_info.sh file:
#!/bin/bash
echo "System information - requires root privileges"
echo "Hostname: $(hostname)"
echo "Kernel version: $(uname -r)"
echo "Available disk space:"
df -h /
echo "User executing the script: $(whoami)"
Make the script executable:
chmod +x ~/project/ansible-lab/scripts/system_info.sh
Creating a Playbook with Become
Now, let's create a playbook that uses the become directive:
cd ~/project/ansible-lab/playbooks
touch root_script.yml
Add the following content to the root_script.yml file:
---
- name: Run a script as root
hosts: local
tasks:
- name: Execute the system info script
script: ../scripts/system_info.sh
become: yes
register: script_output
- name: Display script output
debug:
var: script_output.stdout_lines
The become: yes directive tells Ansible to run the script with elevated privileges.
Running the Playbook with Become
Let's run our new playbook:
cd ~/project/ansible-lab
ansible-playbook -i inventory.ini playbooks/root_script.yml
The playbook should execute successfully, and you should see output similar to this:
PLAY [Run a script as root] *********************************
TASK [Gathering Facts] **************************************
ok: [localhost]
TASK [Execute the system info script] **********************
changed: [localhost]
TASK [Display script output] *******************************
ok: [localhost] => {
"script_output.stdout_lines": [
"System information - requires root privileges",
"Hostname: localhost",
"Kernel version: 5.15.0-1015-aws",
"Available disk space:",
"Filesystem Size Used Avail Use% Mounted on",
"/dev/root 59G 17G 42G 29% /",
"User executing the script: root"
]
}
PLAY RECAP ************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Notice that in the script output, the "User executing the script" is now root, not labex. This shows that our script ran with elevated privileges due to the become: yes directive.
Understanding When to Use Become
You should use the become directive in the following situations:
- When the script needs to access system files or directories that require root privileges
- When the script needs to install packages or modify system configurations
- When the script needs to run commands that would normally require
sudoin the command line
By using the become directive appropriately, you can ensure that your scripts have the necessary permissions to execute successfully, avoiding permission denied errors.
Best Practices for Avoiding Permission Issues
Now that we understand how to fix permission issues using chmod and become, let's explore some best practices to prevent permission issues from occurring in the first place.
1. Always Make Scripts Executable Before Using Them
Before using a script in Ansible, always ensure it has the execute permission:
chmod +x path/to/script.sh
It is good practice to do this as part of your script creation process.
2. Use Version Control with Proper File Modes
If you're using Git or another version control system, make sure it preserves file modes (permissions). In Git, you can configure this with:
git config core.fileMode true
For existing repositories, you might need to update the file modes:
git update-index --chmod=+x path/to/script.sh
3. Create a Script to Check and Fix Permissions
Let's create a utility script that checks and fixes permissions for all scripts in our project:
cd ~/project/ansible-lab
touch fix_permissions.sh
Add the following content to the fix_permissions.sh file:
#!/bin/bash
echo "Fixing permissions for scripts in ansible-lab"
## Find all .sh files and make them executable
find ~/project/ansible-lab -name "*.sh" -type f -exec chmod +x {} \;
echo "Done. All script files now have execute permissions."
Make the script executable:
chmod +x ~/project/ansible-lab/fix_permissions.sh
Run the script to ensure all scripts in your project have execute permissions:
./fix_permissions.sh
4. Use Ansible's File Module to Set Permissions
You can also use Ansible's file module to ensure script files have the correct permissions. Let's create a playbook that does this:
cd ~/project/ansible-lab/playbooks
touch set_permissions.yml
Add the following content to the set_permissions.yml file:
---
- name: Set correct permissions for scripts
hosts: local
tasks:
- name: Find all script files
find:
paths: /home/labex/project/ansible-lab
patterns: "*.sh"
recurse: yes
register: script_files
- name: Make script files executable
file:
path: "{{ item.path }}"
mode: "0755"
loop: "{{ script_files.files }}"
Run this playbook to ensure all scripts have the correct permissions:
cd ~/project/ansible-lab
ansible-playbook -i inventory.ini playbooks/set_permissions.yml
5. Create a Pre-flight Check Playbook
Finally, let's create a pre-flight check playbook that runs before your main playbooks to verify everything is set up correctly:
cd ~/project/ansible-lab/playbooks
touch preflight_check.yml
Add the following content to the preflight_check.yml file:
---
- name: Pre-flight checks
hosts: local
tasks:
- name: Check if scripts are executable
find:
paths: /home/labex/project/ansible-lab
patterns: "*.sh"
recurse: yes
register: script_files
- name: Verify script permissions
stat:
path: "{{ item.path }}"
register: stat_results
loop: "{{ script_files.files }}"
failed_when: not stat_results.stat.executable
ignore_errors: yes
This playbook checks if all .sh files are executable and reports any that are not.
Let's run the pre-flight check:
cd ~/project/ansible-lab
ansible-playbook -i inventory.ini playbooks/preflight_check.yml
If all your scripts have the correct permissions, the playbook should complete without errors. If any scripts are missing execute permissions, you'll see a notification.
By following these best practices, you can avoid permission denied errors in your Ansible scripts and ensure that your automation runs smoothly.
Summary
In this lab, you have learned how to identify and resolve 'Permission denied' errors when using the Ansible script module.
Key takeaways from this lab include:
- Understanding the importance of file permissions in Linux and how they affect script execution in Ansible
- Using the
chmodcommand to add execute permissions to script files - Utilizing Ansible's
becomedirective for privilege escalation when running scripts that require root access - Implementing best practices to prevent permission issues, including:
- Making scripts executable before using them
- Maintaining proper file modes in version control
- Creating utility scripts to check and fix permissions
- Using Ansible's file module to set permissions
- Implementing pre-flight checks to verify your environment
By applying these techniques, you can ensure that your Ansible scripts run smoothly without permission errors, enhancing the reliability of your automation workflows.
The skills you've learned in this lab are fundamental to working effectively with Ansible and can be applied to a wide range of automation scenarios.


