ansible manage variables and encryption and decryption
Introduction to ansible variable
Ansible supports the use of variables to store values and reuse these values in all files of ansible projects. This simplifies the creation and maintenance of projects and reduces the number of errors.
For example, a variable might contain the following values:
-
User to create
-
Packages to install
-
Services to restart
-
Files to delete
-
Archive to retrieve from the Internet
Named variable rules
The name of a variable must start with a letter and can only contain letters, numbers, and underscores.
invalid argument | Valid variables |
---|---|
qqq 123 | qqq_123 |
list 123 abc | list_123_abc |
QQQ.123 | QQQ_123 |
list @1 | list1 or list_ one |
Define variables
Variables can be defined at multiple locations in an Ansible project. However, these variables can be roughly reduced to three range levels:
Global variables: variables set from the command line or Ansible configuration
Play range: variables set in play and related structures
Host scope: tasks collected or registered by lists, facts, and variables set on host groups and individual hosts
If a variable with the same name is defined in more than one xekl (level), the variable with the highest priority is used. Narrow scope takes precedence over broader scope: variables defined by the manifest will be overwritten by variables defined by playbook, which will be overwritten by variables defined on the command line.
Variables in playbook
Variables play an important role in Ansible Playbook because they can simplify the management of variable data in playbook.
Defining variables in playbook
When you write playbook, you can define your own variables and then call these values in your tasks.
The playbook variable can be defined in many ways. A common way is to put variables in the vars block at the beginning of Playbook:
--- - hosts: server1 remote_user: tom vars: //Variable module IP: 192.168.56.199 //Define variables NAME: node4 tasks: - name: test lineinfile: path: /etc/hosts line: "{{ IP }} {{ NAME }}" //If {{IP}} is preceded by a letter, do not type "" state: present //View results [root@server1 etc]# cat hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.56.130 server1 192.168.56.199 node4
You can also define variables outside the playbook
You can also define the playbook variable in an external file. Instead of using the vars block in the playbook, you can use vars instead_ Files directive, followed by a list of external variable file names relative to the playbook position:
//Write variable file
[root@control book]# ls ansible.cfg node1.yml playbook vars [root@control book]# cat vars/time.yml IP: 192.168.56.179 NAME: node7
//The variable file must be at the same level as the manifest file, otherwise the variable file cannot be found
[root@control vars]# tree /opt/book/vars/ /opt/book/vars/ ├── ansible.cfg ├── host_vars │ ├── 192.168.56.130 │ ├── node1.yml │ └── time.yml └── playbook
//Modify file
[root@control vars]# cat node1.yml --- - hosts: server1 remote_user: tom vars_files: //External variable module - vars/time.yml //Variable address tasks: - name: test lineinfile: path: /etc/hosts line: "{{ IP }} {{ NAME }}" //Reference variable state: present //implement [root@control vars]# ansible-playbook node1.yml PLAY [server1] ***************************************************************** TASK [Gathering Facts] ********************************************************* ok: [192.168.56.130] TASK [test] ******************************************************************** changed: [192.168.56.130] PLAY RECAP ********************************************************************* 192.168.56.130 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 //see [root@server1 etc]# cat hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.56.130 server1 192.168.56.199 node4 192.168.56.179 node7
Host and group variables
The list variables directly applied to the host are divided into two categories:
- Host variable, applied to a specific host
- Group management, which applies to a host group or all hosts in a group of hosts
Host variables take precedence over group variables, but variables defined in playbook take precedence over both
Variables in playbook > host variables > group variables
One way to define host and group variables is to define them directly in the manifest file.
This is an old practice and is not recommended, but you may encounter it in your future work.
Define host variables:
[root@control vars]# cat playbook [server1] 192.168.56.130 ansible_user=root ansible_password=1
Populate host and group variables with directories
The preferred way to define variables for hosts and host groups is to create groups in the same working directory as the manifest file or directory_ Vars and host_vars two directories. These two directories contain files for defining group variables and host variables, respectively.
The recommended practice is to use host_vars and groups_ The vars directory defines manifest variables instead of defining them directly in the manifest file.
Create Host Directory
[root@control vars]# tree /opt/book/vars/ /opt/book/vars/ ├── ansible.cfg ├── host_vars │ ├── 192.168.56.131 │ ├── node1.yml │ └── time.yml └── playbook //Write host directory file [root@control vars]# cat host_vars/192.168.56.131 ansibel_user: root ansible_password: 1 //View manifest file [root@control vars]# cat playbook [server1] 192.168.56.131 //test [root@control vars]# ansible all -m ping 192.168.56.131 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": false, "ping": "pong" } //Define host variables [root@control vars]# cat host_vars/192.168.56.131 ansibel_user: root ansible_password: 1 IP: 192.168.56.199 NAME: www //implement [root@control vars]# cat host_vars/node1.yml --- - hosts: '192.168.56.131' tasks: - name: test lineinfile: path: /etc/hosts line: "{{ IP }} {{ NAME }}" state: present //View results [root@localhost ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.56.199 www
If the internal and external variables are the same, the internal variable shall prevail
[root@control vars]# cat host_vars/192.168.56.131 ansibel_user: root ansible_password: 1 IP: 192.168.56.110 //Define external variables NAME: QQQ [root@control vars]# cat host_vars/node1.yml --- - hosts: '192.168.56.131' gather_facts: no vars: IP: 192.168.56.188 //Define local variables NAME: LLL tasks: - name: test lineinfile: path: /etc/hosts line: "{{ IP }} {{ NAME }}" state: present //implement [root@control vars]# ansible-playbook host_vars/node1.yml PLAY [192.168.56.131] ********************************************************** TASK [test] ******************************************************************** changed: [192.168.56.131] PLAY RECAP ********************************************************************* 192.168.56.131 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 //View results [root@localhost ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.56.199 www 192.168.56.188 LLL //Only local variables are added
Use array as variable
In addition to allocating the configuration data related to the same element (package list, service list, user list, etc.) to multiple variables, arrays can also be used. One advantage of this approach is that arrays are browsable
Create group:
[root@control vars]# cat host_vars/192.168.56.131 ansibel_user: root ansible_password: 1 info: node2: ip: 5.5.5.5 max: www.aliyun.com node3: ip: 6.6.6.6 min: www.baidu.com [root@control vars]# cat host_vars/node1.yml --- - hosts: '192.168.56.131' gather_facts: no vars: IP: 192.168.56.188 NAME: LLL tasks: - name: test lineinfile: path: /etc/hosts line: "{{ info.node2.ip }} {{ info.node3.min }}" state: present "{{info.node2.ip}} {{info.node3.min}}" //View results [root@localhost ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 5.5.5.5 www.baidu.com
Capture command output using registered variables
You can use the register statement to capture command output. The output is stored in a temporary variable and can then be used in the playbook for debugging purposes or for other purposes, such as specific configurations based on command output.
Standard input: STDIN
Standard output: STDOUT
Standard error: STDERR
The following playbook demonstrates how to capture command output for debugging purposes:
[root@control vars]# cat host_vars/node1.yml --- - hosts: '192.168.56.131' gather_facts: no tasks: - name: test command: "echo hello time" //Output results register: result //Registered name - debug: var=result // [root@control vars]# ansible-playbook host_vars/node1.yml PLAY [192.168.56.131] ********************************************************** TASK [test] ******************************************************************** changed: [192.168.56.131] TASK [debug] ******************************************************************* ok: [192.168.56.131] => { "result": { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "cmd": [ "echo", "hello", "time" ], "delta": "0:00:00.001394", "end": "2021-07-22 23:01:09.288632", "failed": false, "rc": 0, "start": "2021-07-22 23:01:09.287238", "stderr": "", "stderr_lines": [], "stdout": "hello time", "stdout_lines": [ "hello time" //capture ] } } PLAY RECAP ********************************************************************* 192.168.56.131 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
//Capture printout results
[root@control vars]# cat host_vars/node1.yml --- - hosts: '192.168.56.131' gather_facts: no tasks: - name: test command: "echo hello time" register: result - name: create shell: "echo {{ result['stdout'] }} > /opt/abc" //The file / opt/abc must exist on the controlled host [root@control vars]# ansible-playbook host_vars/node1.yml //implement PLAY [192.168.56.131] ********************************************************** TASK [test] ******************************************************************** changed: [192.168.56.131] TASK [create] ****************************************************************** changed: [192.168.56.131] PLAY RECAP ********************************************************************* 192.168.56.131 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 //View results [root@localhost opt]# cat abc hello time
Management Secrets
Ansible may need to access sensitive data such as passwords or API keys in order to be able to configure the managed host. Typically, this information may be stored in plain text in manifest variables or other ansible files. However, if so, any user who has access to ansible files or the version control system storing these ansible files can access this sensitive data. This indicates a security risk.
Ansible Vault provided by ansible can encrypt and decrypt any structured data file used by ansible. To use Ansible Vault, you can create, edit, encrypt, decrypt, and view files through a command-line tool called Ansible Vault. Ansible Vault can encrypt any structured data file used by ansible. This may include manifest variables, variable files contained in the playbook, variable files passed as parameters when the playbook is executed, or variables defined in the ansible role.
To create an encrypted file:
//Create encrypted file [root@control vars]# ansible-vault create took.ymlNew Vault password: Confirm New Vault password: [root@control vars]# ls ansible.cfg host_vars took.yml group_vars playbook //see [root@control group_vars]# ls took.yml //Encrypted file [root@control group_vars]# cat took.yml $ANSIBLE_VAULT;1.1;AES256 35313330376339343338366131383335623366396631663436383238646266383136353062356230 3437373338633230643133666563346463616265326566340a353336633934633939313835333338 36363034306364383236366434306537623635613565336562626235643566323735346166613537 3932623638393866620a396434663538663635373235353634386165623836386434323532653065 3339
View encrypted files
[root@control group_vars]# ansible-vault view took.yml Vault password: //Enter password to view 123 [root@control group_vars]# ls -a . .. .passwd took.yml [root@control group_vars]# cat .passwd / / create a password file 123456 //Create an encrypted file with a password file [root@control vars]# ansible-vault create --vault-password-file=group_vars/.passwd group_vars/pook.yml [root@control vars]# ansible-vault view group_vars/pook.yml //Enter password to view [root@control vars]# ansible-vault view group_vars/pook.yml Vault password: port: 9090 //View encrypted files with password files [root@control vars]# ansible-vault view --vault-password-file=group_vars/.passwd group_vars/pook.yml port: 9090
Encrypt existing files
[root@control vars]# ls ansible.cfg group_vars host_vars playbook [root@control vars]# ansible-vault encrypt --vault-password-file=group_vars/.passwd playbook Encryption successful //Password encrypted playbook file [root@control vars]# cat playbook $ANSIBLE_VAULT;1.1;AES256 35336637323031346432353466306636366137303233356530653339353435663638313932313730 3032346163636538613633326661323836623638626530370a323163303266623265306631653838 35393034386139326234336661626638373166323461653063393435366435363837656231323630 3766386334663761640a353733633136343761383830356636323836663035333463653738343466 64316638623238663932356365346431623530343234313462373431303031366466 //View encrypted files with password [root@control vars]# ansible-vault view --vault-password-file=group_vars/.passwd playbook [server1] 192.168.56.131
Decrypt existing files
[root@control vars]# ansible-vault decrypt --vault-password-file=group_vars/.passwd playbook //playbook encrypted file Decryption successful [root@control vars]# cat playbook [server1] 192.168.56.131
Change password for encrypted file
[root@control group_vars]# ls pook.yml took.yml //Change Password [root@control group_vars]# ansible-vault rekey pook.yml Vault password: New Vault password: Confirm New Vault password: //You must know the password to change the new password //View file with new password [root@control group_vars]# ansible-vault view --vault-password-file=pk pook.yml port: 9090