This article is to show you how easy is to use automation tools for managing your servers. If you are new to ansible this article is right for you!
Installation
First, you must install ansible, which is pretty easy. At present all Linux distributions have the ansible package:
Ubuntu
sudo apt install ansible
CentOS 7
sudo yum install ansible
Fedora
sudo dnf install ansible
Gentoo
emerge -v ansible
Multiple python (version 3) packages will be pulled because the tool is based on python. The following files will appear in your machine (and a lot of python modules under the python directory of your Linux distribution):
/usr/bin/ansible /usr/bin/ansible-config -> ansible /usr/bin/ansible-connection /usr/bin/ansible-console -> ansible /usr/bin/ansible-doc -> ansible /usr/bin/ansible-galaxy -> ansible /usr/bin/ansible-inventory -> ansible /usr/bin/ansible-playbook -> ansible /usr/bin/ansible-pull -> ansible /usr/bin/ansible-vault -> ansible
The important program name is ansible, with which you can do any of the other task.
What you can do using ansible with simple words
At present (July 2019) ansible 2.8.x has around 2080 modules (all modules here https://docs.ansible.com/ansible/latest/modules/list_of_all_modules.html) so you will find a solution for any automation task you may encounter. But here our purpose is to show you several simple commands.
ansible uses ssh to connect remotely to other machines and it is the best option to use ssh keys for passwordless connections
Still, ansible has the option to use also password authentication with “–ask-pass” option. In fact, connecting to the remote host could be done without ssh, but another protocol and this is beyond the scope of this article and it is rarely used.
Ansible modules could be used with different Linux distributions without specifying what kind of packaging software or init system is used.
So when you use module to install a package in your server you may not specify to use apt, yum or any other, or when you want to stop/start/reload/restart a service you do not need to specify it is a systemd or openrc or upstart or sysvinit and so on. The modules gather this information from the currently connected remote host and use the proper command to do its job. Look below in the playbook section.
The inventory file
The first thing to do is your file with servers. In terms of ansible, this is your “inventory file” – the file describing how to connect to your servers like hostname, ports, keys and so on.
The default inventory file is in /etc/ansible/hosts, but you can use file in any location if you include it in the ansible with “-i
So open your favorite text editor and write down your servers (it supports two syntaxes INI and YAML styles):
1) Just enumerate your servers’ hostnames.
Using default port 22 and the user you are logged in. Still, if you use “~/.ssh/config” and you included specific options like port, user, identity file these options will be used by ansible to connect to the hosts.
srv1.example.com srv2.example.com
2) Or you can include options.
Like port, user, private key
srv1 ansible_host=10.10.10.10 ansible_port=10077 ansible_connection=ssh ansible_ssh_user=root ansible_ssh_private_key_file=~/.ssh/example-ident srv2 ansible_host=srv2.example.com ansible_port=10077 ansible_connection=ssh ansible_ssh_user=myuser ansible_ssh_private_key_file=~/.ssh/example-ident
The host name could be different from the ansible_host, which will be used to connect to. Here we change the default behavior – port=10077, use the root user to connect to the remote host with the private key from the current user directory. So if you are logged with let’s say “myuser” you are going to connect to the host with your private key and user root. The configuration in the inventory file overwrites the configuration of your openssh (“~/.ssh/config”).
3) Servers’ groups in the inventory file
[storages] srv1 ansible_host=10.10.10.10 ansible_port=10077 ansible_connection=ssh ansible_ssh_user=root ansible_ssh_private_key_file=~/.ssh/example-ident srv2 ansible_host=srv2.example.com ansible_port=10077 ansible_connection=ssh ansible_ssh_user=myuser ansible_ssh_private_key_file=~/.ssh/example-ident [webservers] srv3 ansible_host=srv1.example.com ansible_port=10077 ansible_connection=ssh ansible_ssh_user=root ansible_ssh_private_key_file=~/.ssh/example-ident [project1:children] storages webservers
We have two groups consisting of server names and a group, which includes the two groups “storages” and “webservers”. You could use the group names in the ansible command to execute commands.
List all hosts in the inventory file
myuser@srv ~ $ ansible -i ./inventory.ini --list-hosts all hosts (3): srv1 srv2 srv3
Check if everything works properly and ansible could connect the hosts (on all remote hosts you must have python installed to use ansible, preferable to be python 3+ verions). Use ping module:
myuser@srv ~ $ ansible all -i ./inventory.ini -m ping srv2 | SUCCESS => { "changed": false, "ping": "pong" } srv3 | SUCCESS => { "changed": false, "ping": "pong" } srv1 | SUCCESS => { "changed": false, "ping": "pong" }
4) Local execution
In some cases you may want to execute local tasks (i.e. commands) so here is what to include in the inventory file:
localhost ansible_connection=local
When you execute multiple tasks (i.e. commands) in a playbook (i.e. a file with multiple commands) you may want to use ansible locally in a first boot after installation.
More on the subject of inventory file here https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html
Connecting to the remote servers and executing simple command(s)
Here we load the inventory file and use module shell to execute a command on the remote server srv1:
myuser@srv ~ $ ansible srv1 -i ./inventory.ini -m shell -a 'uname -a' srv1 | CHANGED | rc=0 >> Linux srv1.example.com 3.10.0-862.3.2.el7.x86_64 #1 SMP Mon May 21 23:36:36 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
Again, if you use /etc/ansible/hosts you could skip “-i
Simple multiple server connect (inventory file) and hosts’ groups
“all” is the host pattern for all servers in the inventory file (or you can use host names from the inventory file like “srv1” in our example above)
myuser@srv ~ $ ansible webservers -i ./inventory.ini -m shell -a 'uname -a' srv3 | CHANGED | rc=0 >> Linux srv3.example.com 4.18.12 #2 SMP Tue Oct 9 20:48:52 UTC 2018 x86_64 Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz GenuineIntel GNU/Linux
Execute “whoami” to all hosts:
myuser@srv ~ $ ansible all -i ./inventory.ini -m shell -a 'whoami' srv1 | CHANGED | rc=0 >> root srv2 | CHANGED | rc=0 >> myuser srv3 | CHANGED | rc=0 >> root
As you can see we user “myuser” to log in in srv2 and the root for srv1 and srv3. srv1 uses sudo to escalate privileges to root for better security.
Executing commands using sudo to escalate to root
In your remote servers change “/etc/sudoers” to have a like like:
%wheel ALL=(ALL) NOPASSWD: ALL
and comment the line if it exits:
#%wheel ALL=(ALL) ALL
Then add the group to the user, with which you are going to connect to the remote server with:
usermod -a -G wheel myuser
And here we can use sudo (or various ansible ways to become another/root user):
myuser@srv ~ $ ansible all -i ./inventory.ini -m shell -a 'sudo whoami' [WARNING]: Consider using 'become', 'become_method', and 'become_user' rather than running sudo srv1 | CHANGED | rc=0 >> root srv2 | CHANGED | rc=0 >> root srv3 | CHANGED | rc=0 >> root
Of course, we suppose your distribution uses wheel group (most modern distributions have wheel group for administrative tasks by users). If you do not have it just replace it with the group name of the user you are going to connect to the server and replace “wheel” with the group name (or you can use the username for this purpose, too).
Copy a local file to all remote servers in /root directory using ansible module “copy”. Note we use “-b” to become the requested user if needed (as you may recall our connection to the “srv2” is using “myuser”):
myuser@srv ~ $ ansible all -i ./inventory.ini -m copy -a 'src=copy-test-file.txt dest=/root/ owner=root group=root mode=0644' -b srv1 | CHANGED => { "changed": true, "checksum": "12039d6dd9a7e27622301e935b6eefc78846802e", "dest": "/root/copy-test-file.txt", "gid": 0, "group": "root", "md5sum": "7c12772809c1c0c3deda6103b10fdfa0", "mode": "0644", "owner": "root", "secontext": "system_u:object_r:admin_home_t:s0", "size": 11, "src": "/root/.ansible/tmp/ansible-tmp-1564998029.2082274-174670050907050/source", "state": "file", "uid": 0 } srv2 | CHANGED => { "changed": true, "checksum": "12039d6dd9a7e27622301e935b6eefc78846802e", "dest": "/root/copy-test-file.txt", "gid": 0, "group": "root", "md5sum": "7c12772809c1c0c3deda6103b10fdfa0", "mode": "0644", "owner": "root", "secontext": "system_u:object_r:admin_home_t:s0", "size": 11, "src": "/home/myuser/.ansible/tmp/ansible-tmp-1564998029.1584368-84263920779880/source", "state": "file", "uid": 0 } srv3 | CHANGED => { "changed": true, "checksum": "12039d6dd9a7e27622301e935b6eefc78846802e", "dest": "/root/copy-test-file.txt", "gid": 0, "group": "root", "md5sum": "7c12772809c1c0c3deda6103b10fdfa0", "mode": "0644", "owner": "root", "size": 11, "src": "/root/.ansible/tmp/ansible-tmp-1564998029.199494-96448253016479/source", "state": "file", "uid": 0 }
Ansible playbook and multiple commands (tasks)
In the last example above, when copying file from local using copy ansible module, you may want to have multiple commands before and/or after the copying and it is a way more convinient to describe the commands in a file and then just execute a simple command line. Let’s say you want to copy the new configuration files to your webserver and then reload the web server – no need to write long command lines (and then probably save them to some place) you can use
playbook files, which are with the simple words a list(s) of commands (ansible uses “tasks”, because it may have not been commands to execute)!
Ansible playbook consists of tasks to manage configurations and software deployment. The playbook uses YAML format to describe the tasks.
Here is a simple task to reload the nginx web server. Put the following in a text file
--- - hosts: all tasks: - name: Reload nginx service: name=nginx state=reloaded become: yes
Note: do not use tabs for spacing.
And then execute the playbook with:
myuser@srv ~ $ ansible-playbook -l srv2 -i ./inventory.ini ./playbook-example.yml PLAY [all] ***************************************************************************************************************************************************************** TASK [Gathering Facts] ***************************************************************************************************************************************************** ok: [srv2] TASK [Reload nginx] ******************************************************************************************************************************************************** changed: [srv2] PLAY RECAP ***************************************************************************************************************************************************************** srv2 : ok=2 changed=1 unreachable=0 failed=0
And our nginx was reloaded successfully. This playbook uses “all” for hosts, but in the command line we specify only host “srv2” with the “-l” option.
Including the option “-v” can show you some debug information:
myuser@supermyuser ~ $ ansible-playbook -v -l srv2 -i ./inventory.ini ./playbook-example.yml -b No config file found; using defaults /home/myuser/inventory.ini did not meet host_list requirements, check plugin documentation if this is unexpected /home/myuser/inventory.ini did not meet script requirements, check plugin documentation if this is unexpected /home/myuser/inventory.ini did not meet yaml requirements, check plugin documentation if this is unexpected PLAY [all] ***************************************************************************************************************************************************************** TASK [Gathering Facts] ***************************************************************************************************************************************************** ok: [srv2] TASK [Reload nginx] ******************************************************************************************************************************************************** changed: [srv2] => {"changed": true, "name": "nginx", "state": "started", "status": {"ActiveEnterTimestamp": "Mon 2019-02-25 13:53:46 UTC", "ActiveEnterTimestampMonotonic": "5869633632962", "ActiveExitTimestamp": "Mon 2019-02-25 13:53:45 UTC", "ActiveExitTimestampMonotonic": "5869632613882", "ActiveState": "active", "After": "systemd-journald.socket network-online.target remote-fs.target nss-lookup.target basic.target system.slice", "AllowIsolate": "no", "AmbientCapabilities": "0", "AssertResult": "yes", "AssertTimestamp": "Mon 2019-02-25 13:53:45 UTC", "AssertTimestampMonotonic": "5869633381024", "Before": "multi-user.target shutdown.target", "BlockIOAccounting": "no", "BlockIOWeight": "18446744073709551615", "CPUAccounting": "no", "CPUQuotaPerSecUSec": "infinity", "CPUSchedulingPolicy": "0", "CPUSchedulingPriority": "0", "CPUSchedulingResetOnFork": "no", "CPUShares": "18446744073709551615", "CanIsolate": "no", "CanReload": "yes", "CanStart": "yes", "CanStop": "yes", "CapabilityBoundingSet": "18446744073709551615", "ConditionResult": "yes", "ConditionTimestamp": "Mon 2019-02-25 13:53:45 UTC", "ConditionTimestampMonotonic": "5869633381024", "Conflicts": "shutdown.target", "ControlGroup": "/system.slice/nginx.service", "ControlPID": "0", "DefaultDependencies": "yes", "Delegate": "no", "Description": "nginx - high performance web server", "DevicePolicy": "auto", "Documentation": "http://nginx.org/en/docs/", "ExecMainCode": "0", "ExecMainExitTimestampMonotonic": "0", "ExecMainPID": "31012", "ExecMainStartTimestamp": "Mon 2019-02-25 13:53:46 UTC", "ExecMainStartTimestampMonotonic": "5869633632910", "ExecMainStatus": "0", "ExecReload": "{ path=/bin/kill ; argv[]=/bin/kill -s HUP $MAINPID ; ignore_errors=no ; start_time=[Mon 2019-08-05 10:34:48 UTC] ; stop_time=[Mon 2019-08-05 10:34:48 UTC] ; pid=7688 ; code=exited ; status=0 }", "ExecStart": "{ path=/usr/sbin/nginx ; argv[]=/usr/sbin/nginx -c /etc/nginx/nginx.conf ; ignore_errors=no ; start_time=[Mon 2019-02-25 13:53:45 UTC] ; stop_time=[Mon 2019-02-25 13:53:46 UTC] ; pid=31007 ; code=exited ; status=0 }", "ExecStop": "{ path=/bin/kill ; argv[]=/bin/kill -s TERM $MAINPID ; ignore_errors=no ; start_time=[Mon 2019-02-25 13:53:45 UTC] ; stop_time=[Mon 2019-02-25 13:53:45 UTC] ; pid=30989 ; code=exited ; status=0 }", "FailureAction": "none", "FileDescriptorStoreMax": "0", "FragmentPath": "/usr/lib/systemd/system/nginx.service", "GuessMainPID": "yes", "IOScheduling": "0", "Id": "nginx.service", "IgnoreOnIsolate": "no", "IgnoreOnSnapshot": "no", "IgnoreSIGPIPE": "yes", "InactiveEnterTimestamp": "Mon 2019-02-25 13:53:45 UTC", "InactiveEnterTimestampMonotonic": "5869632664810", "InactiveExitTimestamp": "Mon 2019-02-25 13:53:45 UTC", "InactiveExitTimestampMonotonic": "5869633386655", "JobTimeoutAction": "none", "JobTimeoutUSec": "0", "KillMode": "control-group", "KillSignal": "15", "LimitAS": "18446744073709551615", "LimitCORE": "18446744073709551615", "LimitCPU": "18446744073709551615", "LimitDATA": "18446744073709551615", "LimitFSIZE": "18446744073709551615", "LimitLOCKS": "18446744073709551615", "LimitMEMLOCK": "65536", "LimitMSGQUEUE": "819200", "LimitNICE": "0", "LimitNOFILE": "4096", "LimitNPROC": "126979", "LimitRSS": "18446744073709551615", "LimitRTPRIO": "0", "LimitRTTIME": "18446744073709551615", "LimitSIGPENDING": "126979", "LimitSTACK": "18446744073709551615", "LoadState": "loaded", "MainPID": "31012", "MemoryAccounting": "no", "MemoryCurrent": "7798784000", "MemoryLimit": "18446744073709551615", "MountFlags": "0", "Names": "nginx.service", "NeedDaemonReload": "no", "Nice": "0", "NoNewPrivileges": "no", "NonBlocking": "no", "NotifyAccess": "none", "OOMScoreAdjust": "0", "OnFailureJobMode": "replace", "PIDFile": "/var/run/nginx.pid", "PermissionsStartOnly": "no", "PrivateDevices": "no", "PrivateNetwork": "no", "PrivateTmp": "no", "ProtectHome": "no", "ProtectSystem": "no", "RefuseManualStart": "no", "RefuseManualStop": "no", "RemainAfterExit": "no", "Requires": "basic.target", "Restart": "no", "RestartUSec": "100ms", "Result": "success", "RootDirectoryStartOnly": "no", "RuntimeDirectoryMode": "0755", "SameProcessGroup": "no", "SecureBits": "0", "SendSIGHUP": "no", "SendSIGKILL": "yes", "Slice": "system.slice", "StandardError": "inherit", "StandardInput": "null", "StandardOutput": "journal", "StartLimitAction": "none", "StartLimitBurst": "5", "StartLimitInterval": "10000000", "StartupBlockIOWeight": "18446744073709551615", "StartupCPUShares": "18446744073709551615", "StatusErrno": "0", "StopWhenUnneeded": "no", "SubState": "running", "SyslogLevelPrefix": "yes", "SyslogPriority": "30", "SystemCallErrorNumber": "0", "TTYReset": "no", "TTYVHangup": "no", "TTYVTDisallocate": "no", "TasksAccounting": "no", "TasksCurrent": "8", "TasksMax": "18446744073709551615", "TimeoutStartUSec": "1min 30s", "TimeoutStopUSec": "1min 30s", "TimerSlackNSec": "50000", "Transient": "no", "Type": "forking", "UMask": "0022", "UnitFilePreset": "disabled", "UnitFileState": "enabled", "WantedBy": "multi-user.target", "Wants": "network-online.target system.slice", "WatchdogTimestamp": "Mon 2019-02-25 13:53:46 UTC", "WatchdogTimestampMonotonic": "5869633632935", "WatchdogUSec": "0"}} PLAY RECAP ***************************************************************************************************************************************************************** srv2 : ok=2 changed=1 unreachable=0 failed=0
The verbose output level could be raised by adding more “v”s like “-vvv”.
Here we are using the service ansible module you can check more here – https://docs.ansible.com/ansible/latest/modules/service_module.html
The playbook could include multiple tasks like the following:
--- - hosts: all tasks: - name: copy ssl certificates to nginx folder copy: src=/home/myuser/projects/web-example/ALL.example.com.crt dest=/etc/ssl/nginx/ALL.example.com.crt owner=root group=root mode=400 backup=yes tags: certificates - name: copy script file to storage folder copy: src=/home/myuser/projects/web-example/scripts/parse.php dest=/var/www/parse.php owner=root group=root mode=755 backup=no tags: script_logs - name: copy referer_blacklist to all servers copy: src=/home/myuser/projects/web-example/configs/referer_blacklist.conf dest=/etc/nginx/conf.d/referer_blacklist.conf owner=root group=root mode=644 backup=no tags: referer_blacklist - name: enable-cors copy: src=/home/myuser/projects/web-example/configs/enable-cors.conf dest=/etc/nginx/conf.d/enable-cors.conf owner=root group=root mode=644 backup=no tags: enable-cors
Multiple commands to copy configuration files. You can execute all of them with:
myuser@srv ~ $ ansible-playbook -l srv3 -i ./inventory.ini ./playbook-example-2.yml PLAY [all] ***************************************************************************************************************************************************************** TASK [Gathering Facts] ***************************************************************************************************************************************************** ok: [srv3] TASK [copy ssl certificates to nginx folder] ******************************************************************************************************************************* changed: [srv3] TASK [copy script file to storage folder] ********************************************************************************************************************************** changed: [srv3] TASK [copy referer_blacklist to all servers] ******************************************************************************************************************************* changed: [srv3] TASK [enable-cors] ********************************************************************************************************************************************************* changed: [srv3] PLAY RECAP ***************************************************************************************************************************************************************** srv3 : ok=5 changed=4 unreachable=0 failed=0
As you can see we included in every task the keyword “tags”, “tags” means you can mark the task with a name and execute it (or them if you include a specific tag in multiple tasks). This can be done with:
ansible-playbook --tags certificates -l all -i ./inventory.ini ./playbook-example-2.yml
More on ansible playbook here – https://docs.ansible.com/ansible/latest/user_guide/playbooks.html
Protecting sensitive information with encryption – the Ansible Vault
You can protect basically every part of your ansible project – files, parts of a playbook, variables and so on. The password could be entered in the command line when executing the playbook or read from a file.
Here are some examples:
1) Create a new encrypted file with sensitive information
You can use this method to create and encrypt a file with variables, for example:
myuser@srv ~ $ ansible-vault create protected.yml New Vault password: Confirm New Vault password:
And it will open your default editor (taken from the EDITOR environment). In our case, it was nano and then write your variables like:
--- certname1: "ALL.example.com" pass1: "ainaikai%sheuze9quiebu+xau4ooK" pass2: "toh9ti3wai&maem5yen9Ung8ip0Fie" pass3: "Eid0AiY~ae6ais8aecei7oow#u8Ke7"
Here is the encrypted file:
$ANSIBLE_VAULT;1.1;AES256 37316234623436343266653364616339316237323634336633356362376238616136353361393337 3437363630316666626333326464656664396136633334300a333238633932366162656332376534 36326132643063303964316561646162626235386362353361396533353434613539626235623738 3635363834663266390a666566656365306635316536366666396233323966386132306134326562 39316235376362666536653135613231336330653832353438353138636462356232626130303237 30626531366138626531663363633035323138623633613236303363303533343062353334626336 64396262323164663266666232383230323966336262663464313064383039336462623462383062 64353239393430303430383838306564343030373962316631646666653761333765656437363634 30353362303332353539613830383738663532613835386533613766323564363234
Then in your playbook you can just include the file with:
--- - hosts: all vars_files: - 'protected.yml' tasks: - name: copy ssl certificates to nginx folder copy: src=/home/myuser/projects/web-example/{{ certname1 }}.crt dest=/etc/ssl/nginx/{{ certname1 }}.crt owner=root group=root mode=400 backup=yes tags: certificates - name: copy the password file of the certificate copy: content="{{ pass1 }}" dest=/etc/ssl/nginx/{{ certname1 }}.psw owner=root group=root mode=400 backup=yes tags: certificates - debug: msg: Cert - {{ certname1 }} tags: mydebug
So all variables in protected.yml can be used in your ansible playbook as ordinary variables. In the example above we use simple variables stored in a protected vault file for the name and the password of our certificate “ALL.example.com”. The playbook will copy the certificate and will create a file with the certificate’s password (with the proper permissions “root:root” and 400) to be used in nginx web server. You can also use templates with the vault variables to replace the certificate name and password, but this is beyond the scope of this article.
myuser@srv ~ $ ansible-playbook --ask-vault-pass -l srv3 -i ./inventory.ini ./playbook-example-2.yml Vault password: PLAY [all] ***************************************************************************************************************************************************************** TASK [Gathering Facts] ***************************************************************************************************************************************************** ok: [srv3] TASK [copy ssl certificates to nginx folder] ******************************************************************************************************************************* ok: [srv3] TASK [copy the password file of the certificate] *************************************************************************************************************************** changed: [srv3] TASK [debug] *************************************************************************************************************************************************************** ok: [srv3] => { "msg": "Cert - ALL.example.com" } PLAY RECAP ***************************************************************************************************************************************************************** srv3 : ok=4 changed=1 unreachable=0 failed=0
2) You can create an encrypted variable in the ansible playbook file
First, encrypt the variable with”
myuser@srv ~ $ ansible-vault encrypt_string 'SoC6ahGheech@aengei3' --name 'the_pass_3' New Vault password: Confirm New Vault password: the_pass_3: !vault | $ANSIBLE_VAULT;1.1;AES256 61663935383430323364373037386234346236323637343030303835373466663733613262636664 3833303636376266373338643135323236643230353232660a363238636539343831343433393462 39666163386664643835646562636433373531666430373335316661643537303737616435643961 6430353039636364340a383361653133643732366430303262373665643633646336383939326362 38343338396630343036393430643263646534363266323737343265336664323963 Encryption successful
Include the variable in your ansible playbook and use it:
--- - hosts: all vars_files: - 'protected.yml' vars: the_pass_3: !vault | $ANSIBLE_VAULT;1.1;AES256 61663935383430323364373037386234346236323637343030303835373466663733613262636664 3833303636376266373338643135323236643230353232660a363238636539343831343433393462 39666163386664643835646562636433373531666430373335316661643537303737616435643961 6430353039636364340a383361653133643732366430303262373665643633646336383939326362 38343338396630343036393430643263646534363266323737343265336664323963 tasks: - name: copy ssl certificates to nginx folder copy: src=/home/myuser/projects/web-example/{{ certname1 }}.crt dest=/etc/ssl/nginx/{{ certname1 }}.crt owner=root group=root mode=400 backup=yes tags: certificates - name: copy the password file of the certificate copy: content="{{ pass1 }}" dest=/etc/ssl/nginx/{{ certname1 }}.psw owner=root group=root mode=400 backup=yes tags: certificates - debug: msg: Cert - {{ certname1 }} and the variable the_pass_3 - {{ the_pass_3 }} tags: mydebug
And executing with the output result:
myuser@srv ~ $ ansible-playbook --ask-vault-pass --tags certificates,mydebug -l srv3 -i ./inventory.ini ./playbook-example-2.yml Vault password: PLAY [all] ***************************************************************************************************************************************************************** TASK [Gathering Facts] ***************************************************************************************************************************************************** ok: [srv3] TASK [copy ssl certificates to nginx folder] ******************************************************************************************************************************* ok: [srv3] TASK [copy the password file of the certificate] *************************************************************************************************************************** ok: [srv3] TASK [debug] *************************************************************************************************************************************************************** ok: [srv3] => { "msg": "Cert - ALL.example.com and the variable the_pass_3 - SoC6ahGheech@aengei3" } PLAY RECAP ***************************************************************************************************************************************************************** srv3 : ok=4 changed=0 unreachable=0 failed=0
3) You can also encrypt a whole file with the ansible vault
Protect your private key in the file “private.key” with a password:
myuser@srv ~ $ ansible-vault encrypt private.key New Vault password: Confirm New Vault password: Encryption successful myuser@srv ~ $ cat private.key $ANSIBLE_VAULT;1.1;AES256 31306239393333363166326436323864333365353938313234666434656562386662643234623736 3833653739373433643438633933303137313432363561630a653666623265386166363634613937 30333765643336343264666662313266636236643064656635663466336138323330396530373036 3434636336396235330a353035306161313764343637353633363761326134363065643364323131 35396463656266343163643132616431613062333336633262343835313266316435
4) View an encrypted file
You can view an ansible encrypted file with the view command:
myuser@srv ~ $ ansible-vault view protected.yml Vault password: --- certname1: "ALL.mytv.bg" pass1: "toh9ti3wai&maem5yen9Ung8ip0Fie" pass2: "Eid0AiY~ae6ais8aecei7oow#u8Ke7"
All encrypted content (no matter, a whole file or an encrypted variable within an ordinary YAML playbook file) has the same header “$ANSIBLE_VAULT” so it easy to search for the occurrence of it if you need to change all your protected content on a compromised password!
More on ansible vault subject here – https://docs.ansible.com/ansible/latest/user_guide/vault.html
Simple debug
In the last example with the vault ansible playbook we included a debug task to print a variable:
- debug: msg: Cert - {{ certname1 }}
And here is what you can expect:
TASK [debug] *************************************************************************************************************************************************************** ok: [srv3] => { "msg": "Cert - ALL.example.com" }