Skip to content

Ansible_advanced

This chapter covers advanced Ansible features including Vault, lookups, async tasks, and custom modules.

Ansible Vault encrypts sensitive data in playbooks and roles.

┌─────────────────────────────────────────────────────────────────────────────┐
│ Ansible Vault │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Vault Encryption │ │
│ │ │ │
│ │ ansible-vault create secrets.yml # Create encrypted file │ │
│ │ ansible-vault edit secrets.yml # Edit encrypted file │ │
│ │ ansible-vault decrypt secrets.yml # Decrypt file │ │
│ │ ansible-vault encrypt secrets.yml # Encrypt file │ │
│ │ ansible-vault view secrets.yml # View without decrypt │ │
│ │ ansible-vault rekey secrets.yml # Change password │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ Using encrypted files: │
│ ansible-playbook site.yml --vault-password-file ~/.vault_pass │
│ ansible-playbook site.yml --ask-vault-pass │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Terminal window
# Create new encrypted file
ansible-vault create secrets.yml
# Encrypt existing file
ansible-vault encrypt secrets.yml
# Edit encrypted file
ansible-vault edit secrets.yml
# View encrypted file
ansible-vault view secrets.yml
# group_vars/production/vault.yml (encrypted)
---
vault_db_password: "super_secret_password"
vault_api_key: "api_key_12345"
vault_ssl_cert: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
# Using vault variables
# (unencrypted file)
db_password: "{{ vault_db_password }}"
Terminal window
# Create password file
echo "my_vault_password" > .vault_pass
# Make secure
chmod 600 .vault_pass
# Use in playbook
ansible-playbook site.yml --vault-password-file .vault_pass

Lookups fetch data from external sources.

# Using lookups
---
- name: Get password from HashiCorp Vault
debug:
msg: "{{ lookup('hashi_vault', 'secret=secret/data/db:password') }}"
- name: Read file contents
debug:
msg: "{{ lookup('file', '/path/to/file.txt') }}"
- name: Get environment variable
debug:
msg: "{{ lookup('env', 'PATH') }}"
- name: Query DNS
debug:
msg: "{{ lookup('dig', 'example.com') }}"
- name: Use password store
debug:
msg: "{{ lookup('passwordstore', 'database/password') }}"
- name: Read from template
debug:
msg: "{{ lookup('template', 'config.j2') }}"
- name: URL content
debug:
msg: "{{ lookup('url', 'https://api.github.com') }}"
- name: CSV data
debug:
msg: "{{ lookup('csvfile', 'item=server1 file=inventory.csv delimiter=,') }}"
async_playbook.yml
---
- name: Run long-running tasks
hosts: all
tasks:
- name: Start backup
command: /opt/backup.sh
async: 3600 # Max runtime in seconds
poll: 0 # Don't wait, fire and forget
register: backup_job
- name: Check backup status
async_status:
jid: "{{ backup_job.ansible_job_id }}"
register: status
until: status.finished
retries: 100
delay: 30
- name: Download files in parallel
get_url:
url: "http://example.com/file{{ item }}.tar.gz"
dest: "/tmp/file{{ item }}.tar.gz"
loop: "{{ range(1, 11) | list }}"
throttle: 5 # Max parallel tasks

Run tasks on different hosts.

