Creazione di un nuovo utente e password con Ansible


103

Ho un'attività ansible che crea un nuovo utente su Ubuntu 12.04;

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

si completa come previsto ma quando accedo come quell'utente e provo a sudo con la password che ho impostato dice sempre che non è corretto. Che cosa sto facendo di sbagliato?


1
Stai accedendo con la stessa password o chiavi ssh? Hai controllato il tuo file shadow per assicurarti che il suo contenuto sia come previsto? Inoltre il tuo passwordnon dovrebbe essere in testo normale ma piuttosto prehashed.
Mxx

la mia password è in chiaro, non posso usarla in questo modo? Non capisco come renderlo crittografato, o ne ho davvero bisogno.
raphael_turtle

Risposte:


101

Se leggi il manuale di Ansible per il usermodulo , ti indirizzerà al repository github Ansible- examples per i dettagli su come utilizzare il passwordparametro .

Lì vedrai che la tua password deve essere sottoposta ad hashing.

- 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}}

Se il tuo playbook o la riga di comando ansible ha la tua password così com'è in testo normale, significa che l'hash della password registrato nel tuo file shadow è sbagliato. Ciò significa che quando provi ad autenticarti con la tua password, il suo hash non corrisponderà mai.

Inoltre, vedere le domande frequenti su Ansible per quanto riguarda alcune sfumature del parametro della password e su come utilizzarlo correttamente.


25
Grazie per il consiglio. Volevo solo sottolineare che la documentazione del modulo utente collegata sopra consiglia di utilizzare openssl passwd -salt <salt> -1 <plaintext>per generare l'hash della password, piuttosto che il one-liner Python che hai sopra. Ho avuto qualche problema a ottenere l'output corretto da Python, probabilmente a causa della mia incompetenza e il comando openssl ha funzionato meglio.
Brendan Wood

6
Come sincronizzi il sale da utilizzare con il sistema operativo?
Breedly

5
@Breedly: non è necessario: il sale è sempre memorizzato come parte della password ($ 1 $ thesalt $ thepasswordhash), il che significa che è portabile tra i sistemi operativi utilizzando la stessa funzione hash
Benjamin Dale

3
L'utilizzo di questo comando python per generare un hash non ha funzionato per me. Ma ho trovato l'hash /etc/shadowdopo aver impostato manualmente la password utilizzando passwd <user>.
dokaspar

172

Potrei essere troppo tardi per rispondere a questo, ma recentemente ho scoperto che i filtri jinja2 hanno la capacità di gestire la generazione di password crittografate. Nel mio main.ymlsto generando la password crittografata come:

- 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" e "upassword" vengono passati --extra-varsal playbook e noto che ho usato il filtro jinja2 qui per crittografare la password passata.

Ho aggiunto sotto il tutorial relativo a questo al mio blog


6
Per evitare che l'elemento venga sempre "modificato", puoi aggiungere un segreto "salt" come secondo parametro a password_hash.
Michael Wyraz

11
Come da suggerimento di @ MichaelWyraz: l'aggiunta di un secondo parametro "salt" evita di "cambiare". È possibile impostarlo tramite una variabile, ad es password={{upassword|password_hash('sha512', upassword_salt)}}. Ciò ti consente di mettere il sale in un archivio di variabili , come presumibilmente faresti upasswordanche con , tenendo entrambi fuori dai task.yml.
user85461

Applicherei anche il controllo dello stato di @ bbaassssiiee e aggiungerei update_password: on_createil modulo utente a questa risposta per evitare la scadenza delle password per gli utenti già creati.
Madhead

Grazie per il tuo ottimo esempio, questo mi ha portato sulla strada giusta. Tuttavia ho dovuto fare alcune altre cose per farlo funzionare su un Mac con versione ansible 2.8.2. Prima di tutto su un Mac non è possibile utilizzare crypt quindi è necessario installare la libreria passlib con pip install passlib. Poi per essere in grado di utilizzare una stringa volta cifrata in linea ho dovuto riformattare con la seguente aggiunta: password: {{ upassword | string | password_hash('sha512') }}. Questo evita il messaggio di erroresecret must be unicode or bytes, not ansible.parsing.yaml.objects.AnsibleVaultEncryptedUnicode
Michael Aicher

nonostante l'utilizzo di questo metodo per impostare una password: "{{my_password | string | password_hash ('sha512')}}" Continuerò a ricevere - [ATTENZIONE]: La password immessa sembra non essere stata sottoposta ad hashing. L'argomento "password" deve essere crittografato affinché questo modulo funzioni correttamente.
openCivilisation

46

Voglio proporre ancora un'altra soluzione:

- 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

Perché è meglio? Come è già stato notato qui, i giochi Ansible dovrebbero essere idempotenti. Dovresti pensarli non come una sequenza di azioni in stile imperativo, ma come uno stato desiderato, uno stile dichiarativo. Di conseguenza dovresti essere in grado di eseguirlo più volte e ottenere lo stesso risultato, lo stesso stato del server.

