Tworzenie nowego użytkownika i hasła w Ansible

103

Mam zadanie ansible, które tworzy nowego użytkownika na systemie ubuntu 12.04;

- name: Add deployment user
    action: user name=deployer password=mypassword

kończy się zgodnie z oczekiwaniami, ale kiedy loguję się jako ten użytkownik i próbuję sudo z ustawionym hasłem, zawsze mówi, że jest nieprawidłowe. Co ja robię źle?

raphael_turtle
źródło
1
Czy logujesz się przy użyciu tego samego hasła lub kluczy SSH? Czy sprawdziłeś plik shadow, aby upewnić się, że jego zawartość jest zgodna z oczekiwaniami? Również twój passwordnie powinien być zwykłym tekstem, ale raczej zhasowany.
Mxx,
moje hasło jest w postaci zwykłego tekstu, czy nie mogę go w ten sposób używać? Nie rozumiem, jak to zaszyfrować, albo naprawdę muszę.
raphael_turtle

Odpowiedzi:

101

Jeśli przeczytasz instrukcję Ansible dla usermodułu , przekieruje Cię ona do repozytorium Ansible na github z przykładami, aby uzyskać szczegółowe informacje na temat używania passwordparametru .

Tam zobaczysz, że Twoje hasło musi zostać zaszyfrowane.

- hosts: all
  user: root
  vars:
    # created with:
    # python -c 'import crypt; print crypt.crypt("This is my Password", "$1$SomeSalt$")'
    password: $1$SomeSalt$UqddPX3r4kH3UL5jq5/ZI.

  tasks:
    - user: name=tset password={{password}}

Jeśli Twój playbook lub wiersz poleceń programu ansible zawiera Twoje hasło w postaci zwykłego tekstu, oznacza to, że skrót hasła zarejestrowany w pliku shadow jest nieprawidłowy. Oznacza to, że gdy próbujesz uwierzytelnić się za pomocą hasła, jego skrót nigdy się nie zgadza.

Dodatkowo, zobacz Ansible FAQ , aby dowiedzieć się więcej o niektórych niuansach parametrów hasła i ich poprawnym użyciu.

Mxx
źródło
25
Dzięki za wskazówkę. Chciałem tylko zwrócić uwagę, że w dokumentacji modułu użytkownika, do której link znajduje się powyżej, zaleca się używanie openssl passwd -salt <salt> -1 <plaintext>do generowania skrótu hasła, a nie jednowierszowego Pythona, który masz powyżej. Miałem problemy z uzyskaniem poprawnych danych wyjściowych z Pythona, prawdopodobnie z powodu mojej własnej niekompetencji, a polecenie openssl działało lepiej.
Brendan Wood,
6
Jak synchronizujesz sól, która ma być używana z systemem operacyjnym?
Breedly
5
@Breedly: nie ma potrzeby - sól jest zawsze przechowywana jako część hasła (1 $ thesalt $ thepasswordhash), co oznacza, że ​​można ją przenosić między systemami operacyjnymi przy użyciu tej samej funkcji skrótu
Benjamin Dale
3
Użycie tego polecenia Pythona do wygenerowania skrótu nie zadziałało. Ale znalazłem hash /etc/shadowpo ręcznym ustawieniu hasła za pomocą passwd <user>.
dokaspar
172

Mogę być za późno, aby odpowiedzieć na to pytanie, ale ostatnio odkryłem, że filtry jinja2 mają możliwość obsługi generowania zaszyfrowanych haseł. W moim main.ymlgeneruję zaszyfrowane hasło jako:

- name: Creating user "{{ uusername }}" with admin access
  user: 
    name: {{ uusername }}
    password: {{ upassword | password_hash('sha512') }}
    groups: admin append=yes
  when:  assigned_role  == "yes"

- name: Creating users "{{ uusername }}" without admin access
  user:
    name: {{ uusername }}
    password: {{ upassword | password_hash('sha512') }}
  when:  assigned_role == "no"

