Task 1 Information
To manage all servers within the stack using Ansible, the Nautilus DevOps team is planning to use a common sudo user among all servers. Ansible will be able to use this to perform different tasks on each server. This is not finalized yet, but the team has decided to first perform testing. The DevOps team has already installed Ansible on jump host using yum, and they now have the following requirement:
On the jump host, please make the necessary changes so that Ansible can utilize kareem as the default SSH user for all hosts. Ensure these adjustments are made within Ansible's default configuration without creating a new config file.
Task 2 Information
Ansible utilizes SSH connections to communicate with remote hosts. The Nautilus DevOps team intends to employ a unified Ansible manager for overseeing several remote hosts. To streamline operations, they seek to implement a common Ansible configuration to govern these hosts.
Create an Ansible configuration file under /home/thor/ansible-config directory and disable the SSH host key checking for all Ansible managed hosts.
Task 3 Information
a.. On jump host create a playbook /home/thor/ansible/playbook-t2q3.yml to copy /usr/src/itadmin-t2q3/linux-t2q3.txt file on same host at location /opt/itadmin-t2q3.
Note: Validation will try to run the playbook using command ansible-playbook -i localhost playbook-t2q3.yml so please make sure the playbook works this way without passing any extra arguments.
Task 4 Information
a. On jump host create a playbook /home/thor/ansible/playbook-t2q5.yml to copy /usr/src/itadmin-t2q5/story-t2q5.txt file from App Server 2 at location /opt/itadmin-t2q5 on App Server 2.
b. An inventory is already placed under /home/thor/ansible/inventory-t2q5.
Note: Validation will try to run the playbook using command ansible-playbook -i inventory-t2q5 playbook-t2q5.yml so please make sure the playbook works this way without passing any extra arguments.
Task 5 Information
The Nautilus DevOps team is working to create some data on different app servers in using Ansible. They want to create some files/directories and have some specific requirements related to this task. Find below more details about the same:
a. Utilise the inventory file /home/thor/playbook/inventory-t4q3, present on the jump host.
b. Create a playbook named /home/thor/playbook/playbook-t4q3.yml to create a directory named /opt/backup-t4q3 on all App Servers.
Note: Validation will attempt to execute the playbook using the command ansible-playbook -i inventory-t4q3 playbook-t4q3.yml. Please ensure the playbook functions correctly with this command alone, without requiring any additional arguments.
Task 6 Information
The Nautilus DevOps team is working to create some data on different app servers in using Ansible. They want to create some files/directories and have some specific requirements related to this task. Find below more details about the same:
Create a playbook called playbook-t4q6.yml under /home/thor/playbook/ directory and configure it to create a file called /opt/file-t4q6.txt on all App Servers. The contents of the file must be This file is created by Ansible!. Inventory is already placed under /home/thor/playbook/inventory-t4q6.
Note: Validation will try to run the playbook using command ansible-playbook -i inventory-t4q6 playbook-t4q6.yml, so please make sure the playbook works this way without passing any extra arguments.
Task 7 Information
As per the details given in the table below, you can see that, the web servers are linux based hosts and the db server is a Windows machine. Update the inventory /home/thor/playbooks/inventory-t3q6 to add a similar entry for server4.company.com host.
Find the required details from the table below.
| Alias | HOST | Connection | User | Password |
| web1 | server1.company.com | ssh | root | Password123! |
| web2 | server2.company.com | ssh | root | Password123! |
| web3 | server3.company.com | ssh | root | Password123! |
| db1 | server4.company.com | winrm | administrator | Dbp@ss123! |
Note: For Linux based hosts, use ansible_ssh_pass parameter and for Windows based hosts, use ansible_password parameter.
Task 8 Information
The Nautilus DevOps team intends to test multiple Ansible playbooks across various app servers in the Stratos DC. Before proceeding, certain prerequisites must be addressed. Specifically, the team requires the establishment of a password-less SSH connection between the Ansible controller and the managed nodes. An assigned ticket outlines the task; please carry out the following details:
a. The Jump host serves as our Ansible controller, and the Ansible playbooks will be executed through the thor user from the jump host.
b. An inventory file, /home/thor/playbook/inventory-t3q2, is available on the jump host. Utilize this inventory file to perform an Ansible ping from the jump host to App Server 3 and ensure the successful execution of the ping command.
Task 9 Information
The Nautilus DevOps team recently recommended employing Ansible for configuration management and automation purposes. As they've commenced creating playbooks, a need has arisen for a basic playbook, outlined as follows.
Create a playbook named /home/thor/ansible/playbook-t1q2.yml on the jump host and configure the playbook to run on localhost and execute an echo command echoing Welcome!.
Task 10 Information
A team member completed writing a playbook, but when we attempted to execute it, an error occurred. We need someone to review the playbook, identify the issue, and fix it.
The playbook name is /home/thor/ansible/playbook-t1q5.yml, make sure it executes without any error.
Task 1 Solutions
β
Part 1: Lab Step-by-Step Guidelines
π© Step 1 β Confirm Ansible is installed
On jump host:
ansible --version
You should see output showing:
ansible version
config file location
Example line to observe:
config file = /etc/ansible/ansible.cfg
β οΈ This is important β we must modify the default config file, not create a new one.
π© Step 2 β Edit the default Ansible configuration file
Open:
sudo vi /etc/ansible/ansible.cfg
π© Step 3 β Locate the [defaults] section
Find this section:
[defaults]
Under it, add or modify the following line:
remote_user = kareem
Save and exit.
π© Step 4 β Verify the change
Run:
ansible-config dump | grep DEFAULT_REMOTE_USER
Expected output:
DEFAULT_REMOTE_USER(/etc/ansible/ansible.cfg) = kareem
β This confirms Ansible will now use kareem as default SSH user
β No need to specify ansible_user in inventory anymore
π§ Part 2: Simple Step-by-Step Explanation (Beginner Friendly)
Letβs explain what we built in a very simple way.
This lab changes how Ansible connects to servers.
Instead of writing the SSH user in every inventory file,
we tell Ansible:
βAlways use kareem unless I say otherwise.β
π What Are We Building?
Think of it like this:
1οΈβ£ Ansible needs a username to connect
2οΈβ£ We set one global default username
3οΈβ£ Now Ansible automatically uses that user everywhere
Flow:
Ansible Command
βββ
ansible.cfg
βββ
remote_user = kareem
βββ
SSH connection uses kareem
π’ Step 1 β Understand How Ansible Connects
When you run:
ansible all -m ping
Ansible internally does something like:
ssh @server
If no user is defined:
It uses the current Linux user (thor)
Or a user defined in inventory
We changed that behavior.
π’ Step 2 β Set a Global Default User
Inside:
/etc/ansible/ansible.cfg
We added:
[defaults]
remote_user = kareem
Now Ansible automatically assumes:
ssh kareem@server
Even if inventory does not mention a username.
π’ Step 3 β Why This Is Useful
Before:
Every inventory file needed:
ansible_user=kareem
After:
Inventory can simply be:
stapp01
stapp02
stapp03
Cleaner. Simpler. Centralized.
π’ Step 4 β How Ansible Chooses a User (Priority Order)
Ansible decides the SSH user like this:
1οΈβ£ ansible_user in inventory
2οΈβ£ remote_user in ansible.cfg
3οΈβ£ Current Linux user
We configured level #2.
So now the default becomes kareem.
π’ Step 5 β Why We Edited /etc/ansible/ansible.cfg
The lab says:
βEnsure these adjustments are made within Ansible's default configuration without creating a new config file.β
Ansible config priority:
ansible.cfg in current directory
~/.ansible.cfg
/etc/ansible/ansible.cfg β default system config
We modified the system default.
No new file created.
π’ Step 6 β What This Looks Like During Execution
When you run:
ansible stapp01 -m ping
Internally Ansible now does:
ssh kareem@stapp01
Because:
remote_user = kareem
is globally defined.
π’ Final Result
After the change:
β Ansible automatically uses kareem
β No need to specify username in inventory
β Configuration is centralized
β Lab requirement satisfied
π― What I Learned
I learned how to:
β Change Ansible default SSH behavior
β Modify system-wide ansible.cfg
β Understand user precedence order
β Control connection behavior globally
Task 2 Solutions
β
Part 1: Lab Step-by-Step Guidelines
π© Step 1 β Create the directory
mkdir -p /home/thor/ansible-config
π© Step 2 β Create the Ansible configuration file
Create a file named ansible.cfg inside that directory:
vi /home/thor/ansible-config/ansible.cfg
π© Step 3 β Add the required configuration
Insert the following content:
[defaults]
host_key_checking = False
Save and exit.
π© Step 4 β Verify Ansible is using this config file
Move into the directory:
cd /home/thor/ansible-config
# Now check:
ansible --version
Output:
thor@jumphost ~/ansible-config$ ansible --version
ansible [core 2.14.17]
config file = /home/thor/ansible-config/ansible.cfg
configured module search path = ['/home/thor/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.9/site-packages/ansible
ansible collection location = /home/thor/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.9.18 (main, Jan 24 2024, 00:00:00) [GCC 11.4.1 20231218 (Red Hat 11.4.1-3)] (/usr/bin/python3)
jinja version = 3.1.2
libyaml = True
β This confirms Ansible is using your custom configuration
β SSH host key checking is now disabled
π§ Part 2: Simple Step-by-Step Explanation (Beginner Friendly)
Letβs explain what we built in a very simple way.
This lab changes how Ansible handles SSH security checks.
π What Are We Building?
Think of it like this:
Normally when Ansible connects to a new server:
Ansible
βββ
SSH
βββ
βAre you sure you trust this host?β
That message blocks automation.
We disabled that check.
π’ Step 1 β What Is Host Key Checking?
When you SSH to a new server manually, you see:
Are you sure you want to continue connecting (yes/no)?
This is called host key verification.
It prevents:
Man-in-the-middle attacks
Connecting to fake servers
Ansible performs the same check by default.
π’ Step 2 β Why Disable It?
In automation labs:
Servers are created dynamically
Host keys change frequently
Manual confirmation is impossible
So we disable it globally.
π’ Step 3 β What This Line Does
Inside:
[defaults]
host_key_checking = False
This tells Ansible:
βDo NOT ask to verify SSH host keys.β
Now connection flow becomes:
Ansible
βββ
SSH
βββ
Connect immediately
No prompt. No interruption.
π’ Step 4 β Why We Created ansible.cfg in That Directory
Ansible configuration priority order:
1οΈβ£ ansible.cfg in current directory
2οΈβ£ ~/.ansible.cfg
3οΈβ£ /etc/ansible/ansible.cfg
When we run Ansible from:
/home/thor/ansible-config
It automatically uses:
/home/thor/ansible-config/ansible.cfg
So we created a project-level configuration.
π’ Step 5 β What Changes Internally?
Before:
ansible all -m ping
Might fail with:
Host key verification failed.
After:
ansible all -m ping
Connects immediately.
π’ Final Result
β Created custom ansible.cfg
β Disabled SSH host key checking
β Confirmed Ansible uses that config
β Automation runs without SSH prompts
β Lab requirement satisfied
π― What I Learned
I learned how to:
β Create project-level Ansible configuration
β Disable SSH host key checking
β Understand Ansible config precedence
β Control SSH behavior globally
Task 3 Solutions
β
Part 1: Lab Step-by-Step Guidelines
π© Step 1 β Create the playbook directory (if not exists)
mkdir -p /home/thor/ansible
π© Step 2 β Create the playbook file
vi /home/thor/ansible/playbook-t2q3.yml
π© Step 3 β Add the correct playbook content
Insert exactly this:
---
- name: Copy file on localhost
hosts: localhost
connection: local
gather_facts: no
tasks:
- name: Copy linux-t2q3.txt to /opt/itadmin-t2q3
copy:
src: /usr/src/itadmin-t2q3/linux-t2q3.txt
dest: /opt/itadmin-t2q3/linux-t2q3.txt
Save and exit.
π© Step 4 β Ensure destination directory exists (IMPORTANT)
sudo mkdir -p /opt/itadmin-t2q3
# Ensure proper permissions:
sudo chown thor:thor /opt/itadmin-t2q3
π© Step 5 β Test the playbook exactly like validation will
cd /home/thor/ansible
ansible-playbook -i localhost playbook-t2q3.yml
Expected result:
thor@jumphost ~/ansible$ ansible-playbook -i inventory-t2q5 playbook-t2q5.yml
PLAY [Copy story file on App Server 2] **********************************************************************
TASK [Ensure destination directory exists] ******************************************************************
ok: [stapp02]
TASK [Copy story file inside App Server 2] ******************************************************************
changed: [stapp02]
PLAY RECAP **************************************************************************************************
stapp02 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
π§ Part 2: Simple Step-by-Step Explanation (Beginner Friendly)
Letβs explain what we built in a very simple way.
This lab copies a file from the jump host to itself using Ansible.
π What Are We Building?
Think of it like this:
Source File
/usr/src/itadmin-t2q3/linux-t2q3.txt
βββ
Ansible Playbook
βββ
Destination Folder
/opt/itadmin-t2q3/
Even though itβs the same machine, we still use Ansible.
π’ Step 1 β Why Use hosts: localhost?
Validation runs:
ansible-playbook -i localhost playbook-t2q3.yml
So our play must target:
hosts: localhost
Otherwise it wonβt match.
π’ Step 2 β Why connection: local?
By default, Ansible tries SSH.
But this is the same machine.
So we tell Ansible:
connection: local
Meaning:
βDo NOT use SSH. Execute locally.β
π’ Step 3 β What the copy Module Does
copy:
src: /usr/src/itadmin-t2q3/linux-t2q3.txt
dest: /opt/itadmin-t2q3/linux-t2q3.txt
This tells Ansible:
1οΈβ£ Read file from src
2οΈβ£ Copy it to dest
3οΈβ£ Create file if it does not exist
π’ Step 4 β Why We Donβt Need Inventory File
Because validation runs:
-i localhost
This creates a temporary inventory with:
localhost
And our play targets exactly that.
Perfect match.
π’ Final Result
After execution:
β File exists in /opt/itadmin-t2q3/
β Playbook runs without extra arguments
β Works with -i localhost
β No SSH required
β Lab requirement satisfied
π― What I Learned
I learned how to:
β Run Ansible locally
β Use connection: local
β Write validation-safe playbooks
β Copy files using Ansible
Task 4 Information
β
Part 1: Lab Step-by-Step Guidelines
π© Step 1 β Move to ansible directory
cd /home/thor/ansible
π© Step 2 β Confirm App Server 2 hostname in inventory
cat inventory-t2q5
You will likely see something like:
stapp02 ansible_host=172.16.238.11 ansible_ssh_pass=Am3ric@ ansible_user=steve
We must target:
stapp02
(That is App Server 2.)
π© Step 3 β Create the playbook
vi playbook-t2q5.yml
Add the following content:
---
- name: Copy story file on App Server 2
hosts: stapp02
become: yes
gather_facts: no
tasks:
- name: Ensure destination directory exists
file:
path: /opt/itadmin-t2q5
state: directory
mode: '0755'
- name: Copy story file inside App Server 2
copy:
src: /usr/src/itadmin-t2q5/story-t2q5.txt
dest: /opt/itadmin-t2q5/story-t2q5.txt
remote_src: yes
Save and exit.
π© Step 4 β Test exactly like validation
ansible-playbook -i inventory-t2q5 playbook-t2q5.yml
Expected result:
thor@jumphost ~/ansible$ ansible-playbook -i inventory-t2q5 playbook-t2q5.yml
PLAY [Copy story file on App Server 2] **********************************************************************
TASK [Ensure destination directory exists] ******************************************************************
ok: [stapp02]
TASK [Copy story file inside App Server 2] ******************************************************************
changed: [stapp02]
PLAY RECAP **************************************************************************************************
stapp02 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
π§ Part 2: Simple Step-by-Step Explanation (Beginner Friendly)
Letβs explain what we built in a simple way.
π What Are We Building?
We are copying a file inside App Server 2.
Source (on App Server 2):
/usr/src/itadmin-t2q5/story-t2q5.txt
Destination (on App Server 2):
/opt/itadmin-t2q5/story-t2q5.txt
Flow:
Jump Host
βββ (Ansible connects)
App Server 2
βββ
Copy file internally
π’ Step 1 β Why hosts: stapp02?
The requirement says:
Copy from App Server 2
So we must target only that host.
If we use all, the lab may fail.
Precision matters.
π’ Step 2 β Why remote_src: yes Is Critical
By default, Ansible thinks:
src β file is on jump host
But our file is already on App Server 2.
So we add:
remote_src: yes
This tells Ansible:
βThe source file is already on the remote machine.β
Without this line, the playbook will fail.
This is the most important detail in this lab.
π’ Step 3 β Why We Use become: yes
The destination path is:
/opt/itadmin-t2q5
Normal users cannot write to /opt.
So we use:
become: yes
This runs tasks using sudo.
π’ Step 4 β Why We Create the Directory in the Playbook
Instead of manually creating the directory, we use:
file:
state: directory
Why?
Because:
Playbook becomes self-contained
Validation does not depend on manual steps
It works even if directory does not exist
π’ Final Result
After execution:
β File copied successfully
β Located at /opt/itadmin-t2q5/story-t2q5.txt
β Only App Server 2 affected
β Works with given inventory
β No extra CLI arguments
β Lab requirement satisfied
π― What I Learned
I learned how to:
β Copy files inside a remote server
β Use remote_src: yes correctly
β Use become for privileged paths
β Write validation-safe playbooks
Task 5 Solutions
β
Part 1: Lab Step-by-Step Guidelines
π© Step 1 β Move to the required directory
cd /home/thor/playbook
π© Step 2 β Verify inventory file exists
ls -l inventory-t4q3
cat inventory-t4q3
This inventory already contains the App Servers.
We will not modify it.
π© Step 3 β Create the playbook
vi playbook-t4q3.yml
# Add the following content:
---
- name: Create backup directory on all App Servers
hosts: all
become: yes
gather_facts: no
tasks:
- name: Create /opt/backup-t4q3 directory
file:
path: /opt/backup-t4q3
state: directory
mode: '0755'
Save and exit.
π© Step 4 β Test exactly like validation
ansible-playbook -i inventory-t4q3 playbook-t4q3.yml
Expected result:
thor@jumphost ~/playbook$ ansible-playbook -i inventory-t4q3 playbook-t4q3.yml
PLAY [Create backup directory on all App Servers] ***********************************************************
TASK [Create /opt/backup-t4q3 directory] ********************************************************************
changed: [stapp02]
changed: [stapp03]
changed: [stapp01]
PLAY RECAP **************************************************************************************************
stapp01 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
stapp02 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
stapp03 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
π§ Part 2: Simple Step-by-Step Explanation (Beginner Friendly)
Letβs explain what we built in a very simple way.
π What Are We Building?
We are creating this directory:
/opt/backup-t4q3
On:
App Server 1
App Server 2
App Server 3
Flow:
Jump Host
βββ
Ansible connects to all App Servers
βββ
Creates directory /opt/backup-t4q3
π’ Step 1 β Why hosts: all?
The inventory contains only the App Servers.
So:
hosts: all
Means:
Run this task on every server listed.
π’ Step 2 β Why Use the file Module?
We use:
file:
path: /opt/backup-t4q3
state: directory
Because:
state: directory ensures the folder exists
If it already exists β nothing changes
If it doesnβt β Ansible creates it
This is called idempotency.
π’ Step 3 β Why become: yes Is Required
/opt is a system directory.
Normal users cannot create folders there.
So we use:
become: yes
Which means:
Run the task with sudo privileges.
Without this, the playbook would fail.
π’ Step 4 β Why No Extra Arguments?
Validation runs:
ansible-playbook -i inventory-t4q3 playbook-t4q3.yml
So:
We must not depend on --ask-become-pass
We must not depend on extra flags
Everything must be inside the playbook
π’ Final Result
After execution:
β Directory created on all App Servers
β Located at /opt/backup-t4q3
β Proper permissions applied
β Works with provided inventory
β No extra arguments required
β Lab requirement satisfied
π― What I Learned
I learned how to:
β Run playbooks on multiple hosts
β Create directories using file module
β Use become for system paths
β Write validation-safe playbooks
Task 6 Solutions
β Part 1: Lab Step-by-Step Guidelines (Validation Safe)
π© Step 1 β Move to required directory
cd /home/thor/playbook
π© Step 2 β Verify inventory exists
ls -l inventory-t4q6
cat inventory-t4q6
Do not modify it.
π© Step 3 β Create the playbook
vi playbook-t4q6.yml
Insert the following:
---
- name: Create file on all App Servers
hosts: all
become: yes
gather_facts: no
tasks:
- name: Create /opt/file-t4q6.txt with required content
copy:
dest: /opt/file-t4q6.txt
content: "This file is created by Ansible!"
mode: '0644'
Save and exit.
π© Step 4 β Test exactly like validation
ansible-playbook -i inventory-t4q6 playbook-t4q6.yml
Expected result:
thor@jumphost ~/playbook$ ansible-playbook -i inventory-t4q6 playbook-t4q6.yml
PLAY [Create file on all App Servers] ***********************************************************************
TASK [Create /opt/file-t4q6.txt with required content] ******************************************************
changed: [stapp03]
changed: [stapp01]
changed: [stapp02]
PLAY RECAP **************************************************************************************************
stapp01 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
stapp02 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
stapp03 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
π§ Part 2: Simple Step-by-Step Explanation (Beginner Friendly)
Letβs explain what we built in a very simple way.
π What Are We Building?
We are creating this file:
/opt/file-t4q6.txt
On:
App Server 1
App Server 2
App Server 3
With this exact content inside:
This file is created by Ansible!
Flow:
Jump Host
βββ
Ansible connects to all App Servers
βββ
Creates file in /opt
βββ
Writes required content
π’ Step 1 β Why hosts: all?
The inventory already contains only App Servers.
So:
hosts: all
Means:
Run on every server listed in inventory.
π’ Step 2 β Why Use the copy Module Instead of file?
We need to:
Create a file
Add specific content
The file module only creates empty files.
The copy module allows:
content: "This file is created by Ansible!"
So it:
1οΈβ£ Creates file if missing
2οΈβ£ Overwrites if content is wrong
3οΈβ£ Keeps it consistent
This is called idempotent behavior.
π’ Step 3 β Why become: yes?
Because:
/opt
Is a system directory.
Normal users cannot write there.
So:
become: yes
Means:
Use sudo to execute tasks.
π’ Step 4 β Why No Extra Arguments?
Validation runs:
ansible-playbook -i inventory-t4q6 playbook-t4q6.yml
So:
No --ask-become-pass
No extra flags
Everything must be defined inside playbook
π’ Final Result
After execution:
β File exists on all App Servers
β Located at /opt/file-t4q6.txt
β Contains exact required sentence
β Proper permissions set
β Works with provided inventory
β No extra arguments required
β Lab requirement satisfied
π― What I Learned
I learned how to:
β Create files with specific content
β Use copy module with content
β Run playbooks on multiple hosts
β Use become for system paths
β Write validation-safe playbooks
Task 7 Solutions
β
Part 1: Lab Step-by-Step Guidelines
π© Step 1 β Open the inventory file
vi /home/thor/playbook/inventory-t3q6
π© Step 2 β Review existing entries
You will likely see entries similar to:
web1 ansible_host=server1.company.com ansible_user=root ansible_ssh_pass=Password123!
web2 ansible_host=server2.company.com ansible_user=root ansible_ssh_pass=Password123!
web3 ansible_host=server3.company.com ansible_user=root ansible_ssh_pass=Password123!
Do NOT modify them.
π© Step 3 β Add entry for Windows DB server
Add the following line at the end:
db1 ansible_host=server4.company.com ansible_connection=winrm ansible_user=administrator ansible_password=Dbp@ss123!
Save and exit.
π© Step 4 β Verify the file
cat /home/thor/playbook/inventory-t3q6
Output
# Sample Inventory File
# Web Servers
web1 ansible_host=server1.company.com ansible_connection=ssh ansible_user=root ansible_ssh_pass=Password123!
web2 ansible_host=server2.company.com ansible_connection=ssh ansible_user=root ansible_ssh_pass=Password123!
web3 ansible_host=server3.company.com ansible_connection=ssh ansible_user=root ansible_ssh_pass=Password123!
db1 ansible_host=server4.company.com ansible_connection=winrm ansible_user=administrator ansible_password=Dbp@ss123!
β Linux hosts use ansible_ssh_pass
β Windows host uses ansible_password
β Windows host explicitly sets ansible_connection=winrm
π§ Part 2: Simple Step-by-Step Explanation (Beginner Friendly)
Letβs explain what we built in a simple way.
π What Are We Building?
We already had 3 Linux web servers:
web1 β SSH β root
web2 β SSH β root
web3 β SSH β root
Now we add:
db1 β WinRM β administrator
So the environment becomes:
Linux Servers (SSH)
+
Windows Server (WinRM)
π’ Step 1 β Why Linux Uses ansible_ssh_pass?
Linux servers connect using:
ssh
So we define:
ansible_user=root
ansible_ssh_pass=Password123!
Ansible understands:
Use SSH and this password.
π’ Step 2 β Why Windows Uses ansible_password?
Windows does NOT use SSH by default.
It uses:
WinRM
So we must specify:
ansible_connection=winrm
ansible_user=administrator
ansible_password=Dbp@ss123!
Notice:
Linux β ansible_ssh_pass
Windows β ansible_password
This difference is very important in exams.
π’ Step 3 β Why We Added ansible_connection=winrm
Without it, Ansible would try:
ssh administrator@server4.company.com
Which would fail.
By adding:
ansible_connection=winrm
We tell Ansible:
βThis is a Windows host. Use WinRM protocol.β
π’ Final Inventory Structure
Linux Hosts:
SSH β root β ansible_ssh_pass
Windows Host:
WinRM β administrator β ansible_password
π’ Final Result
β server4.company.com added
β Correct alias: db1
β Correct connection type: winrm
β Correct authentication variable
β Linux and Windows properly differentiated
β Lab requirement satisfied
π― What I Learned
I learned how to:
β Configure mixed Linux & Windows inventory
β Use ansible_ssh_pass vs ansible_password
β Configure WinRM connection
β Properly define host-specific connection types
Task 8 Solutions
β
Part 1: Lab Step-by-Step Guidelines
π© Step 1 β Switch to thor (if not already)
whoami
Output must be:
thor
π© Step 2 β Verify inventory file
cat /home/thor/playbook/inventory-t3q2
Output
stapp01 ansible_host=172.16.238.10 ansible_ssh_pass=Ir0nM@n
stapp02 ansible_host=172.16.238.11 ansible_ssh_pass=Am3ric@
stapp03 ansible_host=172.16.238.12 ansible_ssh_pass=BigGr33n
Update with this
stapp01 ansible_host=172.16.238.10 ansible_ssh_pass=Ir0nM@n ansible_user=tony
stapp02 ansible_host=172.16.238.11 ansible_ssh_pass=Am3ric@ ansible_user=steve
stapp03 ansible_host=172.16.238.12 ansible_ssh_pass=BigGr33n ansible_user=banner
π© Step 3 β Generate SSH key (if not already created)
Check if key exists:
ls ~/.ssh
If id_rsa does NOT exist, generate one:
ssh-keygen -t rsa
Press Enter for:
File location
Passphrase
Confirm passphrase
This creates:
~/.ssh/id_rsa
~/.ssh/id_rsa.pub
π© Step 4 β Copy SSH key to App Server 3
Use the user defined in inventory (usually banner).
ssh-copy-id banner@stapp03
Enter the password when prompted.
This enables password-less SSH.
π© Step 5 β Verify manual SSH works without password
ssh banner@stapp03
It should log in without asking for password.
Exit:
exit
π© Step 6 β Run Ansible ping using provided inventory
cd /home/thor/playbook
ansible -i inventory-t3q2 stapp03 -m ping
Expected output:
thor@jumphost ~/playbook$ ansible -i inventory-t3q2 stapp03 -m ping
stapp03 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
β SSH key authentication working
β Ansible connectivity verified
β Lab requirement satisfied
π§ Part 2: Simple Step-by-Step Explanation (Beginner Friendly)
Letβs explain what we built in a simple way.
π What Are We Building?
We are creating this connection:
Jump Host (thor)
β
SSH Key Authentication
β
App Server 3
So Ansible can connect without typing passwords.
π’ Step 1 β Why Password-less SSH?
Ansible is automation.
If every connection asks for a password:
Password:
Automation breaks.
So we use SSH keys instead.
π’ Step 2 β What Does ssh-keygen Do?
It creates:
Private key β stays on jump host
Public key β gets copied to remote server
Think of it like:
Private Key β Your secret key
Public Key β Lock installed on server
If they match β access granted.
π’ Step 3 β What Does ssh-copy-id Do?
It:
1οΈβ£ Takes your public key
2οΈβ£ Adds it to:
~/.ssh/authorized_keys
on App Server 3
3οΈβ£ Enables password-less login
π’ Step 4 β Why Test Manual SSH First?
If this works:
ssh banner@stapp03
Without password β Ansible will work.
If manual SSH fails β Ansible will fail too.
Always test SSH first.
π’ Step 5 β What Does Ansible Ping Actually Test?
It checks:
SSH connectivity
Python interpreter availability
Inventory correctness
It does NOT use network ping.
π’ Final Result
After completion:
β SSH key configured
β No password prompts
β Ansible ping successful
β Inventory used correctly
β Lab requirement satisfied
π― What I Learned
I learned how to:
β Set up password-less SSH
β Use ssh-keygen and ssh-copy-id
β Test SSH connectivity properly
β Validate Ansible communication
Task 9 Solutions
β
Part 1: Lab Step-by-Step Guidelines
π© Step 1 β Move to the ansible directory
cd /home/thor/ansible
π© Step 2 β Create the playbook file
vi playbook-t1q2.yml
π© Step 3 β Add the correct playbook content
Insert exactly this:
---
- name: Echo Welcome on localhost
hosts: localhost
connection: local
gather_facts: no
tasks:
- name: Run echo command
command: echo Welcome!
Save and exit.
π© Step 4 β Test the playbook
Run:
ansible-playbook playbook-t1q2.yml
Expected output:
thor@jumphost ~/ansible$ ansible-playbook playbook-t1q2.yml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does
not match 'all'
PLAY [Echo Welcome on localhost] ****************************************************************************
TASK [Run echo command] *************************************************************************************
changed: [localhost]
PLAY RECAP **************************************************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
π§ Part 2: Simple Step-by-Step Explanation (Beginner Friendly)
Letβs explain what we built in a simple way.
π What Are We Building?
We are telling Ansible:
βRun a command on this same machine.β
So the flow is:
Ansible Playbook
βββ
Runs on localhost
βββ
Executes: echo Welcome!
βββ
Prints: Welcome!
π’ Step 1 β Why hosts: localhost?
We are not targeting remote servers.
We want Ansible to run on:
localhost
That means:
This same jump host.
π’ Step 2 β Why connection: local?
By default, Ansible tries SSH.
But localhost does not need SSH.
So we tell Ansible:
connection: local
Meaning:
Execute directly on this machine.
π’ Step 3 β Why Use command Module?
We use:
command: echo Welcome!
The command module:
Executes a command
Does not use a shell
Is safe and simple
Since we just need to echo text, this is perfect.
π’ What Happens Internally?
When you run:
ansible-playbook playbook-t1q2.yml
Ansible:
1οΈβ£ Reads the playbook
2οΈβ£ Targets localhost
3οΈβ£ Runs command module
4οΈβ£ Prints output
π’ Final Result
β Playbook created at correct path
β Runs on localhost
β Executes echo command
β Displays βWelcome!β
β No extra arguments required
β Lab requirement satisfied
π― What I Learned
I learned how to:
β Create a basic Ansible playbook
β Run tasks on localhost
β Use connection: local
β Execute shell commands using Ansible
Task 10 Solutions
β
Part 1: Lab Step-by-Step Guidelines
π© Step 1 β Open the problematic playbook
cat /home/thor/ansible/playbook-t1q5.yml
π© Step 2 β Check for common YAML errors
Playbook currently has:
- host: localhost
β host is incorrect
β It must be hosts
Ansible requires the keyword:
hosts:
Edit the file:
vi /home/thor/ansible/playbook-t1q5.yml
Replace its content with:
---
- hosts: localhost
connection: local
gather_facts: no
tasks:
- name: Debug a message
debug:
msg: "Hello There!"
Save and exit.
π© Step 3 β Validate syntax before running
Use:
ansible-playbook /home/thor/ansible/playbook-t1q5.yml --syntax-check
This will show the exact line number of the problem.
π© Step 4 β Run playbook to confirm fix
ansible-playbook /home/thor/ansible/playbook-t1q5.yml
Expected:
thor@jumphost ~$ ansible-playbook /home/thor/ansible/playbook-t1q5.yml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does
not match 'all'
PLAY [localhost] ********************************************************************************************
TASK [Debug a message] **************************************************************************************
ok: [localhost] => {
"msg": "Hello There!"
}
PLAY RECAP **************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
π§ Part 2: Simple Step-by-Step Explanation (Beginner Friendly)
Letβs explain what went wrong in a very simple way.
π What Was the Problem?
You wrote:
host: localhost
But Ansible playbooks require:
hosts: localhost
That βsβ matters.
YAML is strict.
Ansible expects exact keywords.
π’ Why hosts Is Mandatory
Every playbook must define:
hosts:
It tells Ansible:
βWhere should this play run?β
Without it, Ansible does not understand the play structure.
π’ Why We Added gather_facts: no
By default, Ansible gathers system facts.
For a simple debug message, that is unnecessary.
So we disable it for faster execution.
(Not mandatory, but cleaner.)
π’ Correct Playbook Structure
Every valid playbook should look like:
- hosts: tasks:
That is the minimum required structure.
π― What I Learned
I learned:
β hosts is required (not host)
β YAML is indentation and keyword sensitive
β Small spelling errors break playbooks
β How to debug simple syntax issues
Top comments (0)