I have a playbook which calls a script file. It is going to pass a secret to the script file.
What I would like is for the secret not to be shown in standard out.
According to the ansible documentation, no_log: true can be used however this will not work when used in a ANSIBLE_DEBUG env variable is set true.
What I am also finding is that in the task "Set Execution File and parameters", the variables are being displayed even with no_log: true.
---
- block:
- name: Set Execution File and parameters
set_fact:
scriptfile: "{{ansible_user_dir}}\\scripts\\host_check.ps1"
params: " -servername '{{the_host_name}}' -secret {{my_secret}}"
- name: Execute script
win_command: powershell.exe "{{scriptfile}}" "{{params}}"
no_log: True
rescue:
- debug:
msg: "Play failed"
I would like to replace the my_secret variable with *******
Actually no_log: true is all you can do. Ansible will need to know your secret to use it and anybody who can set ANSIBLE_DEBUG can also just edit your playbook to display the secret. So as much as you hide it, it can always be revealed.
You have, however, the possibility to encrypt the secret using ansible-vault and pass the password to ansible, so nobody except you (or has the password) can use (and my this display) the secret.
This is how you encrypt a value (<secret-value> in this case):
ansible-vault encrypt_string --ask-vault-pass '<secret-value>' --name 'secret'
You will be asked for a password (I used test here) and then will get something that looks like this:
secret: !vault |
$ANSIBLE_VAULT;1.1;AES256
36323534396462626132653332653266393832306337336164373834626330373132363136633865
6161623130363364643138633236306334313833663535380a666261383838313631396264626534
66373637653937616231353361633635353238333630303563343630333161626137396332616263
3966356531613234370a633331333862616164386130663262613430316630373230373833313330
6265
You place that in your inventory like this (just an example what it should look like, you need to put in your hosts and other variables):
---
all:
hosts:
your-host:
vars:
secret: !vault |
$ANSIBLE_VAULT;1.1;AES256
36323534396462626132653332653266393832306337336164373834626330373132363136633865
6161623130363364643138633236306334313833663535380a666261383838313631396264626534
66373637653937616231353361633635353238333630303563343630333161626137396332616263
3966356531613234370a633331333862616164386130663262613430316630373230373833313330
6265
the_host_name: host.name
ansible_user_dir: 'C:\\some\\dir'
Then you can do this in your playbook:
---
- block:
- name: Execute script
win_command: 'powershell.exe "{{ ansible_user_dir }}\\scripts\\host_check.ps1" -servername "{{ the_host_name }}" -secret "{{ my_secret }}"'
no_log: true
rescue:
- debug:
msg: "Play failed"
You need to run it with --ask-vault-pass like this:
ansible-playbook -i your-inventory.yml your-playbook.yml --ask-vault-pass
It will ask you for the password every time you run it, so make sure to keep it somewhere.
If you are using multiple encrypted values in one run, you need to use the same password to encrypt all of them.
Related
I have a playbook that runs correctly when used with ansible-playbook.
It contains an encrypted variable. According to the manual https://docs.ansible.com/ansible/latest/user_guide/vault.html#id16, I can view the variable with
$ ansible localhost -m ansible.builtin.debug -a var="ansible_value" -e
"'debug_playbook.yml" --vault-password-file=./pw_file
But I get an error of
ERROR! failed at splitting arguments, either an unbalanced jinja2 block or quotes: 'debug_playbook.yml
As the playbook itself runs, presumably its syntax is correct.
The playbook is
- name: Run a series of debug tasks to see the value of variables
hosts: localhost
vars:
ansible_password: vault |
$ANSIBLE_VAULT;1.1;AES256
63343064633966653833383264346638303466663265363566643062623436383364376639636630
3032653839323831316361613138333999999999999999999a313439383536353737616334326636
63616162323230333635663364643935383330623637633239626632626539656434333434316631
3965373931643338370a393530323165393762656264306130386561376362353863303232346462
3039
user: myuser
tasks:
- name: show env variable HOME and LOGNAME
debug:
msg: "environment variable {{ item }}"
with_items:
- "{{ lookup('env','HOME') }}"
- "{{ lookup('env','LOGNAME') }}"
- name: now show all of the variables for the current managed machine
debug:
msg: "{{ hostvars[inventory_hostname] }}"
- name: now show all of the hosts in the group from inventory file
debug:
msg: "server {{ item }}"
with_items:
- "{{ groups.mintServers }}"
- "{{ groups.centosServers }}"
I have googled the error and nothing jumps out (to me anyway). Is the manual correct? I have seen other methods where the encrypted variable is echoed into ansible-vault decrypt but it is all a bit of a bother.
I have yamllint'd the playbook. So interested to know what the error means and a way of debugging.
Regards
Following my comments: you cannot view an encrypted var inside a playbook with the technique proposed in the documentation, for memory:
ansible localhost -m debug -a "var=your_var" \
-e #your_file.yml --ask-vault-password
This will only work if your file is a "simple" var file where the top level element is a dictionary.
What I have done in the past is use the yq command line tool (which is a wrapper above jq) that you can easily install with pip install yq. (Note that jq needs to be installed separately and is available in most linux distribution channels. On ubuntu: apt install jq).
Once the prerequisites are available you can use yq to extract the var from you playbook and decrypt it with ansible-vault directly.
For this to work, you will still need to fix your var value which is not a valid vault definition as it misses a question mark in front of the vault marker:
vars:
ansible_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
63343064633966653833383264346638303466663265363566643062623436383364376639636630
3032653839323831316361613138333999999999999999999a313439383536353737616334326636
63616162323230333635663364643935383330623637633239626632626539656434333434316631
3965373931643338370a393530323165393762656264306130386561376362353863303232346462
3039
The solution is not so trivial as yq will get the vault value adding some garbage white-space and new line at the end that will make ansible-vault literally freak out. With your above fixed playbook example, this would give:
yq -r '.[0].vars.ansible_password|rtrimstr(" \n")' your_playbook.yaml \
| ansible-vault decrypt --ask-vault-pass
I am running this playbook:
---
- name: New user is created
hosts: machine2
become: true
vars:
username: test
tasks:
- name: User gets created
user:
name: " {{ username }}"
state: present
However, I get the following error:
Review the line where you use the variable username. So far there's a blank space. It should be:
name: "{{username}}".
You can see in the second image that it is complaining because it tries to create the user ' test' (with a blank space at the beginning). Anyway, for debugging purposes it might become handy to use the -v flat when launching the playbook. You can use:
ansible-playbook example.yml -v
ansible-playbook example.yml -vv
ansible-playbook example.yml -vvv
ansible-playbook example.yml -vvvv
Each v will increase the verbosity level.
The issue
The problem is than you have an extra space before you variable
name: " {{ username }}"
It should be:
name: "{{ username }}"
Explanation for beginner
It's actually some jinja2 templating. You have set the variable username with "test" as content. So if in " {{ username }}" you replace {{ username }} by test you ends up with " test". Note the space before the first curly bracket remains and comes before "test". And the system does not accept to create a user with a usernamer starting with a space.
I need to determine if someone as used --ask-vault-pass option while executing their playbook or not. If they have not issued the ansible-playbook command with --ask-vault-pass, fail it.
Pass if someone run like:
ansible-playbook -i myinv.ini test.yml --ask-vault-pass
Fail if someone run like:
ansible-playbook -i myinv.ini test.yml
Note that, this is not extra-vars which I could validate.
The following is not detecting the --ask-vaul-pass option but will still achieve your requirement. Note anyway that detecting this option in itself is not sufficient for your need since you can provide the vault password in different ways (--vault-passwork-file option, environment variables...)
Basically, I'm testing one of the vars that I know is encoded and failing the playbook nicely if we cannot decode. I targeted localhost for the purpose of the test but you can target any group. This is why I used run_once on the test task to make sure we only test once for all hosts in the play. I also used no_log to make sure we don't leak any sensitive data on screen.
- hosts: localhost
gather_facts: false
vars:
test_var: !vault |
$ANSIBLE_VAULT;1.1;AES256
<encrypted data goes here>
pre_tasks:
- block:
- name: verify we can decode vault
debug:
var: test_var
no_log: true
run_once: true
rescue:
- name: fail playbook if decode failed
fail:
msg: You did not provide a vault pass or it is not recognized
tasks:
- name: a task
debug:
msg: I'll be played if pre_tasks are ok
Would this make the trick in your situation ?
I trying to create a simple paybook with a common role. Unfortunately I get stymied by ansible. I have looked up and down the internet for solution for this error.
The setup:
I am running ansible 2.7.4 on Ubuntu 18.04
directory structure:
~/Ansible_Do
playbook.yml
inventory (hosts file)
/roles
/common
/defaults
main.yml (other variables)
/tasks
main.yml
richard_e.yml
/vars
vars_and_stuff.yml (vault)
I have a simple playbook.yml
---
# My playbook 1
- hosts: test
- name: Go to common role to run tasks.
roles:
- common
tasks:
- name: echo something
shell: echo $(ip addr | grep inet)
...
I run this command to start the playbook:
~/Ansible_Do$ ansible-playbook -vv --vault-id #prompt -i ~/Ansible_Do/inventory playbook.yml
I enter the vault password continuing the playbook.
The playbook starts pulls facts from the test group of servers. Then reads the role and works to /roles/common. That calls the /common/tasks/main.yml file. This is where the error happens.
The error appears to have been in '/home/~/Ansible_Do/roles/common/tasks/main.yml': line 8, column 3
# Common/tasks file
---
- name: Bring variable from vault
include_vars:
file: vars_and_stuff.yml
name: My_password
- name: Super Richard <====== Error
become: yes
vars:
ansible_become_pass: "{{ My_password }}"
- import_tasks: ./roles/common/tasks/ricahrd_e.yml
...
The ./roles/common/tasks/ricahrd_e.yml is a simple testing task.
---
- name: say hi
debug:
msg: "Active server."
...
The error on "- name". I have checked online and in the Ansible docs to see if there is a key I'm missing. I found an example for include_vars in a /role/tasks (https://gist.github.com/halberom/ef3ea6d6764e929923b0888740e05211) showing proper syntax (I presume) in a simple role. The code works as parts, but not together.
I have reached what I can understand. I feel that is error is utterly simple and I am missing something (forest for the trees).
The error means exactly what it says, except the "module name" is not misspelled in your case, but missing altogether.
This...
- name: Super Richard <====== Error
become: yes
vars:
ansible_become_pass: "{{ My_password }}"
... is not a valid task definition, it does not declare an action.
An action in Ansible is a call to a module, hence "misspelled module name".
The error comes after name, because that's where Ansible expects the name of the "module" that you want to call, e.g. shell in your first example.
You are probably assuming that become is a "module", but it is not.
It is a "playbook keyword", in this case applied on the task level, which has the effect that you become another user for this task only.
But as the task has no action, you get this error.
See docs:
Playbook keywords
Understanding privilege escalation
After a bit of work I got the playbook to work. Knowing that 'become' is not a task was the start. I also found out how to pull the proper vars from the vault.
# My first playbook 1
- hosts: test
become: yes
vars_files:
- ./roles/common/vars/vars_and_stuff.yml
vars:
ansible_become_pass: "{{ My_password }}"
roles:
- common
tasks:
- name: echo something
shell: echo $(ip addr | grep inet)
The vars file access the vault and then vars: pulls the password used by become. With become in force I ran the other tasks in the common role with a last standalone task. Lastly, don't try to - name: at the top level of the playbook as it trigger a hosts undefined error.
I have a job in Rundeck, which require users to pass in database password to ansible. And ansible will take it as an extra variable.
ansible-playbook test.yml -e "password=123"
However, we would like to vault the password during the runtime, but from ansible's best practice. They would require the password to be stored in a file.
and vault the entire file using ansible-vault create.
Since we have a large number of the password to pass in, and I notice there is a function call encrypt_string. I try to call it in a playbook and try to generate a vault password on the fly, but I'm getting error below:
"ERROR! Only one --vault-id can be used for encryption. This includes
passwords from configuration and cli."
Here is my playbook test.yml:
---
- name: test
hosts: localhost
tasks:
- name: vault var
command: ansible-vault encrypt_string "{{ password }}" --vault-password-file ~/.vault_pass.txt
register: var
- name: variable
set_fact:
mypass: var
- name: test encrypt_string
debug:
msg: "{{ mypass }}"
I'm not sure if this is the correct way to do it/best practice, anyone can shed some light will be very appreciated.
Thanks,
You may update your task by removing option --vault-password-file as ansible seems getting/reading it from your environment some way.
...
...
- name: test
hosts: localhost
tasks:
- name: vault var
command: ansible-vault encrypt_string "{{ password }}"
register: var
...
...
If you prefer to keep this option in playbook, you may need to find where ansible is reading it from. Ansible may be reading it from it's default config file, generally found at ~/.ansible.cfg [look for vault_password_file] or alias or somewhere else.
You may find more details at ansible vault documentation with examples.