1

I have a list of users (this is not actual Ansible code, just an example):

users:
 -tom
 -jerry
 -pluto

Now I am trying to create a dynamic structure ( list of dictionaries ?) like this, for setting random (at runtime) passwords to them:

users_and_passwords:
  -tom, "random_password_here1"
  -jerry, "random_password_here2"
  -pluto, "random_password_here3"

How can I write a set_fact task to generate random password for each user and save it for later use?
How can I then read that and use it in other tasks later?

So far I tried declaring a list of users (later to be looped from a file), then an empty list of passwords. Now I am trying to populate the Password list with random strings, then to combine them into a single {user:password} dict.I can't figure out how to do this easier, and I am stuck in the "populate password list" phase.

    users:
      -top
      -jerry
      -pluto

    passwords: []


  tasks:
  - name: generate passwords in an empty Dict
    set_fact: 
      passwords: "{{ passwords | default({}) + {{ lookup('password', '/dev/null chars=ascii_lowercase,ascii_uppercase,digits,punctuation length=20') }} }}"

    with_items: "{{users}}"
florian
  • 35
  • 7

2 Answers2

3

Rather than having a complex dictionary that would read:

- tom: password123456
- jerry: password123456789
- muttley: password12345

Aim for a structure that would be normalized, like:

- name: tom
  password: password123456
- name: jerry
  password: password123456789
- name: muttley
  password: password12345

This can be achieved with the task:

- set_fact:
    users_with_passwords: >-
      {{
        users_with_passwords | default([]) + 
        [{
          'name': item,
          'password': lookup(
            'password', 
            '/dev/null chars=ascii_lowercase,ascii_uppercase,digits,punctuation length=20'
          )
        }]
      }}
  loop: "{{ users }}"

And, can be easily accessed via something like:

- debug:
    msg: "{{ item.name }}'s password is `{{ item.password }}`"
  loop: "{{ users_with_passwords }}"
  loop_control:
    label: "{{ item.name }}"

Given the playbook

- hosts: localhost
  gather_facts: no
  vars:
    users:
      - tom
      - jerry
      - muttley

  tasks:
    - set_fact:
        users_with_passwords: >-
          {{
            users_with_passwords | default([]) + 
            [{
              'name': item,
              'password': lookup(
                'password', 
                '/dev/null chars=ascii_lowercase,ascii_uppercase,digits,punctuation length=20'
              )
            }]
          }}
      loop: "{{ users }}"

    - debug:
        msg: "{{ item.name }}'s password is `{{ item.password }}`"
      loop: "{{ users_with_passwords }}"
      loop_control:
        label: "{{ item.name }}"

This yields:

TASK [set_fact] *************************************************************
ok: [localhost] => (item=tom)
ok: [localhost] => (item=jerry)
ok: [localhost] => (item=muttley)

TASK [debug] ****************************************************************
ok: [localhost] => (item=tom) => 
  msg: tom's password is `tLY>@jg6k/_|sqke{-mm`
ok: [localhost] => (item=jerry) => 
  msg: jerry's password is `Liu1wF@gPM$q^z~g|<E1`
ok: [localhost] => (item=muttley) => 
  msg: muttley's password is `BGHL_QUTHmbn\(NGW`pJ`
β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
  • This is very close to what I needed ! Thank you very much ! – florian Jan 14 '22 at 07:23
  • Still one more question : how can I retrieve the password for a specific user (by name), later in the script ? I know I can retrieve it by index, but I would like to use something like : users_with_passwords['tom'].password – florian Jan 15 '22 at 14:24
  • @florian the best is to open a new question. But since it is quite trivial: `"{{ (users_with_passwords | selectattr('name', 'equalto', 'tom') | first).password }}"` – β.εηοιτ.βε Jan 15 '22 at 19:18
  • Or `"{{ (users_with_passwords | items2dict(key_name='name', value_name='password')).tom }}"` – β.εηοιτ.βε Jan 15 '22 at 19:21
1

How can I write a set_fact task to generate random password for each user and save it for later use?

This sound like a task for the password_lookup which "Retrieves or generate a random password, stored in a file", in Example

- name: Create random but idempotent password
  set_fact:
    toms_password: "{{ lookup('password', '/dev/null', seed=username) }}"

How can I then read that and use it in other tasks later?

Just by Using variable name which was defined during set_fact.

Further readings

β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
U880D
  • 8,601
  • 6
  • 24
  • 40
  • Thank you for your reply. This is what I am trying , but I have a long list of users, so I can't use "toms_password" variables. I am trying to loop the user's list out of a separate file – florian Jan 13 '22 at 20:35
  • @florian, but you can generate lists, loop over them, generate passwords with the lookup module, store them under `/tmp/{{ username }}.pwd` or somewhere else, etc. There are already plenty of questions with answers here on SO how to do this. Some of them I've linked. – U880D Jan 13 '22 at 20:40
  • @florian, or is your question more related to "how to create a specific data structure" as the headline indicates? If so, some more information in the question might help us all. – U880D Jan 13 '22 at 20:44