- name: Expiring password for user "{{ uusername }}"
  shell: chage -d 0 "{{ uusername }}"

„uusername” i „upassword” są przekazywane jako --extra-varsplaybook i zauważ, że użyłem tutaj filtru jinja2 do zaszyfrowania przekazanego hasła.

Dodałem poniższy poradnik związany z tym do mojego bloga

myślący potwór
źródło
6
Aby uniknąć sytuacji, w której pozycja jest zawsze „zmieniana”, możesz dodać tajną „sól” jako drugi parametr do skrótu password_hash.
Michael Wyraz
11
Zgodnie z sugestią @ MichaelWyraz: dodanie drugiego parametru „sól” pozwala uniknąć „zmiany”. Możesz to ustawić za pomocą zmiennej, np password={{upassword|password_hash('sha512', upassword_salt)}}. To pozwala umieścić sól w skarbcu zmiennych , jak przypuszczalnie zrobiłbyś to upasswordsamo, utrzymując oba z dala od tasks.yml.
user85461
Zastosowałbym również sprawdzanie stanu @ bbaassssiiee i dodałbym update_password: on_createmoduł użytkownika do tej odpowiedzi, aby zapobiec wygaśnięciu haseł dla już utworzonych użytkowników.
szalony
Dziękuję za wspaniały przykład, który zaprowadził mnie na właściwą drogę. Niemniej jednak musiałem zrobić kilka rzeczy, aby działał na komputerze Mac z wersją ansibla 2.8.2. Przede wszystkim na komputerze Mac nie można używać crypt, dlatego wymagane jest zainstalowanie biblioteki passlib z pip install passlib. Następnie, aby móc użyć inline przechowalni zaszyfrowany ciąg musiałem sformatować z następującym uzupełnieniem: password: {{ upassword | string | password_hash('sha512') }}. Pozwala to uniknąć komunikatu o błędziesecret must be unicode or bytes, not ansible.parsing.yaml.objects.AnsibleVaultEncryptedUnicode
Michael Aicher
pomimo użycia tej metody do ustawienia hasła: "{{my_password | string | password_hash ('sha512')}}" Nadal dostanę - [OSTRZEŻENIE]: Wprowadzone hasło nie zostało zaszyfrowane. Argument „hasło” musi być zaszyfrowany, aby ten moduł działał poprawnie.
openCivilisation
46

Chcę zaproponować jeszcze jedno rozwiązanie:

- name: Create madhead user
  user:
    name: madhead
    password: "{{ 'password' | password_hash('sha512') }}"
    shell: /bin/zsh
    update_password: on_create
  register: madhead
- name: Force madhead to change password
  shell: chage -d 0 madhead
  when: madhead.changed

Dlaczego to jest lepsze? Jak już tu wspomniano, gry Ansible powinny być idempotentne. Powinieneś myśleć o nich nie jako o sekwencji działań w stylu rozkazującym, ale jak o pożądanym stanie, stylu deklaratywnym. W rezultacie powinieneś być w stanie uruchomić go wiele razy i uzyskać ten sam wynik, ten sam stan serwera.

To wszystko brzmi świetnie, ale są pewne niuanse. Jednym z nich jest zarządzanie użytkownikami. „Stan pożądany” oznacza, że ​​za każdym razem, gdy uruchamiasz grę, która tworzy użytkownika, zostanie on zaktualizowany, aby dokładnie odpowiadał temu stanowi. Przez „zaktualizowane” rozumiem, że jego hasło również zostanie zmienione. Ale najprawdopodobniej to nie jest to, czego potrzebujesz. Zwykle wystarczy tylko raz stworzyć użytkownika, ustawić i wygaśnąć jego hasło, dalsze rozgrywki nie powinny aktualizować jego hasła.

