Use ansible to create a vault file and write output to it - ansible

I want to create user accounts with corresponding passwords all in a single playbook. To do this I define the users I need for my project and want to generate passwords for them. The attached script creates a password per user and assigns it to the r variable. This all works fine, I can call the items with their passwords. However I would like to save the usernames and passwords into a vault file that is encrypted all from within the playbook. But I can't figure out a way to do this.
Currently I write the output to the userfile.txt (output is a single line of .json, would like to have it in a nicer format) but then I would have to run an extra ansible-vault encrypt command. Is there a way to do this all from within a single playbook?
vars:
users:
- testuser1
- testuser2
tasks:
- name: Generate passwords
script: generate_passwords.py "{{item}}"
register: "r"
args:
executable: python3
with_items: "{{ users }}"
# The following proves that I can call the username and password:
- debug: msg="username={{item.item}}, password={{item.stdout_lines[0]}}"
with_items: "{{r.results}}"
# This saves everything in cleartext, how to do this into a vault file?
- copy:
content: "{{r}}"
dest: userfile.txt

Related

Give Input from Text file to Ansible Playbook

In my ansible playbook I want to get the input from text file and perform some set of operations.
I have 10 user names in the text file, then the play has to pick first name from the text file and do few tasks. Once done for the first user and the play has to pick it for second user and so on.
I wrote play for a single user. Kindly help me or give some sample play for this kind of scenario.
You should be using roles and manage everything from inventory.
But however, simplest way; Create a file, and store your user names in a variable that way
users:
- user1
- user2
- user3
- user4
- user5
At the beginning of your playbook, include that file
- hosts: whatever
become: yes
vars_file:
- <<path_to_your_var_file>>
Then in the task you can use that users variable you included from the variable file
tasks:
- name: create 10 users
user:
name: "{{ item }}"
state: present
with_items:
- "{{ users }}"
Ansible will import the users variable from your var file, and loop n times with number of users you have.

How to combine multiple vars files per host?

I have a playbook running against multiple servers. All servers require a sudo password to be specified, which is specific to each user running the playbook. When running the playbook, I can't use --ask-become-pass, because the sudo passwords on the servers differ. This is the same situation as in another question about multiple sudo passwords.
A working solution is to specify ansible_become_pass in host_vars:
# host_vars/prod01.yml
ansible_become_pass: secret_prod01_password
domain: prod01.example.com
# host_vars/prod02.yml
ansible_become_pass: secret_prod02_password
domain: prod02.example.com
Besides ansible_become_pass, there are other variables defined per host. These variables should be committed to the git repository. However, as ansible_become_pass is specific to each user running the playbook, I'd like to have a separate file (ideally, vaulted) which specifies the password per host.
I imagine the following:
# host_vars/prod01.yml: shared in git
domain: prod01.example.com
# host_vars/prod01_secret.yml: in .gitignore
ansible_become_pass: secret_prod01_password
I imagine both files to be combined by Ansible when running the playbook. Is this possible in Ansible? If so, how?
You should be able to use the include_vars task with the inventory_hostname or ansible_hostname variable. For example:
- name: Include host specific variables
include_vars: "{{ ansible_hostname }}.yml"
- name: Include host specific secret variables
include_vars: "{{ ansible_hostname }}_secret.yml"
An even better solution would be to address the problem of users having unique passwords on different hosts.
You could create a new group in the inventory file, maybe sudo-hosts. Put all your sudo host in this group. Then create a file under the directory group_vars with the name of this goup. In this file put the secret yaml-structured text.
sudo_hosts:
host1:
password: xyz
othersecret_stuff: abc
host2:
...
then use ansbile-vault to encrypt this file with ONE password. Call the playbook with option --ask-vault-pass
and you can use your secrets with
"{{ sudo_host['ansible_host'].password }}"

Run ansible-vault encrypt_string in ansible playbook

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.

How do I save an ansible variable into a temporary file that is automatically removed at the end of playbook execution?

In order to perform some operations locally (not on the remote machine), I need to put the content of an ansible variable inside a temporary file.
Please note that I am looking for a solution that takes care of generating the temporary file to a location where it can be written (no hardcoded names) and also that takes care of the removal of the file as we do not want to leave things behind.
You should be able to use the tempfile module, followed by either the copy or template modules. Like so:
- hosts: localhost
tasks:
# Create a file named ansible.{random}.config
- tempfile:
state: file
suffix: config
register: temp_config
# Render template content to it
- template:
src: templates/configfile.j2
dest: "{{ temp_config.path }}"
vars:
username: admin
Or if you're running it in a role:
- tempfile:
state: file
suffix: config
register: temp_config
- copy:
content: "{{ lookup('template', 'configfile.j2') }}"
dest: "{{ temp_config.path }}"
vars:
username: admin
Then just pass temp_config.path to whatever module you need to pass the file to.
It's not a great solution, but the alternative is writing a custom module to do it in one step.
Rather than do it with a file, why not just use the environment? This wan you can easily work with the variable and it will be alive through the ansible session and you can easily retrieve it in any steps or outside of them.
Although using the shell/application environment is probably, if you specifically want to use a file to store variable data you could do something like this
- hosts: server1
tasks:
- shell: cat /etc/file.txt
register: some_data
- local_action: copy dest=/tmp/foo.txt content="{{some_data.stdout}}"
- hosts: localhost
tasks:
- set_fact: some_data="{{ lookup('file', '/tmp/foo.txt') }}"
- debug: var=some_data
As for your requirement to give the file a unique name and clean it up at the end of the play. I'll leave that implementation to you

Ansible to generate random passwords automatically for users

I am trying to create playbook where list of users will be created.
However, I also want to generate random password for each user. Once the passwords are generated, I would like to have a text file holding username:new_generated_password key values, next to the playbook file. Is it possible to do this without developing a new module?
The password lookup can generate passwords for you and puts the generated password on the control machine (i.e. where the playbook is running). An example task that creates a user and sets their password may look something like this:
- name: Create users with auto generated password
user:
name: "{{ item.name }}"
password: "{{ lookup('password', 'credentials/' + item.name + '/password.txt encrypt=md5_crypt') }}"
with_items: users
This would then create a text file named ~/credentials/$username/password.txt on the control machine. If you were to rerun the Ansible play then Ansible would recognise that filepath as the password and make sure to set the user's password to that same value - making it idempotent.
This doesn't get you quite what you wanted but gets all the information that you needed on to the Ansible control host so you could then further manipulate it to get the final output that you wanted.

Resources