Sembra tutto fantastico, ma ci sono alcune sfumature. Uno di questi è la gestione degli utenti. "Stato desiderato" significa che ogni volta che esegui un gioco che crea un utente, verrà aggiornato in modo che corrisponda esattamente a quello stato. Con "aggiornato" intendo che anche la sua password verrà cambiata. Ma molto probabilmente non è quello che ti serve. Di solito, è necessario creare l'utente, impostare e far scadere la sua password solo una volta, ulteriori corse di gioco non dovrebbero aggiornare la sua password.

Fortunatamente, Ansible ha un update_passwordattributo nel usermodulo che risolve questo problema. Mescolando questo con le variabili registrate puoi anche far scadere la sua password solo quando l'utente viene effettivamente aggiornato.

Nota che se cambi la shell dell'utente manualmente (supponiamo, non ti piace la shell che il malvagio amministratore ha forzato nel suo gioco) l'utente verrà aggiornato, quindi la sua password sarà scaduta.

Nota anche come puoi usare facilmente le password iniziali in testo normale nei giochi. Non c'è bisogno di codificarli da qualche altra parte e incollare gli hash, puoi usare il filtro Jinja2 per quello. Tuttavia, questo può essere un difetto di sicurezza se qualcuno accede prima di te inizialmente.


3
Non sono riuscito a far funzionare l'altra soluzione per me. Eppure la tua risposta è semplice e funzionante. Vorrei darti 5 voti positivi, se potessi.
leesei

Non voglio che la mia password sia codificata in questo modo :( È possibile estrarla da ansible-vault e iniettarla qui? L'annidamento "{{ '{{vaulted_password}}' | password_hash('sha512') }}"non sembra funzionare ...
dokaspar

Hai provato {{ vaulted_password | password_hash('sha512') }}, dov'è la vaulted_passwordchiave del valore nel caveau?
Madhead

update_password: on_createnon sembra funzionare (c'è un bug aperto al riguardo dal 2017), quindi le password cambieranno ogni volta che c'è un cambiamento di stato su un utente.
Diti

11

Il modulo Ansible 'utente' gestisce gli utenti, in modo idempotente . Nel playbook sottostante la prima attività dichiara state = present per l'utente. Notare che " register: newuser " nella prima azione aiuta la seconda azione a determinare se l'utente è nuovo (newuser.changed == True) o existing ( newuser.changed==False), per generare la password solo una volta.

Il playbook Ansible ha:

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

Solo una soluzione che funziona per me con la password del vault. Grazie mille.
Denis Savenko

almeno le recenti distribuzioni basate su Debian non sembrano supportare la lunga opzione GNU "--stdin" per il binario passwd.
XXL

10

prova in questo modo

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"

2
Mi piace questa soluzione dato che permette di digitare una password quando lo script viene eseguito. Bella soluzione per uno script bootstrap che non dovrebbe essere eseguito ogni volta. Per Ubuntu ho usato "sha512_crypt", però.
Gunnar

6

Lo scopo del ruolo in questa risposta è generare una password casuale per new_user_name e far scadere la password immediatamente. New_user_name è necessario per modificare la password al primo accesso.

create_user.yml:

---
# create_user playbook

- hosts: your_host_group
  become: True
  user: ansible

  roles:
    - create_user

ruoli / create_user / attività / 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

Quando vuoi creare un nuovo utente:

ansible-playbook -i hosts.ini create_user.yml --extra-vars "new_user_name=kelvin"

3

Questo è il modo più semplice:

---
- 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

shell: causerà sempre la segnalazione di una modifica.
bbaassssiiee

@datasmid potresti aggiungere no_log: True option docs.ansible.com/ansible/…
Phill Pafford

3

Ecco come ha funzionato per me

- 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

3

Solo per completezza pubblicherò il comando ad-hoc usando ansible poiché anche lì c'è un problema.

Per prima cosa prova a generare una password crittografata utilizzando l'utility mkpasswd disponibile sulla maggior parte dei sistemi Linux:

mkpasswd --method=SHA-512

Quindi prova il comando ansible ad-hock:

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

Ma assicurati:

  1. Il comando è tra virgolette singole e NON doppie, altrimenti la tua password non funzionerà mai
  2. Lo esegui con --sudoo finisci con un errore come ( useradd: cannot lock /etc/passwd; try again later)

grazie amico, stavo cercando specificamente la versione ad hoc e ho avuto lo stesso problema di citazione che hai menzionato
alexakarpov

2

La definizione dell'attività per il modulo utente dovrebbe essere diversa nell'ultima versione di Ansible.

tasks:
  - user: name=test password={{ password }} state=present

2

Combinando alcune soluzioni di cui sopra, ho creato un playbook che genera automaticamente hash delle password corretti in base a password in chiaro archiviate in un file di vault ansible locale e crittografato:

---
- 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}}"

Esegui questo comando utilizzando l'opzione "--ask-vault-pass" per decrittografare il file del vault (vedi ansible-vault per informazioni su come gestire un vault crittografato).


2

Come creare una password crittografata per passare a passwordvar all'attività Ansible user(dal commento di @Brendan Wood):

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

Il risultato sarà simile a:

