PL - 006 — Ansible Practice: Managing Secrets, Ansible Facts
Managing Secrets
Using Ansible Vault
Secret
|
v
+----------------+
| Ansible Vault |
| Encryption |
+----------------+
|
v
Encrypted File
|
v
Git Repository
|
v
ansible-playbook
|
Vault password
|
v
Decrypt at runtime
|
v
Use secret securely
|
v
Target System
Lab Session
[cnode@control-node ~]$ ls
ansible-lab done validate_nodes.sh
[cnode@control-node ~]$ cat validate_nodes.sh
#!/bin/bash
nodes=(dev1 dev2 testserver prodserver)
for host in "${nodes[@]}";
do
echo "----- $host -----"
ssh -o BatchMode=yes \
-o PasswordAuthentication=no \
"cnode@$host" 'hostname; sudo -n whoami'
echo
done
[cnode@control-node ~]$ ./validate_nodes.sh
----- dev1 -----
dev1
root
----- dev2 -----
dev2
root
----- testserver -----
testserver
root
----- prodserver -----
prodserver
root
[cnode@control-node ~]$ cd ansible-lab/
[cnode@control-node ansible-lab]$ ls
ansible.cfg inventory vars-play.yml
[cnode@control-node ansible-lab]$ mv vars-play.yml ../done/
[cnode@control-node ansible-lab]$ ls
ansible.cfg inventory
[cnode@control-node ansible-lab]$
[cnode@control-node ansible-lab]$ ls
ansible.cfg inventory
[cnode@control-node ansible-lab]$ ansible-vault create secret.yml
New Vault password:
Confirm New Vault password:
[cnode@control-node ansible-lab]$ ls
ansible.cfg inventory secret.yml
[cnode@control-node ansible-lab]$ ls -l secret.yml
-rw-------. 1 cnode cnode 484 Sep 9 13:49 secret.yml
[cnode@control-node ansible-lab]$ cat secret.yml
$ANSIBLE_VAULT;1.1;AES256
31346562356565383666336333613262303966326261336238643963653433613135386563623438
3735373036363637373432313931363465643432636266320a323839633832326436356165663931
63323432393761623661663363613666343666396439666235643138306263323462363737346565
3063663961343333330a313337663763616530306137623630313633353762323561363431663639
36343539666335643037323131653238306664623137306235363764323031306432313131623331
6537376564366539666561376132613662646639326530353539
[cnode@control-node ansible-lab]$ ansible-vault view secret.yml
Vault password:
ERROR! Decryption failed (no vault secrets were found that could decrypt) on secret.yml for secret.yml
[cnode@control-node ansible-lab]$ ansible-vault view secret.yml
Vault password:
name: aadarsha
password: Nepal_123
[cnode@control-node ansible-lab]$
[cnode@control-node ansible-lab]$ ls
ansible.cfg inventory secret.yml
[cnode@control-node ansible-lab]$ vim secretfile.yml
[cnode@control-node ansible-lab]$ cat secretfile.yml
name: aadarsha
password: secret_password
[cnode@control-node ansible-lab]$ ansible-vault encrypt secretfile.yml
New Vault password:
Confirm New Vault password:
[WARNING]: Error in vault password prompt (default): Passwords do not match
ERROR! Passwords do not match
[cnode@control-node ansible-lab]$ ansible-vault encrypt secretfile.yml
New Vault password:
Confirm New Vault password:
Encryption successful
[cnode@control-node ansible-lab]$ cat secretfile.yml
$ANSIBLE_VAULT;1.1;AES256
38663636393038663237656236396631663465383862386565333362313136653464306435653265
6365356638353263653437393733393638313536306539360a323765643462653961396338643064
36333564663061393637623538336564636666666133616465366331363361313338313333363538
3034656531323562640a303230623437313030623961306438393261646662616337383934336665
30663632393530363637353134633634646233653461356563386230366433393862373463313632
6265316164326134623837323238656434373838363266366532
[cnode@control-node ansible-lab]$ ansible-vault view secretfile.yml
Vault password:
name: aadarsha
password: secret_password
[cnode@control-node ansible-lab]$
[cnode@control-node ansible-lab]$ ls
ansible.cfg inventory secretfile.yml secret.yml
[cnode@control-node ansible-lab]$ ansible-vault rekey secret.yml
Vault password:
New Vault password:
Confirm New Vault password:
Rekey successful
[cnode@control-node ansible-lab]$
[cnode@control-node ansible-lab]$ ansible-vault view secret.yml
Vault password:
name: aadarsha
password: Nepal_123
[cnode@control-node ansible-lab]$
[cnode@control-node ansible-lab]$ ansible-vault --help
[cnode@control-node ansible-lab]$ ls
ansible.cfg inventory secretfile.yml secret.yml
[cnode@control-node ansible-lab]$ ansible-vault decrypt secret.yml
Vault password:
Decryption successful
[cnode@control-node ansible-lab]$ cat secret.yml
name: aadarsha
password: Nepal_123
[cnode@control-node ansible-lab]$
[cnode@control-node ansible-lab]$ ansible-inventory --list
{
"_meta": {
"hostvars": {}
},
"all": {
"children": [
"ungrouped",
"develop",
"testprod"
]
},
"develop": {
"hosts": [
"dev1",
"dev2"
]
},
"production": {
"hosts": [
"prodserver"
]
},
"test": {
"hosts": [
"testserver"
]
},
"testprod": {
"children": [
"test",
"production"
]
}
}
[cnode@control-node ansible-lab]$
[cnode@control-node ansible-lab]$ ls
ansible.cfg inventory secretfile.yml secret.yml
[cnode@control-node ansible-lab]$ mkdir vars
[cnode@control-node ansible-lab]$ ansible-vault create vars/userinfo.yml
New Vault password:
Confirm New Vault password:
[cnode@control-node ansible-lab]$ ls vars/
userinfo.yml
[cnode@control-node ansible-lab]$ vi vault_usercreate.yml
[cnode@control-node ansible-lab]$ vim vault_usercreate.yml
[cnode@control-node ansible-lab]$ cat vault_usercreate.yml
---
#
- name: Create users using ansible vault
hosts: dev
vars_files:
- vars/userinfo.yml
tasks:
- name: Add a user
ansible.builtin.user:
name: "{{ username }}"
state: present
password: "{{ password | password_hash('sha512') }}"
[cnode@control-node ansible-lab]$ ansible-playbook --syntax-check --ask-vault-pass vault_usercreate.yml
Vault password:
[WARNING]: Could not match supplied host pattern, ignoring: dev
playbook: vault_usercreate.yml
[cnode@control-node ansible-lab]$ vim vault_usercreate.yml
[cnode@control-node ansible-lab]$ cat vault_usercreate.yml
---
#
- name: Create users using ansible vault
hosts: develop
vars_files:
- vars/userinfo.yml
tasks:
- name: Add a user
ansible.builtin.user:
name: "{{ username }}"
state: present
password: "{{ password | password_hash('sha512') }}"
[cnode@control-node ansible-lab]$ ansible-playbook --syntax-check --ask-vault-pass vault_usercreate.yml
Vault password:
playbook: vault_usercreate.yml
[cnode@control-node ansible-lab]$ ls
ansible.cfg secretfile.yml vars
inventory secret.yml vault_usercreate.yml
[cnode@control-node ansible-lab]$ echo "KhoYo123!" >passfile
[cnode@control-node ansible-lab]$ cat passfile
KhoYo123!
[cnode@control-node ansible-lab]$ ls -l passfile
-rw-r--r--. 1 cnode cnode 10 Sep 9 14:18 passfile
[cnode@control-node ansible-lab]$ chmod 400 passfile
[cnode@control-node ansible-lab]$ ls -l passfile
-r--------. 1 cnode cnode 10 Sep 9 14:18 passfile
[cnode@control-node ansible-lab]$ ansible-playbook --syntax-check --vault-password-file=passfile vault_usercreate.yml
playbook: vault_usercreate.yml
[cnode@control-node ansible-lab]$ ansible-playbook --vault-password-file=passfile vault_usercreate.yml
PLAY [Create users using ansible vault] ****************************************
TASK [Gathering Facts] *********************************************************
ok: [dev2]
ok: [dev1]
TASK [Add a user] **************************************************************
[DEPRECATION WARNING]: Encryption using the Python crypt module is deprecated.
The Python crypt module is deprecated and will be removed from Python 3.13.
Install the passlib library for continued encryption functionality. This
feature will be removed in version 2.17. Deprecation warnings can be disabled
by setting deprecation_warnings=False in ansible.cfg.
changed: [dev1]
changed: [dev2]
PLAY RECAP *********************************************************************
dev1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
dev2 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[cnode@control-node ansible-lab]$
ansible-doc user
:
/EXAMPLES
/password
[cnode@control-node ansible-lab]$ ls
ansible.cfg passfile secret.yml vault_usercreate.yml
inventory secretfile.yml vars
[cnode@control-node ansible-lab]$ ansible develop -m ansible.builtin.shell -a "id ram"
dev1 | CHANGED | rc=0 >>
uid=1006(ram) gid=1006(ram) groups=1006(ram)
dev2 | CHANGED | rc=0 >>
uid=1006(ram) gid=1006(ram) groups=1006(ram)
[cnode@control-node ansible-lab]$
[cnode@dev1 ~]$ hostname
dev1
[cnode@dev1 ~]$ grep ram /etc/passwd
ram:x:1006:1006::/home/ram:/bin/bash
[cnode@dev1 ~]$
Managing Ansible Facts
Ansible facts are variables that are automatically discovered by ansible on a managed host
Jinja2 template:
A Jinja2 template is a text-based file (typically HTML, XML, or configuration files) that combines static content with placeholder variables and control structures. Jinja2 is a fast, highly extensible template engine for Python inspired by Django’s template system. It isolates business logic from presentation by letting you dynamically inject data into your layout before rendering the final output.
[cnode@control-node ansible-lab]$ ls
ansible.cfg inventory
[cnode@control-node ansible-lab]$ ansible all --list-hosts
hosts (4):
dev1
dev2
testserver
prodserver
[cnode@control-node ansible-lab]$ ls ../done/
ansible.cfg passfile vars
files secretfile.yml vars-play.yml
inventory secret.yml vault_usercreate.yml
multiplays.yml undeploy-webserver.yml webserver.yml
[cnode@control-node ansible-lab]$ cp ../done/files/* ../done/webserver.yml .
[cnode@control-node ansible-lab]$ ls
ansible.cfg index.html inventory webserver.yml
[cnode@control-node ansible-lab]$ cp -r ../done/files .
[cnode@control-node ansible-lab]$ ls
ansible.cfg files index.html inventory webserver.yml
[cnode@control-node ansible-lab]$ rm index.html
[cnode@control-node ansible-lab]$ ls
ansible.cfg files inventory webserver.yml
[cnode@control-node ansible-lab]$ ls files/
index.html
[cnode@control-node ansible-lab]$
[cnode@control-node ansible-lab]$ vim webserver.yml
[cnode@control-node ansible-lab]$ ls
ansible.cfg files inventory webserver.yml
[cnode@control-node ansible-lab]$ vim inventory
[cnode@control-node ansible-lab]$ cat inventory
[myself]
control-node
[develop]
dev1
dev2
[test]
testserver
[production]
prodserver
[testprod:children]
test
production
[cnode@control-node ansible-lab]$ cat ansible.cfg
[defaults]
inventory = ./inventory
remote_user = cnode
[privilege_escalation]
become = true
become_method = sudo
[cnode@control-node ansible-lab]$ vim files/index.html
[cnode@control-node ansible-lab]$ cp files/index.html files/index.html.j2
[cnode@control-node ansible-lab]$ vim files/index.html.j2
[cnode@control-node ansible-lab]$ cat files/index.html.j2
<!DOCTYPE html>
<html>
<head>
<title>Ansible Lab</title>
</head>
<body>
<h1>Hello from Ansible!</h1>
<h2>Machine: {{ ansible_hostname }}
<p>This Apache web server was configured using Ansible.</p>
</body>
</html>
[cnode@control-node ansible-lab]$ vim webserver.yml
[cnode@control-node ansible-lab]$ vim webserver.yml
[cnode@control-node ansible-lab]$ ansible-playbook --syntax-check webserver.yml
playbook: webserver.yml
[cnode@control-node ansible-lab]$ ansible-playbook webserver.yml
PLAY [Configure Apache web server] *********************************************
TASK [Gathering Facts] *********************************************************
ok: [testserver]
ok: [prodserver]
TASK [Install Apache web server] ***********************************************
ok: [testserver]
ok: [prodserver]
TASK [Start and enable Apache service] *****************************************
ok: [prodserver]
ok: [testserver]
TASK [Print return information from the previous task] *************************
ok: [testserver] => {
"service_out": {
"changed": false,
"enabled": true,
"failed": false,
"name": "httpd",
"state": "started",
"status": {
"AccessSELinuxContext": "system_u:object_r:httpd_unit_file_t:s0",
"ActiveEnterTimestamp": "Wed 2026-09-09 12:08:33 +0545",
...
"WantedBy": "multi-user.target",
"Wants": "-.mount httpd-init.service",
"WantsMountsFor": "/var/tmp /tmp",
"WatchdogSignal": "6",
"WatchdogTimestampMonotonic": "0",
"WatchdogUSec": "0"
}
}
}
TASK [Allow HTTP traffic through the firewall] *********************************
ok: [prodserver]
ok: [testserver]
TASK [Deploy website index page] ***********************************************
changed: [prodserver]
changed: [testserver]
PLAY RECAP *********************************************************************
prodserver : ok=6 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
testserver : ok=6 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[cnode@control-node ansible-lab]$
[cnode@control-node ansible-lab]$ ansible testprod -m ansible.builtin.shell -a "curl 0"
testserver | CHANGED | rc=0 >>
<!DOCTYPE html>
<html>
<head>
<title>Ansible Lab</title>
</head>
<body>
<h1>Hello from Ansible!</h1>
<h2>Machine: testserver</h2>
<p>This Apache web server was configured using Ansible.</p>
</body>
</html> % Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:--100 222 100 222 0 0 221k 0 --:--:-- --:--:-- --:--:-- 216k
prodserver | CHANGED | rc=0 >>
<!DOCTYPE html>
<html>
<head>
<title>Ansible Lab</title>
</head>
<body>
<h1>Hello from Ansible!</h1>
<h2>Machine: prodserver</h2>
<p>This Apache web server was configured using Ansible.</p>
</body>
</html> % Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:--100 222 100 222 0 0 156k 0 --:--:-- --:--:-- --:--:-- 216k
[cnode@control-node ansible-lab]$
on testserver and prodserver
[cnode@testserver ~]$ cat /var/www/html/index.html
<!DOCTYPE html>
<html>
<head>
<title>Ansible Lab</title>
</head>
<body>
<h1>Hello from Ansible!</h1>
<h2>Machine: testserver</h2>
<p>This Apache web server was configured using Ansible.</p>
</body>
</html>
[cnode@testserver ~]$
[cnode@prodserver ~]$ cat /var/www/html/index.html
<!DOCTYPE html>
<html>
<head>
<title>Ansible Lab</title>
</head>
<body>
<h1>Hello from Ansible!</h1>
<h2>Machine: prodserver</h2>
<p>This Apache web server was configured using Ansible.</p>
</body>
</html>
[cnode@prodserver ~]$
[cnode@testserver ~]$ curl 0
<!DOCTYPE html>
<html>
<head>
<title>Ansible Lab</title>
</head>
<body>
<h1>Hello from Ansible!</h1>
<h2>Machine: testserver</h2>
<p>This Apache web server was configured using Ansible.</p>
</body>
</html>
[cnode@testserver ~]$
[cnode@prodserver ~]$ curl 0
<!DOCTYPE html>
<html>
<head>
<title>Ansible Lab</title>
</head>
<body>
<h1>Hello from Ansible!</h1>
<h2>Machine: prodserver</h2>
<p>This Apache web server was configured using Ansible.</p>
</body>
</html>
[cnode@prodserver ~]$