delegation_playbook.yml
---
- name: Deploy to webservers, manage on localhost
hosts: webservers
tasks:
- name: Deploy application
synchronize:
src: ./app/
dest: /opt/app/
- name: Restart app on all webservers
service:
name: myapp
state: restarted
delegate_to: "{{ inventory_hostname }}"
- name: Notify external service
uri:
url: https://api.example.com/deploy
method: POST
delegate_to: localhost
- name: Run on local machine
local_action:
module: command
cmd: echo "Running locally"
error_handling.yml
---
- name: Error handling with blocks
hosts: webservers
tasks:
- name: Block with rescue
block:
- name: Attempt risky operation
command: /opt/may_fail.sh
register: result
rescue:
- name: Handle failure
debug:
msg: "Operation failed: {{ result.stderr }}"
always:
- name: Always run this
debug:
msg: "Cleanup or notification"
- name: Handle errors
block:
- name: Install packages
apt:
name: "{{ packages }}"
state: present
failed_when: "'not found' in result.stderr"
changed_when: result.rc == 0
facts_playbook.yml
---
- name: Work with facts
hosts: all
tasks:
- name: Show all facts
debug:
var: ansible_facts
- name: Show specific facts
debug:
msg: "OS: {{ ansible_facts['distribution'] }}"
- name: Register variable
command: hostname
register: hostname_result
- name: Use registered variable
debug:
msg: "Hostname: {{ hostname_result.stdout }}"
- name: Hostvars
debug:
msg: "Other host IP: {{ hostvars['other.example.com'].ansible_host }}"
- name: Group names
debug:
msg: "Groups: {{ group_names }}"
- name: Loop hosts
debug:
msg: "Host: {{ item }}"
loop: "{{ groups['webservers'] }}"
library/custom_module.py
#!/usr/bin/python3
from ansible.module_utils.basic import AnsibleModule
def main():
module = AnsibleModule(
argument_spec=dict(
name=dict(type='str', required=True),
state=dict(type='str', default='present', choices=['present', 'absent'])
)
)
name = module.params['name']
state = module.params['state']
if state == 'present':
# Logic to ensure something exists
module.exit_json(changed=True, msg="Created resource")
else:
# Logic to remove something
module.exit_json(changed=True, msg="Removed resource")
if __name__ == '__main__':
main()
playbook.yml
---
- name: Use custom module
hosts: all
tasks:
- name: Call custom module
custom_module:
name: myresource
state: present
# Using filters
---
- name: Use filters
hosts: localhost
gather_facts: no
vars:
numbers: [1, 2, 3, 4, 5]
user_data:
name: john
email: john@example.com
tasks:
- name: String filters
debug:
msg: "{{ 'hello' | upper }}"
- name: Number filters
debug:
msg: "{{ numbers | sum }}"
- name: JSON filter
debug:
msg: "{{ user_data | to_json }}"
- name: Default filter
debug:
msg: "{{ undefined_var | default('default_value') }}"
- name: Unique filter
debug:
msg: "{{ [1,2,2,3] | unique }}"
- name: Zip filter
debug:
msg: "{{ ['a','b'] | zip(['1','2']) | list }}"
- name: Ternary filter
debug:
msg: "{{ (true) | ternary('yes', 'no') }}"
performance_playbook.yml
---
# Use free strategy (run tasks as fast as possible)
- name: Fast execution
hosts: all
strategy: free
tasks:
- name: Quick tasks
yum:
name: "{{ item }}"
state: present
loop:
- vim
- curl
# Use serial for rolling updates
- name: Rolling update
hosts: webservers
serial: 1 # Or percentage: "25%"
tasks:
- name: Update service
yum:
name: myapp
state: latest
- name: Verify
uri:
url: http://localhost/health
┌─────────────────────────────────────────────────────────────────────────────┐
│ Ansible Security Best Practices │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. Credentials Management │
│ ✓ Use Ansible Vault for secrets │
│ ✓ Use external secrets management (HashiCorp Vault) │
│ ✓ Never commit secrets to version control │
│ │
│ 2. SSH Security │
│ ✓ Use SSH keys instead of passwords │
│ ✓ Enable StrictHostKeyChecking │
│ ✓ Use ansible-bender for encrypted connections │
│ │
│ 3. Privilege Escalation │
│ ✓ Use become: yes only when necessary │
│ ✓ Limit sudo access │
│ ✓ Use specific sudo users instead of all │
│ │
│ 4. Code Review │
│ ✓ Review playbooks before running │
│ ✓ Use --check mode (dry run) │
│ ✓ Use --diff to see changes │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Terminal window
# Syntax check
ansible-playbook --syntax-check playbook.yml
# Dry run
ansible-playbook --check playbook.yml
# Show differences
ansible-playbook --diff playbook.yml
# Lint with ansible-lint
ansible-lint playbook.yml
molecule/default/converge.yml
---
- name: Converge
hosts: all
become: yes
roles:
- role: my_role
my_role_var: test_value
Terminal window
# Run molecule tests
molecule test
# Create scenario
molecule init scenario
# List scenarios
molecule list

In this chapter, you learned:

  • Ansible Vault: Encrypting sensitive data
  • Lookups: Fetching data from external sources
  • Async Tasks: Running long-running tasks
  • Delegation: Running on different hosts
  • Error Handling: Blocks and rescue
  • Custom Modules: Creating your own modules
  • Jinja2 Filters: Data transformation
  • Performance: Strategies and parallel execution
  • Security Best Practices: Securing Ansible
  • Testing: Syntax check, dry run, Molecule