I'm trying to run an ansible playbook with the ansible_ssh_pass option to connect to the destination server.
ansible-playbook test-playbook.yml -i hosts -u daniel --extra-vars "{"ansible_ssh_pass":"u5!vuL!<35Lf?<>n'x"}"
The problem is that the password has special characters.
I tried saving it using.
"password\'s"
"password"
"\"password\""
Any idea how can I save the password?
Probably a little late but the exact solution to your specific problem is:
ansible-playbook test-playbook.yml -i hosts -u daniel --extra-vars ansible_ssh_pass=$'"u5!vuL!<35Lf?<>n\'x"'
The shell treats $'<string>' specially and escapes the single quote inside (see the backslash)
The outermost double quotes are necessary so that jinja2 template engine does not get confused inside ansible.
That being said, it is quite a bad idea to run the command like this for at least two reasons:
It's not secure. Anyone with access to listing processes on the machine or to your shell history will be able to see the password.
It's not flexible. Ansible extra variables provided on the command line have the highest precedence. If you add an other host in your inventory with a different ssh password, you won't be able to differentiate the two passwords.
For the first problem, and if you are sure you will only have one machine (or the same password everywhere), you could ask for the password interactively with vars_prompt for example (http://docs.ansible.com/ansible/latest/user_guide/playbooks_prompts.html)
The best approach solving both issues is to add the password using vault encryption to your inventory for the particular host. You then provide the overall vault password interactively (--ask-vault-pass) or through a well secured vault password file (--vault-password-file=) when you call the playbook.
Finally figured this one out for a password changing script that couldn't use vars_prompts.
For my bash program that was running ansible I needed to first get the password from a user via read then do the following:
Convert the bad string into base64 and save to b64_pass
Pass b64_pass as b64_ansible_ssh_pass extra arg
Use set_fact to set ansible_ssh_pass and use b64decode filter on extra arg b64_ansible_ssh_pass
Short example testba.sh:
#!/bin/bash
read -p -s "Enter ssh password: " ssh_pass
# Convert input or var to base64
b64_pass=$(printf '%s' "$ssh_pass" | base64)
# Run ansible command
ansible-playbook test.yml -m shell -a "echo OK" -e "b64_ansible_ssh_pass='$b64_pass'" -v
Playbook test.yml:
- hosts: all
# Assign ansible_ssh_pass in vars OR below in task with set_fact
vars:
ansible_ssh_pass: "{{ b64_ansible_ssh_pass | b64decode }}"
tasks:
# Assign ansible_ssh_pass in task with set_fact
- name: Set ssh pass
set_fact:
ansible_ssh_pass: "{{ b64_ansible_ssh_pass | b64decode }}"
no_log: true
- shell: echo hi
If you need to pass a password var into the user module
#!/bin/bash
read -p -s "Enter ssh password: " ssh_pass
# Convert input or var to base64
b64_pass=$(printf '%s' "$ssh_pass" | base64)
# Run ansible command
ansible <hosts_to_run_on> -m shell -a "echo OK" -e "new_pass=$b64_pass"
Then in your playbook
- hosts: all
vars:
my_new_pass: "{{ new_pass | b64decode }}"
tasks:
user:
name: "NewUser"
password: "{{ my_new_pass }}"
I know that for ansible-vault you can specify a password in a file, I am assuming that this would also work in this case, though I am not positive.
ansible-playbook test-playbook.yml -i hosts -u daniel --extra-vars ansible_ssh_pass=/path/to/file.txt
If you remove the singe quote special char, you can do single quotes around the rest and it should work:
ansible-playbook test-playbook.yml -i hosts -u daniel -e ansible_ssh_pass='u5!vuL!<35Lf?<>nx'
1、if ansible ansible_ssh_pass Has special characters
[test]
192.168.1.1 ansible_ssh_user=network ansible_ssh_pass="'6j##D#vcsA4'"
Related
For a specific case I need to echo a random string returned by ansible's function password_hash that contains multiple random $ signs (encryption method bcrypt). The echoed string is then piped into the next command.
Ideally I would just escape the entire string. If that is not possible, I would like to escape all $ signs. How is that possible? If there is an ansible native command that automatically escapes a variable, that would be fine, too.
Full task if needed
- name: Update Admin password
shell: "echo \"update users set passwd={{ zabbix_conf.admin_password|password_hash('bcrypt') }} where username='Admin'\" | mysql --user={{ zabbix_conf.db_user}} --password={{ zabbix_conf.db_password }} zabbix"
Currently doesn't work as expected, because the $ signs affect the echo to be empty.
Ansible already has an inbuilt command for executing mysql queries called mysql_query. Therefore one can simply do:
- name: Update Admin password
mysql_query:
login_db: "{{ zabbix_conf.db }}"
login_user: "{{ zabbix_conf.db_user}}"
login_password: "{{ zabbix_conf.db_password }}"
query: "update users set passwd='{{ zabbix_conf.admin_password|password_hash('bcrypt') }}' where username='Admin'"
That way you don't need to escape anything and it looks much cleaner, too.
In case someone wants to reproduce this: Ansible requires the installation of passlib to password_hash bycrypt.
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
Recently I used 'user' module to create user with password provided in vars/main.yml
- name: Create pamuser
user:
name: pamuser
password: "{{ pamuser_pass }}"
groups: wheel
append: yes
tags: pamuser
Once run a playbook, it gives me this warning
TASK [prerequisite : Create pamuser] *****************************************************************************
[WARNING]: The input password appears not to have been hashed. The 'password' argument must be encrypted for this
module to work properly.
Then I use ansible-vault encrypt_string command to encrypt only the specific variable "pamuser_pass"by replace plaintext with vault password that ansible-vault gave me
contents in /vars/main.yml
---
# vars file for prerequisite role
pamuser_pass: !vault |
$ANSIBLE_VAULT;1.1;AES256
65643265346231613137396339303834396663383466636631646337303235306137386534396266
3364333534616238396465626436376561323762303139620a376630643131323133336164373237
64663332363233303032636638306566303034393137636533373332383334333439663930613232
3737
then I remove current pamuser and re-run the playbook with command
ansible-playbook playbook.yaml --tags "pamuser" --ask-pass -K --ask-vault-pass
Along with the running process, it still shows the warning
[WARNING]: The input password appears not to have been hashed. The 'password' argument must be encrypted for this
module to work properly.
the outcome seem fine with id pamuser but once logging in with ssh pamuser#example.com then put the regular password, the password doesn't work. I can't login with that pamuser.
Is there something that I missed?
You should be following one of the recommended ways mentioned
here to provide the hash. It's not the general vault encryption in ansible. This is specific to the user module. Below is from the doc:
How do I generate encrypted passwords for the user module? Ansible
ad-hoc command is the easiest option:
ansible all -i localhost, -m debug -a "msg={{ 'mypassword' | password_hash('sha512',
'mysecretsalt') }}"
The mkpasswd utility that is available on most
Linux systems is also a great option:
mkpasswd --method=sha-512
Context
In my company, we have a shared repository containing our ansible script for our servers. I would like to introduce vault variables to handle services password in the near future. For now, we use encrypted password prompts at the beginning of our playbooks. This solution is annoying (it asked for 3 passwords on some playbooks).
Need
As most of our ansible users are no experts, I would like them to be able to run playbooks smoothly. It means ansible-playbook commands should be short and work without any mandatory parameters (e.g. no --ask-sudo-pass and whatnot). It also means I prefer prompting for vault password at the beginning of a playbook only when it’s needed.
Moreover, I do not want to use ansible password file, because it is not easily shareable and I don’t like the idea of having a cleartext password file on all our ansible users computers.
Problem
Adding --ask-vault-pass for every concerned playbooks is not an option. Our ansible users will not understand why sometimes this parameter is needed and why sometimes it’s not. On the contrary, asking the vault password for every playbook is a burden, because we have a lot of playbooks and sudo password is already asked each time too.
I tried to achieve the following solution, using prompts and various options. Nothing seems to work. Documentation does not explain how to do this:
The best solution (according to me)
Let’s look at this main.yml file:
- import_tasks: foo.yml
tags: always
- import_tasks: bar.yml
tags: bar
# Only this tasks uses a vault encrypted variable
- import_tasks: baz.yml
tags: [baz, vault]
Now, there’s a playbook.yml, importing this main.yml file.
In a perfect world, I would like this to happen:
example1:
ansible-playbook -i prod playbook.yml
Vault password:
example2:
ansible-playbook -i prod playbook.yml --tags baz
Vault password:
example3:
ansible-playbook -i prod playbook.yml --tags foo
# it runs without asking for vault password, because no tasks needing vault
# password will be run
Question
How can I configure ansible to ask for vault password only when it is needed (meaning: every time a vault encrypted variable is encountered)? Is it even possible? If not, what workaround would be viable given my situation?
Thanks.
I found a workaround.
The idea is to always load all passwords (including sudo) from an ansible vault file, needing only the vault password for each playbook. It means all machines should have the same deployer user password. This is even simpler than before, because there’s a single master password (the vault password) to control them all.
This is how it’s done:
ansible.cfg:
[privilege_escalation]
become_ask_pass = False
become = True
[defaults]
ask_vault_pass = True
vars/vault/env:
_vault:
sudo: !vault |
$ANSIBLE_VAULT;1.1;AES256
BLAHBLAHBLAH
another_pass: !vault |
$ANSIBLE_VAULT;1.1;AES256
ANOTHERENCRYPTEDPASSWORD
And for each playbook:
# Playbook stuff
# [...]
vars:
ansible_become_pass: "{{ _vault.sudo }}"
vars_files:
# env var is set dynamically in inventory file, so I can have different password per env.
# If the file is not found, it loads an empty null file
- [ "vars/vault/{{ env }}", "vars/null"]
# [...] Loading other var files
Now, a simple ansible-playbook -i env/prod myPlayBook.yml will only ask for the vault password, no prompt for sudo or anything else. It’s consistent and easy to share (only the encrypted password file and the vault password must be shared).
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).