- Ansible is agentless; this means no agent neeeds to be installed on the target hosts; ssh access is just enough
- Ansible will be run on a control node, which executes the remote tasks.
- Target hosts are also called managed nodes
- Plugins can be used to expand the capabilities of ansible.
- Ansible content can be distributed and shared through Ansible Galaxy. Its like a marketplace.
- A inventory is a list of managed nodes/hosts
- All hosts should be added to the inventory.ini file (hostname or ip address).
- The hosts can be grouped; the group name is inside brackets
[] - The inventory can be ether a
.inior a.yamlfile - Its also possible to declare variables inside of the inventory file
- Its possible to define ranges with
[01:50]. It's also possible to skip some numbers with a stride[01:50:2]so every odd number gets used. - Alphabetical ranges are also possible
- It's possible to configure ansible to escalate privileges after sshing into a host (so it has root privileges)
Verify inventory
ansible-inventory -i inventory.ini --list ansible test -m ping -i inventory.yaml| Parameter | Meaning |
|---|---|
-u |
Defines the user to use for ssh into the servers |
-i |
Specifies the inventory file to use |
--check |
A sort of dry run; hosts configuration don't gets altered |
-
A playbook is an automation blueprint
-
It consists of plays, tasks & modules
-
They have a hierarchy:
- Playbook (List of plays)
- Play (Ordered list of tasks)
- Task (Reference to module for executing a task)
- Module (The code that gets run)
- Task (Reference to module for executing a task)
- Play (Ordered list of tasks)
- Playbook (List of plays)
-
A playbook is defined in a
playbook.yaml-file -
A playbook can be run with the
ansible-playbookcommand
ansible-playbook -i inventory.yaml playbook.yaml- A play is a ordered list of tasks with the definition on how to run them (variables, etc.)
- Each play consists of at minium the nodes to target and the tasks to execute
- So this is a play
- name: Ping specified hosts
hosts: test
tasks:
- name: Ping
ansible.builtin.ping:-
A task is an action inside of a play, which will be executed by a module
-
A module is simply the binary/code that gets run by a task
-
Most ansible modules check before execution if the desired state is already met, if this is the case, it won't do anything.
-
When you wan't to try a playbook without apply the changes to the system, you can pass the
--checkflag. -
So ansible will only do a "dry run" of the playbook without altering the system configuration.
-
This is great for testing new playbooks before running in production.
-
With
ansible-lintit's possible to check a playbook and get feedback about it. -
Just run
ansible-lintfollowed by the playbooks name
ansible-lint playbook.yaml- With
becomeyou can esacalate privileges More details
- Its possible to use jinja2 templates to create dynamic expressions with data like ip address, hostname or environmental information
- Templates get calculated on the control node and then will be sent, to the hosts. The hosts don't notice anything from the templating process.
- Jinja2 supports inline conditionals
"{{ 'wheel' if ansible_os_family == 'RedHat' else 'sudo' }}"python - Jinja2 shorthand conditional - Stack Overflow
- Filters are used to transform something into something for example json data to yaml data or generating a hash out of a string.
- Those filter transformations are aswell (same as with templating) executed on the control node.
- With filters its also possible to defined variables as mandatory or providing default values
Example for a default value
{{ some_variable | default(5) }}- Its also possible to set a default value if a boolean is false/true
- By default ansible requires values for custom set variables. To decalre a variable as optional
omitneeds to be set as default value
{{ item.mode | default(omit) }}To define a value as mandator, use mandatory
{{ variable | mandatory }}Its also possible to define a hint/custom error message, if a required value in undefined
galaxy_api_key: "{{ undef(hint='You must specify your Galaxy API key') }}"- A overview of the possibilites is provided on the corresponding ansible docs page.
- It's possible to define tests/conditions for each tasks, which need to be fulfilled, so the task gets run
- This can be also used for checking if some var is truthy
Example:
- debug:
msg: "Truthy"
when: value is truthy
vars:
value: "some string"- Maybe you want to run a task only on certain linux distributions/os families. Then you can use something like the following:
when: ansible_os_family == 'Debian'- When a playbook is run, ansible firstly gathers some information about the hosts, its running on
- Those facts than can be accessed as variables with
ansible_prefix - This enables the possibility to only run some tasks on certain operating systems
- Fact gathering can be disabled per play with
gather_facts: false
Docs Guide to Ansible Facts and Fact Gathering Best way to run a playbook with different OS’s? : r/ansible
- For debug and developement purposes the debug module can be handy
- It prints a speicifed message as console output
- Its also useful to combine this with conditions via the
when:directive
- name: Print os family
debug:
msg: "{{ ansible_os_family }}"- Variables prompts enable you to ask the user before running the playbook to input some variables/values for the current execution
- Those prompt variables can be defined with a list named
vars_prompt, instead of the defaultvars
vars_prompt:
- name: api_key
prompt: Enter the API key- This can be used for supplying sensitive information at runtime (like passwords) which weren't stored in Ansible Vault.
- Ad-hoc commands are an alternative way for running ansible commands
- They are ideal for simple "one command" tasks which were rarely done (like rebooting some servers)
- By default ansible uses the
ansible.builtin.commandmodule for ad-hoc commands - For example if you wan't to reboot a group of hosts, run:
ansible test -i inventory.yaml -a "/sbin/reboot"- With
-myou can tell ansible to use another module
ansible test -m ansible.builtin.copy -a "src=/etc/hosts dest=/tmp/hosts"- So for quick command execution ad-hoc commands are ideal.
- But for more complex stuff you should prefer the use of regular yaml playbooks
Show installed collections:
ansible-galaxy collection list- Ansible Vault is a tool to manage sensitive information within Ansible, so they don't need to be stored in plaintext
- It's is possible to use one password for encrypting all secrets or use one password per secret
- Each password has his own vault with an vault id. The vault id can be used to differentiate the passwords and where a secret is stored.
- The
--vault-idhas to be passed to ansible like follows:--vault-id label@source - Ansible Vault can be used to encrypt variables and files
- The encrypted content includes
!vaultto signalize that Ansible has to decrypt the content inside - The easiest way to use Ansible Vault is having an encrypted file which stores sensitive variables and then is encrypted via Ansible Vault.
- Using encrypted variables inside a playbook don't differs from using a plaintext variable, so it doens't interrupt you from doing your work.
- To encrypt a string on the fly, use the
encrypt_stringmethod
ansible-vault encrypt_string-
You will be prompted to input your vault password and afterwards the plaintext content of the secret
-
Notice that you end the input with twice typing
Ctrl + Dand not withEnter! -
Using
Entercounts as linebreak inside your secret -
Afterwards the encrypted string is shown in the console
-
From there you can copy and use it inside your playbooks
-
For decrypting to work right, you have to define them as variables
vars:
my_secret: !vault |
$ANSIBLE_VAULT;1.1;AES256
ENCRYPTED-VALUE- To access the secret you have to pass the parameter
--ask-vault-passwhen running a playbook - Whilst runtime you then will be asked for your encryption key
- Ansible Vault then will ensure the values get decrypted right
- Firstly create a file which contains sensitive information
my_secret: this-is-a-very-secret-information- Encrypt a file
ansible-vault encrypt <FILE>Example:
ansible-vault encrypt vars.yaml- When you want to adjust/edit your secrets, you have two ways to accomplish this:
ansible-vault decrypt vars.yaml- Don't forget to encrypt again after editing the file
ansible-vault edit vars.yaml- Referencing a vault item inside a playbook is done as with any other non-encrypted variable
- name: Get secret
debug:
msg: "{{ my_secret }}"- While running the playbook you than have to pass the secrets file with
-e
ansible-playbook -i inventory.yaml -e @vars.yaml --ask-vault-pass playbook.yaml- Alternatively to interactive passing the vault password (encryption key) to Ansible, you can use a password file, which contains the vault password
ansible-playbook -i inventory.yaml -e @vars.yaml --vault-password-file /path/to/password.file playbook.yaml - Notice that this file should be locked down/protected, so that not everyone can access it.
- The file shouldn't store the plaintext password on your disk, for obvious reasons
- The
--vault-password-fileparameter can be combined/tied together with other secret management tools or the CLI of a password manager for providing the password on the fly