Na szczęście Ansible ma update_passwordatrybut w usermodule, który rozwiązuje ten problem. Mieszając to z zarejestrowanymi zmiennymi , możesz również wygasnąć jego hasło tylko wtedy, gdy użytkownik jest faktycznie zaktualizowany.

Zauważ, że jeśli zmienisz powłokę użytkownika ręcznie (przypuśćmy, że nie podoba ci się powłoka, którą zmusił zły administrator do swojej gry), użytkownik zostanie zaktualizowany, a tym samym jego hasło straci ważność.

Zwróć także uwagę, jak łatwo możesz używać początkowych haseł w postaci zwykłego tekstu w grach. Nie ma potrzeby kodowania ich gdzie indziej i wklejania skrótów, możesz do tego użyć filtra Jinja2 . Może to jednak stanowić lukę w zabezpieczeniach, jeśli zdarzy się, że ktoś zaloguje się, zanim to zrobisz.

szaleniec
źródło
3
Nie mogłem sprawić, by inne rozwiązanie działało dla mnie. Jednak twoja odpowiedź jest prosta i skuteczna. Chciałbym dać Ci 5 głosów za, jeśli mógłbym.
leesei
Nie chcę, aby moje hasło było zakodowane na stałe w ten sposób :( Czy można je wyciągnąć ze skarbca ansibla i wstrzyknąć tutaj? Zagnieżdżanie "{{ '{{vaulted_password}}' | password_hash('sha512') }}"wydaje się nie działać ...
dokaspar
Czy próbowałeś {{ vaulted_password | password_hash('sha512') }}, gdzie vaulted_passwordjest klucz do wartości w skarbcu?
szalony
update_password: on_createwygląda na to, że nie działa (jest otwarty błąd z 2017 r.), więc hasła zmienią się za każdym razem, gdy nastąpi zmiana stanu użytkownika.
Diti
11

Moduł użytkownika Ansible zarządza użytkownikami w idempotentny sposób. W playbooku poniżej pierwsze zadanie deklaruje stan = obecny dla użytkownika. Zauważ, że ' register: newuser ' w pierwszej akcji pomaga drugiej akcji określić, czy użytkownik jest nowy (newuser.changed == True) czy istniejący ( newuser.changed==False), aby wygenerować hasło tylko raz.

Playbook Ansible zawiera:

tasks:
  - name: create deployment user
    user: 
      name: deployer 
      createhome: yes 
      state: present 
    register: newuser

  - name: generate random password for user only on creation
    shell: /usr/bin/openssl rand -base64 32 | passwd --stdin deployer
    when: newuser.changed
bbaassssiiee
źródło
Tylko jedno rozwiązanie działa dla mnie z hasłem do skarbca. Dziękuję bardzo.
Denis Savenko,
przynajmniej najnowsze dystrybucje oparte na Debianie nie wydają się obsługiwać długiej opcji GNU „--stdin” w pliku binarnym passwd.
XXL
10

spróbuj w ten sposób

vars_prompt:
 - name: "user_password"    
   prompt: "Enter a password for the user"    
   private: yes    
   encrypt: "md5_crypt" #need to have python-passlib installed in local machine before we can use it    
   confirm: yes    
   salt_size: 7

 - name: "add new user" user: name="{{user_name}}" comment="{{description_user}}" password="{{user_password}}" home="{{home_dir}}" shell="/bin/bash"
Artem Feofanov
źródło
2
Podoba mi się to rozwiązanie, ponieważ pozwala na wpisanie hasła podczas uruchamiania skryptu. Niezłe rozwiązanie dla skryptu bootstrap, który nie powinien być uruchamiany za każdym razem. Jednak w przypadku Ubuntu użyłem „sha512_crypt”.
Gunnar
6

Celem roli w tej odpowiedzi jest wygenerowanie losowego hasła dla new_user_name i natychmiastowe wygaśnięcie hasła. Nowa nazwa_użytkownika jest wymagana do zmiany hasła przy pierwszym logowaniu.

create_user.yml:

---
# create_user playbook

- hosts: your_host_group
  become: True
  user: ansible

  roles:
    - create_user

role / create_user / jobs / main.yml:

---
# Generate random password for new_user_name and the new_user_name
# is required to change his/her password on first logon. 

- name: Generate password for new user
  shell: makepasswd --chars=20
  register: user_password

- name: Generate encrypted password
  shell: mkpasswd --method=SHA-512 {{ user_password.stdout }}
  register: encrypted_user_password

- name: Create user account
  user: name={{ new_user_name }}
        password={{ encrypted_user_password.stdout }}
        state=present
        append=yes
        shell="/bin/bash"
        update_password=always
  when: new_user_name is defined and new_user_name in uids
  register: user_created

- name: Force user to change password
  shell: chage -d 0 {{ new_user_name }}
  when: user_created.changed

- name: User created
  debug: msg="Password for {{ new_user_name }} is {{ user_password.stdout }}"
  when: user_created.changed

Jeśli chcesz utworzyć nowego użytkownika:

ansible-playbook -i hosts.ini create_user.yml --extra-vars "new_user_name=kelvin"
McKelvin
źródło
3

To jest łatwy sposób:

---
- name: Create user
  user: name=user shell=/bin/bash home=/srv/user groups=admin,sudo generate_ssh_key=yes ssh_key_bits=2048
- name: Set password to user
  shell: echo user:plain_text_password | sudo chpasswd
  no_log: True
Oświetlony
źródło
powłoka: zawsze spowoduje zgłoszenie zmiany.
bbaassssiiee
@datasmid możesz dodać opcję no_log: True docs.ansible.com/ansible/…
Phill Pafford
3

Tak to u mnie zadziałało

- hosts: main
  vars:
  # created with:
  #  python -c "from passlib.hash import sha512_crypt; print sha512_crypt.encrypt('<password>')"
  # above command requires the PassLib library: sudo pip install passlib
  - password: '$6$rounds=100000$H/83rErWaObIruDw$DEX.DgAuZuuF.wOyCjGHnVqIetVt3qRDnTUvLJHBFKdYr29uVYbfXJeHg.IacaEQ08WaHo9xCsJQgfgZjqGZI0'

tasks:

- user: name=spree password={{password}} groups=sudo,www-data shell=/bin/bash append=yes
  sudo: yes
hecbuma
źródło
3

Dla kompletności opublikuję komendę ad-hoc za pomocą ansible, ponieważ jest tam również haczyk.

Najpierw spróbuj wygenerować zaszyfrowane hasło za pomocą narzędzia mkpasswd, które jest dostępne w większości systemów Linux:

mkpasswd --method=SHA-512

Następnie wypróbuj polecenie ansible ad-hock:

ansible all -m user -a 'name=testuser shell=/bin/bash \
     comment="Test User" password=$6$XXXX' -k -u admin --sudo

Ale upewnij się:

  1. Polecenie jest w pojedynczych cudzysłowach i NIE podwaja się, w przeciwnym razie twoje hasło nigdy nie będzie działać
  2. Uruchamiasz go z --sudolub kończysz z błędem typu ( useradd: cannot lock /etc/passwd; try again later)
pgaref
źródło
dzięki kolego, szukałem wersji adhoc i miałem ten sam problem z cytatem, o którym wspomniałeś
aleksakarpow
2

Definicja zadania dla modułu użytkownika powinna być inna w najnowszej wersji Ansible.

tasks:
  - user: name=test password={{ password }} state=present
Christian Berendt
źródło
2

Łącząc kilka rozwiązań z powyższego, stworzyłem poradnik, który automatycznie generuje poprawne skróty haseł na podstawie haseł w postaci zwykłego tekstu przechowywanych w zaszyfrowanym, lokalnym pliku skarbca ansible:

---
- hosts: [your hosts]
  tasks:
  - include_vars: [path to your encrypted vault file]
  - local_action: "command openssl passwd -salt '{{password_salt}}' -1 '{{password}}'"
    register: password_hash
  - user: >
        name=[your username]
        state=present
        password="{{password_hash.stdout}}"

Uruchom to polecenie za pomocą opcji „--ask-vault-pass”, aby odszyfrować plik przechowalni (zobacz ansible-vault, aby uzyskać informacje na temat zarządzania zaszyfrowanym skarbcem).

Steve Midgley
źródło
2

Jak stworzyć zaszyfrowane hasło do przekazania do passwordvar do userzadania Ansible (z komentarza @Brendan Wooda):

openssl passwd -salt 'some_plain_salt' -1 'some_plain_pass'

Wynik będzie wyglądał następująco:

$1$some_pla$lmVKJwdV3Baf.o.F0OOy71

Przykładowe userzadanie:

- name: Create user
  user: name="my_user" password="$1$some_pla$lmVKJwdV3Baf.o.F0OOy71"

UPD: crypt using SHA-512 patrz tutaj i tutaj :

Pyton

$ python -c "import crypt, getpass, pwd; print crypt.crypt('password', '\$6\$saltsalt\$')"

$6$saltsalt$qFmFH.bQmmtXzyBY0s9v7Oicd2z4XSIecDzlB5KiA2/jctKu9YterLp8wwnSq.qc.eoxqOmSuNp2xS0ktL3nh/

Perl

$ perl -e 'print crypt("password","\$6\$saltsalt\$") . "\n"'

$6$saltsalt$qFmFH.bQmmtXzyBY0s9v7Oicd2z4XSIecDzlB5KiA2/jctKu9YterLp8wwnSq.qc.eoxqOmSuNp2xS0ktL3nh/

Rubin

$ ruby -e 'puts "password".crypt("$6$saltsalt$")'

$6$saltsalt$qFmFH.bQmmtXzyBY0s9v7Oicd2z4XSIecDzlB5KiA2/jctKu9YterLp8wwnSq.qc.eoxqOmSuNp2xS0ktL3nh/
Dmitriy
źródło
1
Czy to nie jest generowanie zaszyfrowanego hasła md5? Czy to nie jest niepewne?
Mark
2

Możesz użyć ansible-Vault do używania tajnych kluczy w playbookach. Zdefiniuj swoje hasło w yml.

dawny. pass: tajne lub

user:
  pass: secret
  name: fake

zaszyfruj swój plik z sekretami:

ansible-vault encrypt /path/to/credential.yml

ansible poprosi o hasło w celu zaszyfrowania. (wyjaśnię, jak korzystać z tej przepustki)

A potem możesz użyć swoich zmiennych, gdzie chcesz. Nikt nie może ich odczytać bez klucza skarbca.

Użycie klucza Vault:

poprzez przekazanie argumentu podczas uruchamiania programu Playbook.

--ask-vault-pass: secret

lub możesz zapisać do pliku takiego jak password.txt i gdzieś ukryć. (przydatne dla użytkowników CI)

--vault-password-file=/path/to/file.txt

W twoim przypadku: uwzględnij vars yml i użyj swoich zmiennych.

- include_vars: /path/credential.yml

  - name: Add deployment user
    action: user name={{user.name}} password={{user.pass}}
pmoksuz
źródło
Próbowałem dokładnie tego i to nie działa. password={{user.pass}}Wydaje mi się, że dzieje się tak dlatego, że rozszerzy się, aby uwzględnić rzeczywiste hasło, podczas gdy ansibl oczekuje tam skrótu.
texnic
2

Generowanie losowego hasła dla użytkownika

najpierw należy zdefiniować zmienną użytkownika, a następnie postępuj zgodnie z poniższymi instrukcjami

zadania:

- name: Generate Passwords
  become: no
  local_action: command pwgen -N 1 8
  with_items: '{{ users }}'
  register: user_passwords

- name: Update User Passwords
  user:
    name: '{{ item.item }}'
    password: "{{ item.stdout | password_hash('sha512')}}"
    update_password: on_create
  with_items: '{{ user_passwords.results }}'

- name: Save Passwords Locally
  become: no
  local_action: copy content={{ item.stdout }} dest=./{{ item.item }}.txt
  with_items: '{{ user_passwords.results }}'
Apuri Srikanth
źródło
1

Odpowiedź Mxx jest poprawna, ale crypt.crypt()metoda Pythona nie jest bezpieczna, gdy zaangażowane są różne systemy operacyjne (związane z algorytmem mieszania glibc używanym w twoim systemie).

Na przykład nie zadziała, jeśli wygenerujesz swój hash z MacOS i uruchomisz playbook w systemie Linux. W takim przypadku możesz użyć passlib ( pip install passlibaby zainstalować lokalnie).

from passlib.hash import md5_crypt
python -c 'import crypt; print md5_crypt.encrypt("This is my Password,salt="SomeSalt")'
'$1$SomeSalt$UqddPX3r4kH3UL5jq5/ZI.'
Joel B.
źródło
1

Żadne z rozwiązań nie działało bezpośrednio na moim Macu kontrolującym Ubuntu. Więc dla dobra innych, łącząc odpowiedzi Mxx i JoelB, oto aktualne rozwiązanie Python 3:

pip3 install passlib

python3 -c 'from passlib.hash import md5_crypt; \
      print(md5_crypt.encrypt("This is my Password", salt="SomeSalt"))'

Wynik będzie $1$SomeSalt$UqddPX3r4kH3UL5jq5/ZI., jak w odpowiedzi Mxx.

Jeszcze lepiej , użyj SHA512 zamiast MD5:

python3 -c 'from passlib.hash import sha512_crypt; \
      print(sha512_crypt.encrypt("This is my Password", salt="SomeSalt"))' 

Wynik:

$ 6 $ rund = 656000 $ SomeSalt $ oYpmnpZahIsvn5FK8g4bDFEAmGpEN114Fe6Ko4HvinzFaz5Rq2UXQxoJZ9ZQyQoi9zaBo3gBH / FEAov3FHv48

texnic
źródło
1

Stworzyłem poradnik ansible, który umożliwia utworzenie konta linux, które umożliwia uwierzytelnianie hasłem.

Zobacz CreateLinuxAccountWithAnsible .

Zaszyfrowane hasło jest generowane za pomocą mkpasswdpolecenia. Podałem sposoby instalacji mkpasswdw różnych systemach operacyjnych.

Oto kroki wymagane do użycia mojego skryptu:

  1. Zastąp <your_user_name>i <your_password>wewnątrz run.shżądaną nazwą użytkownika i hasłem.

  2. Zmień informacje o połączeniu w inventory, aby ansible mógł łączyć się z urządzeniem w celu utworzenia użytkownika.

  3. Uruchom, ./run.shaby wykonać skrypt.

Brian
źródło
1
Pliku nie ma już w serwisie GitHub.
Janus
1

Wypróbowałem wiele narzędzi, w tym mkpasswd, Python itp. Ale wygląda na to, że istnieje pewien problem ze zgodnością z Ansible w odczytywaniu wartości HASH generowanych przez inne narzędzia. Więc w końcu zadziałało przez samą wartość ansible #.

ansible all -i localhost, -m debug -a "msg = {{'yourpasswd' | password_hash ('sha512', 'mysecretsalt')}}"

Poradnik -

- name: User creation
  user: 
    name: username  
    uid: UID
    group: grpname
    shell: /bin/bash
    comment: "test user"
    password: "$6$mysecretsalt$1SMjoVXjYf.3sJR3a1WUxlDCmdJwC613.SUD4DOf40ASDFASJHASDFCDDDWERWEYbs8G00NHmOg29E0"
DjangoChained
źródło
0

Jeśli chcesz to zrobić jako polecenie ad-hoc Ansible, możesz wykonać następujące czynności:

$ password='SomethingSecret!'
$ ansible 192.168.1.10 -i some_inventory -b -m user -a "name=joe_user \
       update_password=always password=\"{{ \"$password\" | password_hash('sha512') }}\""

Wyjście z powyższego polecenia:

192.168.1.10 | SUCCESS => {
    "append": false,
    "changed": true,
    "comment": "Joe User",
    "group": 999,
    "home": "/home/joe_user",
    "move_home": false,
    "name": "joe_user",
    "password": "NOT_LOGGING_PASSWORD",
    "shell": "/bin/bash",
    "state": "present",
    "uid": 999
}
slm
źródło
0

Wiem, że spóźniłem się na imprezę, ale jest inne rozwiązanie, z którego korzystam. Może to być przydatne w przypadku dystrybucji, które nie mają --stdinkodu binarnego passwd.

- hosts: localhost
  become: True
  tasks:
    - name: Change user password
      shell: "yes '{{ item.pass }}' | passwd {{ item.user }}"
      loop:
       - { pass: 123123, user: foo }
       - { pass: asdf, user: bar }
      loop_control:
        label: "{{ item.user }}"

Etykieta w loop_controljest odpowiedzialna za wydrukowanie tylko nazwy użytkownika. Cały podręcznik lub tylko zmienne użytkownika (których możesz użyć vars_files:) powinny być zaszyfrowane za pomocą ansible-vault.

Alex Baranowski
źródło
0

Moje rozwiązanie wykorzystuje wyszukiwanie i automatyczne generowanie hasła.

---
- hosts: 'all'
  remote_user: root
  gather_facts: no
  vars:
    deploy_user: deploy
    deploy_password: "{{ lookup('password', '/tmp/password chars=ascii_letters') }}"

  tasks:
    - name: Create deploy user
      user:
        name: "{{ deploy_user }}"
        password: "{{ deploy_password | password_hash('sha512') }}"
alex naumov
źródło
-1

Cóż, jestem całkiem spóźniony na imprezę :) Miałem potrzebę gry ansiblowej, która tworzy wielu lokalnych użytkowników z losowymi hasłami. To co wymyśliłem, wykorzystałem kilka przykładów z góry i złożyłem je razem z kilkoma zmianami.

