Manage secrets, facts and cycles
1. Manage confidentiality
1.1 ansible vault
Ansible may need to access sensitive data such as passwords or apl keys so that managed hosts can be configured. Generally, this information may be stored in manifest variables or other ansible files in plain text. However, any user who has access to ansible files can access it, which poses a security risk
Ansible vault provided by ansible can decrypt and encrypt any structured data file used by ansible. To use ansible vault, you can create, edit, encrypt, decrypt, and view files through ansible vault's command-line tools
1.1.1 creating encrypted files
Use ansible vault create filename to create a new encrypted file. Enter the password. The default editor is vi to open the file
[root@my ansible]# ansible-vault create group_vars/apache New Vault password: Confirm New Vault password:
1.1.2 viewing encrypted files
Use ansbile vault view filename to view the encrypted file without having to open it for editing
[root@my ansible]# cat group_vars/apache $ANSIBLE_VAULT;1.1;AES256 33396234613132373566303135306537363139366334343463383065363061336362633333663436 3762353739663035323539613466643239326661633566620a353464626663623133366562636239 63623636346131383162326236666563373933363033613461383032646330303834303434613664 3863386262383932350a343130623164633132376632393563396461613739366630626633376637 36396633666166376537316237613862643666343861363132626566303233353430643862303961 3265636561646264343838626133353239376665613632356364 [root@my ansible]# ansible-vault view group_vars/apache Vault password: ansible_user=root ansible_password=1
1.1.3 decrypt encrypted files
Use the ansbile vault decrypt filename command to permanently decrypt
[root@my ansible]# ansible-vault decrypt group_vars/apache Vault password: Decryption successful [root@my ansible]# cat group_vars/apache ansible_user=root ansible_password=1
1.1.4 the file already exists. Now encrypt it
Use ansible vault encrypt filename
[root@my ansible]# ansible-vault encrypt group_vars/apache New Vault password: Confirm New Vault password: Encryption successful
1.1.5 edit encrypted files
Use ansible vaule edit filename
[root@my ansible]# ansible-vault edit group_vars/apache Vault password: //Enter the password here //Enter the password and enter the vi editor automatically ansible_user=root ansible_password=1
1.1.6 re encrypt encrypted files
Using the ansible vault rekey filename, you need to enter the old password to modify the new password
[root@my ansible]# ansible-vault rekey group_vars/apache Vault password: New Vault password: Confirm New Vault password: Rekey successful
1.2 playbook and ansible vault
To run a playbook that can access files encrypted by ansible vault, you need to provide the encrypted file to the ansible playbook command. If you do not provide a password, playbook will return an error
[root@my ansible]# ansible-playbook group_vars/apache / / no password provided ERROR! Attempting to decrypt but no vault secrets found
To provide a vault password for the playbook, use the – vault ID option, as shown in
//This is the password you entered manually [root@my ansible]# ansible-playbook --vault-id @prompt playbook/test.yml Vault password (default): ERROR! variable files must contain either a dictionary of variables, or a list of dictionaries. Got: user:yi (<class 'ansible.parsing.yaml.objects.AnsibleUnicode'>)
Alternatively, you can use – vault password file = file name
[root@my ansible]# ls -a . .. ansible.cfg group_vars hosts host_vars inventory playbook roles [root@my ansible]# vim .mima / / set a hidden file name for storing passwords [root@my ansible]# cat .mima 1 [root@my ansible]# ansible-vault view --vault-password-file=.mima group_vars/apache ansible_user=root ansible_password=1 [root@my ~]# openssl rand -base64 20 / / this is a randomly generated password 2mSBfy2utJiEIhIGVJMLrVSg008=
//decrypt [root@my ansible]# ansible-vault decrypt --vault-password-file=.mima group_vars/apache Decryption successful [root@my ansible]# cat group_vars/apache ansible_user=root ansible_password=1 //Encrypt an existing file [root@my ansible]# ansible-vault encrypt --vault-password-file=.mima group_vars/apache Encryption successful //Reset the password without entering a new password [root@my ansible]# vim .xinmima [root@my ansible]# cat .xinmima 1 [root@my ansible]# ansible-vault rekey --vault-password-file=.mima --new-vault-password-file=.xinmima group_vars/apache Rekey successful
1.2.1 recommended practices for variable file management
The general meaning is to put the variables that need to be encrypted under one file and the variables that do not need to be encrypted under another file, which means open
//Create a user module, encrypt variables, and execute after encryption [root@my ansible]# cat playbook/test.yml --- - hosts: "*" vars_files: - vars/users.yml tasks: - name: create user {{ user }} user: user: "{{ user }}" state: present [root@my ansible]# cat .mima 1 [root@my ansible]# ansible-vault create --vault-password-file=.mima playbook/vars/users.yml [root@my ansible]# ansible-playbook --vault-password-file=.mima playbook/test.yml PLAY [*] **************************************************************************************************** TASK [Gathering Facts] ************************************************************************************** ok: [192.168.47.147] TASK [create user yi] *************************************************************************************** changed: [192.168.47.147] PLAY RECAP ************************************************************************************************** 192.168.47.147 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [root@apache ~]# id yi uid=2002(yi) gid=2002(yi) group=2002(yi)
2. Management facts
2.1 describe ansible facts
Ansible is actually a variable that ansible automatically detects on the managed host. The fact contains host related information
Collecting ide facts for managed hosts may include:
- Host name
- Kernel version
- network interface
- IP address
- Operating system version
- Various environmental variables
- Number of CPU s
- Memory provided or available
- disk space available
With the help of facts, it is convenient to detect the state of the managed host and determine the operations to be performed according to the state, such as:
- You can restart the server by running the conditional task based on the fact that it contains the current kernel version of the managed host
- MySQL configuration files can be customized based on available memory through fact reporting
- You can set the IPv4 address used in the configuration file based on the value of the fact
Usually, each play will automatically run the setup module before the first task
//On the command line [root@my ansible]# ansible all -m setup | less 192.168.47.147 | SUCCESS => { "ansible_facts": { //This is all information "ansible_all_ipv4_addresses": [ "192.168.47.147" ], "ansible_all_ipv6_addresses": [ "fe80::5421:1580:4f7f:fa15" ], "ansible_apparmor": { "status": "disabled" }, "ansible_architecture": "x86_64", "ansible_bios_date": "07/29/2019", "ansible_bios_version": "6.00", //In playbook [root@my playbook]# cat test.yml --- - hosts: "*" tasks: - name: my debug: var: ansible_facts //Meaning of var variable [root@my playbook]# ansible-playbook test.yml / / this is to get all TASK [my] *************************************************************************************************** ok: [192.168.47.147] => { "ansible_facts": { "all_ipv4_addresses": [ "192.168.47.147" ], "all_ipv6_addresses": [ //Get the facts you want in playbook [root@my playbook]# vim test.yml [root@my playbook]# cat test.yml --- - hosts: "*" tasks: - name: my debug: var: ansible_facts['all_ipv4_addresses'] [root@my playbook]# ansible-playbook test.yml PLAY [*] **************************************************************************************************** TASK [Gathering Facts] ************************************************************************************** ok: [192.168.47.147] TASK [my] *************************************************************************************************** ok: [192.168.47.147] => { "ansible_facts['all_ipv4_addresses']": [ "192.168.47.147" //Here is the result ] } //Get a little more accurate [root@my playbook]# cat test.yml --- - hosts: "*" tasks: - name: my debug: var: ansible_facts['default_ipv4']['address'] //The difference is here [root@my playbook]# ansible-playbook test.yml PLAY [*] **************************************************************************************************** TASK [Gathering Facts] ************************************************************************************** ok: [192.168.47.147] TASK [my] *************************************************************************************************** ok: [192.168.47.147] => { "ansible_facts['default_ipv4']['address']": "192.168.47.147" //The result is here }
//Another method, python, is not recommended [root@my playbook]# cat test.yml --- - hosts: "*" tasks: - name: my debug: var: ansible_facts.default_ipv4.address //Here it is
The following table is the facts collected by the controlled node and can be used in the playbook:
fact | variable |
---|---|
Short host name | ansible_facts['hostname'] |
Fully qualified domain name | ansible_facts['fqdn'] |
IPv4 address | ansible_facts['default_ipv4']['address'] |
Name list of all network interfaces | ansible_facts['interfaces'] |
/Size of dev/vda1 disk partition | ansible_facts['devices']['vda']['partitions']['vda1']['size'] |
DNS server list | ansible_facts['dns']['nameservers'] |
Currently running kernel version | ansible_facts['kernel'] |
When using facts in playbook, ansible dynamically replaces the variable name of facts with the corresponding value:
msg: meaning of information
[root@my playbook]# cat test.yml --- - hosts: "*" tasks: - name: my debug: msg: > The host named {{ ansible_facts['fqdn'] }}of ip is {{ ansible_facts['default_ipv4']['address'] }} [root@my playbook]# ansible-playbook test.yml PLAY [*] **************************************************************************************************** TASK [Gathering Facts] ************************************************************************************** ok: [192.168.47.147] TASK [my] *************************************************************************************************** ok: [192.168.47.147] => { "msg": "The host named apache of ip is 192.168.47.147\n" //My other host is called apache, and the address is 47.147 }
2.2 inject ansible facts as variables
Comparison of selected ansible fact names
ansible_facts form | Form of old fact variable |
---|---|
ansible_facts['hostname'] | ansible_hostname |
ansible_facts['fqdn'] | ansible_fqdn |
ansible_facts['default_ipv4']['address'] | ansible_default_ipv4['address'] |
ansible_facts['interfaces'] | ansible_interfaces |
ansible_facts['devices']['vda']['partitions']['vda1']['size'] | ansible_devices['vda']['partitions']['vda1']['size'] |
ansible_facts['dns']['nameservers'] | ansible_dns['nameservers'] |
ansible_facts['kernel'] | ansible_kernel |
Insert in the [default] section of the Ansible configuration file_ facts_ as_ Set the vars parameter to False to turn off the old naming system. After closing, you can only use the new ansible_facts.* The naming system refers to Ansible fact. The default setting is currently True.
[root@my ansible]# vim ansible.cfg # will be changed to a default of 'False' in a future release. # ansible_facts. inject_facts_as_vars = false
2.3 close fact collection
Reasons for closing facts:
- Not prepared to use any facts
- Hope to speed up play
- You want to reduce the load caused by play on the managed host
- The managed host cannot run the setup module for some reason
- You need to install some prerequisite software before collecting facts
To disable fact collection for play, set gather_ Set the facts keyword to no:
--- - hosts: "*" gather_facts: no //Here it is
Even if gather is set for play_ Facts: No, you can also manually collect facts at any time by running the task using the setup module:
--- - hosts: "*" gather_facts: no tasks: - name: my setup: - name: debug var: ansible_facts //Turning it off and on belongs to cerebral palsy. It won't be used basically
2.4 custom creation facts
By default, the setup module is from / etc / ansible / facts.com of each managed host Load custom facts in the files and scripts in the D directory. The name of each file or script must be in The end of fact can only be used.
Available INI and JSON formats
[root@apache ~]# mkdir -p /etc/ansible/facts.d [root@apache ~]# cd /etc/ansible/facts.d/ [root@apache facts.d]# vim my.fact [root@apache facts.d]# cat my.fact [packages] web_package = httpd db_package = mariadb-server [users] user1 = joe user2 = jane [root@my playbook]# ansible all -m setup|less "ansible_local": { //Search ansible_local "my": { "packages": { "db_package": "mariadb-server", "web_package": "httpd" }, "users": { "user1": "joe", "user2": "jane"
Custom facts are stored in ansible by the setup module_ facts. ansible_ Local variable.
2.5 magic variables
Some variables are not facts or configured through the setup module, but are also automatically set by Ansible. These magic variables can also be used to obtain information related to a specific managed host.
There are four most commonly used:
Magic variable | explain |
---|---|
hostvars | A variable that contains a managed host and can be used to get the value of a variable of another managed host. If facts have not been collected for the managed host, it will not contain the facts for that host. |
group_names | Lists all groups to which the currently managed host belongs |
groups | Lists all groups and hosts in the list |
inventory_hostname | Contains the host name of the currently managed host configured in the manifest. For various reasons, it may be different from the host name reported in the fact |
One way to gain insight into their values is to use the debug module to report the contents of the hostvars variable for a specific host:
ansible 192.168.47.147 -m debug -a 'var=hostvars["localhost"]'
3. Task cycle
3.1 write cycle and condition tasks
By using loops, the first mock exam does not need to write multiple tasks. Instead of writing five tasks to ensure that there are five users, they just need to write one task to iterate over a list of five users to ensure that they all exist.
Ansible supports iterative tasks on a set of projects using the loop keyword. Loops can be configured to repeat tasks using items in the list, the contents of files in the list, generated sequences of numbers, or more complex structures
3.1.1 simple cycle
A simple loop iterates over a set of projects. Add the loop keyword to the task and take the list of items that should be iterated by it as the value. The loop variable item holds the values used during each iteration.
[root@my playbook]# cat user.yml --- - name: task1 hosts: "*" tasks: - name: Create user {{ item }} user: name: "{{ item }}" state: present loop: - user1 - user2 - user3 [root@my playbook]# ansible-playbook user.yml PLAY [task1] ************************************************************************************************ TASK [Gathering Facts] ************************************************************************************** ok: [192.168.47.147] TASK [Create user {{ item }}] ************************************************************************************** changed: [192.168.47.147] => (item=user1) changed: [192.168.47.147] => (item=user2) changed: [192.168.47.147] => (item=user3) PLAY RECAP ************************************************************************************************** 192.168.47.147 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [root@apache facts.d]# id user1 uid=2003(user1) gid=2003(user1) group=2003(user1) [root@apache facts.d]# id user2 uid=2004(user2) gid=2004(user2) group=2004(user2) [root@apache facts.d]# id user3 uid=2005(user3) gid=2005(user3) group=2005(user3)
//Another way [root@my ansible]# cat playbook/vars/users.yml user: - user1 - user2 - user3 [root@my ansible]# cat playbook/user.yml --- - name: task1 hosts: "*" vars_file: - vars/users.yml tasks: - name: Create user {{ item }} user: name: "{{ item }}" state: absent loop: "{{ user }}" [root@my ansible]# ansible-playbook playbook/user.yml
3.1.2 circular hash or dictionary list
//The first way [root@my playbook]# vim user.yml --- - name: task hosts: "*" vars_file: - vars/users.yml tasks: - name: Create user {{ item.name }} user: name: "{{ item.name }}" uid: "{{ item.uid}}" state: present loop: - name: user1 uid: 2222 [root@my playbook]# ansible-playbook user.yml //The second way [root@my playbook]# cat user.yml --- - name: task hosts: "*" vars_file: - vars/users.yml tasks: - name: Create user {{ item.name }} user: name: "{{ item.name }}" uid: "{{ item.uid}}" state: present loop: "{{ user }}" [root@my playbook]# cat vars/users.yml user: - name: user1 uid: 2222 - name: user2 uid: 2223 [root@my playbook]# ansible-playbook user.yml
3.1.3 cyclic keywords of earlier styles
Circular keyword | describe |
---|---|
with_items | The behavior is the same as the loop keyword of a simple list, such as a string list or a hash / dictionary list. But different from loop, if it is with_items provides a list of lists, which will be flattened into a single-level list. The loop variable item holds the list items used during each iteration. |
with_file | This keyword requires a list of control node file names. The loop variable item saves the contents of the corresponding file in the file list during each iteration. |
with_sequence | This keyword does not require a list, but requires parameters to generate a list of values from a sequence of numbers. The loop variable item saves the value of a generated item in the generated sequence during each iteration. |
vars: data: - user0 - user1 - user2 tasks: - name: "with_items" debug: msg: "{{ item }}" with_items: "{{ data }}"
3.1.4 use register variable with loop
[root@my playbook]# cat test.yml --- - hosts: "*" gather_facts: no tasks: - name: my command: "echo hello {{ item }},how are you" loop: - tom - awm register: result - debug: var: result