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.
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 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.
In order to connect to a windows host I will need to pass the credentials in an inventory file. Here's my inventory file:
[windows]
100.100.100.100
[windows:vars]
ansible_user=Adminuser
ansible_password="Mypassword"
ansible_port=5986
ansible_connection=winrm
ansible_winrm_server_cert_validation=ignore
Ansible documentation says that the credentials should be encrypted with ansible-vault. Can I use a variable file that's been encrypted using ansible-vault in my inventory file? And if so, how do I pass my ansible-vault credentials to my inventory file? I will also be using credentials in my playbook like this:
- hosts: windows
gather_facts: no
vars_files:
- vars.yml
tasks:
- win_domain_membership:
dns_domain_name: my.domain.com
hostname: ansible-host
domain_admin_user: {{ admin_user }}
domain_admin_password: {{ passwd }}
domain_ou_path: "OU=Windows,OU=Servers,DC=ansible,DC=com"
state: domain
register: domain_state
I will then use ansible-vault to encrypt my variable file for this playbook.
---
admin_user:myusername#my.domain.com
passwd:mypassword
And then pass my ansible-vault credentials to my playbook at the command line:
$ ansible-playbook myplaybook.yml --ask-vault-pass
Is it possible to store both the variable file used in my inventory and the variable file used in my playbook in the same ansible-vault? That way I can pass the ansible-vault credentials for both files at the command line?
The ansible-vault command encrypts a single file. Ansible decrypts this at runtime and interprets it the same way it would if the file had been unencrypted (so you can't "store both the variable file used in my inventory and the variable file used in my playbook in the same ansible-vault" because those are two different files).
I would just remove the variable from your inventory, leaving it like this:
[windows]
100.100.100.100
And then create group_vars/windows.yml as a vaulted file with the following content (ansible-vault create groups_vars/windows.yml):
ansible_user: Adminuser
ansible_password: "Mypassword"
ansible_port: 5986
ansible_connection: winrm
ansible_winrm_server_cert_validation: ignore
Ansible will automatically apply the variables in group_vars/windows.yml when you have a play that targets the windows group.
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 deployment project that I share with other teams. I have encrypted my secrets with vault.
I would like to encrypt the production file with a password and a staging file with an other password to avoid other teams having access to production secrets.
Is it possible to do that ?
I have done something like that. My secrets :
cat /group_vars/all/vault_production.yml (encrypt with password A)
production_password: 'test1'
cat/group_vars/all/vault_staging.yml (encrypt with password B)
staging_password: 'test2'
My environments :
cat hosts-production
[all:vars]
env_type=production
cat hosts-staging
[all:vars]
env_type=staging
My script :
- copy:
content: |
env PASS={{hostvars[inventory_hostname][env_type + '_password']}}
...
And I launch the playbook like that.
# for production
ansible-playbook -i hosts-staging test.yml --vault-password-file .password_a
# for staging
ansible-playbook -i hosts-staging test.yml --vault-password-file .password_b
But that doesn't work because there is 2 differents passwords (ERROR! Decryption failed).
Do you know how to do that ?
Thanks.
BR,
Eric
Multiple vault passwords are supported since Ansible 2.4:
ansible-playbook --vault-id dev#dev-password --vault-id prod#prompt site.yml
If multiple vault passwords are provided, by default Ansible will attempt to decrypt vault content by trying each vault secret in the order they were provided on the command line.
In the above case, the ‘dev’ password will be tried first, then the ‘prod’ password for cases where Ansible doesn’t know which vault id is used to encrypt something.
Sorry, only one vault password allowed per run today. Best way to work around this in the case where you really only need one or the other is to dynamically load a vaulted file based on a var; eg:
- hosts: localhost
vars_files:
- secretstuff-{{ env_type }}.yml
tasks:
...
or
- hosts: localhost
tasks:
- include_vars: secretstuff-{{ env_type }}.yml
...
depending on if you need the vars to survive for one play or the entire run (the latter will bring them in as facts instead of play vars).