utwórz-użytkownika-z-hasłem.yml

---
# create_user playbook

- hosts: all
  become: True
  user: root
  vars:
#Create following user
   users:
    - test24
    - test25
#with group
   group: wheel
  roles:
    - create-user-with-password

/roles/create-user-with-password/tasks/main.yml

- name: Generate password for new user
  local_action: shell pwgen -s -N 1 20
  register: user_password
  with_items: "{{ users }}"
  run_once: true

- name: Generate encrypted password
  local_action: shell python -c 'import crypt; print(crypt.crypt( "{{ item.stdout }}", crypt.mksalt(crypt.METHOD_SHA512)))'
  register: encrypted_user_password
  with_items: "{{ user_password.results }}"
  run_once: true

- name: Create new user with group
  user:
    name: "{{ item }}"
    groups: "{{ group }}"
    shell: /bin/bash
    append: yes
    createhome: yes
    comment: 'Created with ansible'
  with_items:
    - "{{ users }}"
  register: user_created

- name: Update user Passwords
  user:
    name: '{{ item.0 }}'
    password: '{{ item.1.stdout }}'
  with_together:
    - "{{ users }}"
    - "{{ encrypted_user_password.results }}"
  when: user_created.changed

- name: Force user to change the password at first login
  shell: chage -d 0 "{{ item }}"
  with_items:
    - "{{ users }}"
  when: user_created.changed

- name: Save Passwords Locally
  become: no
  local_action: copy content={{ item.stdout }} dest=./{{ item.item }}.txt
  with_items: "{{ user_password.results }}"
  when: user_created.changed
Juhani
źródło