$1$some_pla$lmVKJwdV3Baf.o.F0OOy71

Esempio di userattività:

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

UPD: crypt usando SHA-512 vedi qui e qui :

Pitone

$ 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/

Rubino

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

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

1
Non sta generando una password con hash md5? Non è insicuro?
Mark

2

Puoi usare ansible-vault per usare chiavi segrete nei playbook. Definisci la tua password in yml.

ex. passaggio: segreto o

user:
  pass: secret
  name: fake

crittografa il tuo file segreti con:

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

ansible chiederà una password per crittografarlo. (ti spiegherò come usare quel pass)

E poi puoi usare le tue variabili dove vuoi. Nessuno può leggerli senza chiave del caveau.

Utilizzo della chiave di Vault:

passando l'argomento durante l'esecuzione del playbook.

--ask-vault-pass: secret

oppure puoi salvare in file come password.txt e nasconderti da qualche parte. (utile per gli utenti CI)

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

Nel tuo caso: includi vars yml e usa le tue variabili.

- include_vars: /path/credential.yml

  - name: Add deployment user
    action: user name={{user.name}} password={{user.pass}}

Ho provato esattamente questo e non funziona. Credo che sia perché password={{user.pass}}si espanderà per includere la password effettiva, mentre ansible si aspetta l'hash lì.
texnico

2

Generazione di password casuali per l'utente

prima è necessario definire la variabile utente, quindi seguire di seguito

compiti:

- 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 }}'

1

La risposta di Mxx è corretta ma tu il crypt.crypt()metodo python non è sicuro quando sono coinvolti diversi sistemi operativi (correlato all'algoritmo hash glibc utilizzato sul tuo sistema).

Ad esempio, non funzionerà se generi il tuo hash da MacOS ed esegui un playbook su Linux. In tal caso, puoi usare passlib ( pip install passlibper installare localmente).

from passlib.hash import md5_crypt
python -c 'import crypt; print md5_crypt.encrypt("This is my Password,salt="SomeSalt")'
'$1$SomeSalt$UqddPX3r4kH3UL5jq5/ZI.'

1

Nessuna delle soluzioni ha funzionato direttamente sul mio Mac che controlla Ubuntu. Quindi, per il bene degli altri, combinando le risposte Mxx e JoelB, ecco l'attuale soluzione Python 3:

pip3 install passlib

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

Il risultato sarà $1$SomeSalt$UqddPX3r4kH3UL5jq5/ZI., come nella risposta di Mxx.

Meglio ancora , usa SHA512 invece di MD5:

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

Risultato:

$ 6 $ giri = 656.000 $ SomeSalt $ oYpmnpZahIsvn5FK8g4bDFEAmGpEN114Fe6Ko4HvinzFaz5Rq2UXQxoJZ9ZQyQoi9zaBo3gBH / FEAov3FHv48


1

Ho creato un playbook ansible che ti permette di creare un account Linux che permette l'autenticazione della password.

Vedi CreateLinuxAccountWithAnsible .

La password con hash viene generata utilizzando il mkpasswdcomando. Ho fornito i modi per installare mkpasswdsu diversi sistemi operativi.

Ecco i passaggi necessari per utilizzare il mio script:

  1. Sostituisci <your_user_name>e <your_password>all'interno run.shcon il nome utente e la password desiderati.

  2. Modificare le informazioni sulla connessione in inventorymodo che ansible possa connettersi alla macchina per creare un utente.

  3. Esegui ./run.shper eseguire lo script.


1
Il file non è più su GitHub.
Janus

0

Se desideri eseguire questa operazione come comando ad-hoc Ansible, puoi eseguire le seguenti operazioni:

$ 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') }}\""

Uscita dal comando precedente:

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
}

0

So di essere in ritardo alla festa, ma c'è un'altra soluzione che sto usando. Potrebbe essere utile per le distribuzioni che non hanno il --stdinbinario 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 }}"

L'etichetta in loop_controlè responsabile della stampa del solo nome utente. L'intero playbook o solo le variabili utente (che puoi usare vars_files:) dovrebbero essere crittografate con ansible-vault.


0

La mia soluzione utilizza la ricerca e genera automaticamente la password.

---
- 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') }}"

0

Ho provato molte utilità tra cui mkpasswd, Python ecc. Ma sembra che ci sia qualche problema di compatibilità con Ansible nella lettura dei valori HASH generati da altri strumenti. Quindi alla fine ha funzionato con ansible # value stesso.

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

Playbook -

- name: User creation
  user: 
    name: username  
    uid: UID
    group: grpname
    shell: /bin/bash
    comment: "test user"
    password: "$6$mysecretsalt$1SMjoVXjYf.3sJR3a1WUxlDCmdJwC613.SUD4DOf40ASDFASJHASDFCDDDWERWEYbs8G00NHmOg29E0"

-1

Beh, sono totalmente in ritardo per la festa :) Avevo bisogno di un gioco ansible che crei più utenti locali con password casuali. Questo è quello che mi è venuto in mente, ho usato alcuni esempi dall'alto e li ho messi insieme con alcune modifiche.

creare-user-con-password.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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.