Создание нового пользователя и пароля с помощью Ansible


103

У меня есть доступная задача, которая создает нового пользователя в ubuntu 12.04;

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

он завершается, как ожидалось, но когда я вхожу в систему как этот пользователь и пытаюсь выполнить sudo с паролем, который я установил, он всегда говорит, что это неверно. Что я делаю не так?


1
Вы входите в систему с тем же паролем или ключами ssh? Вы проверили свой теневой файл, чтобы убедиться, что его содержимое соответствует ожиданиям? Также ваш passwordне должен быть в виде обычного текста, а скорее предварительно хеширован.
Mxx

мой пароль - открытый текст, могу я не использовать его таким образом? Я не понимаю, как его зашифровать, или мне это действительно нужно.
raphael_turtle

Ответы:


101

Если вы прочитали руководство по userмодулю Ansible , оно направит вас к репозиторию Ansible-examples на github для получения подробной информации о том, как использоватьpassword параметр .

Там вы увидите, что ваш пароль нужно хешировать.

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

Если ваш playbook или командная строка ansible содержат ваш пароль как есть в виде обычного текста, это означает, что ваш хэш пароля, записанный в теневом файле, неверен. Это означает, что когда вы пытаетесь аутентифицироваться со своим паролем, его хэш никогда не совпадет.

Кроме того, смотрите Ansible FAQ , чтобы узнать о некоторых нюансах параметра пароля и о том, как его правильно использовать.


25
Спасибо за чаевые. Я просто хотел указать, что документация по пользовательскому модулю, указанная выше, рекомендует использовать openssl passwd -salt <salt> -1 <plaintext>для генерации хэша пароля вместо однострочника Python, который у вас есть выше. У меня были проблемы с получением правильного вывода из Python, вероятно, из-за моей собственной некомпетентности, и команда openssl работала лучше.
Брендан Вуд

6
Как вы синхронизируете соль, которая будет использоваться с ОС?
Breedly

5
@Breedly: в этом нет необходимости - соль всегда хранится как часть пароля ($ 1 $ thesalt $ thepasswordhash), что означает, что она переносится между ОС с использованием одной и той же хэш-функции
Бенджамин Дейл,

3
Использование этой команды python для создания хеша у меня не сработало. Но я нашел хеш /etc/shadowпосле установки пароля вручную с помощью passwd <user>.
dokaspar

172

Возможно, я слишком поздно отвечу на это, но недавно я понял, что фильтры jinja2 могут обрабатывать генерацию зашифрованных паролей. В моем main.ymlя генерирую зашифрованный пароль как:

- 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" и "upassword" передаются как --extra-vars в playbook, и обратите внимание, что я использовал здесь фильтр jinja2, чтобы зашифровать переданный пароль.

Я добавил в свой блог ниже учебник, связанный с этим.


6
Чтобы избежать того, что элемент всегда «изменяется», вы можете добавить секретную «соль» в качестве второго параметра в password_hash.
Майкл Вайраз

11
Согласно предложению @ MichaelWyraz: добавление второго параметра «соли» позволяет избежать «изменено». Вы можете установить это через переменную, например password={{upassword|password_hash('sha512', upassword_salt)}}. Это позволяет вам помещать соль в хранилище переменных , как вы, вероятно, upasswordтоже сделали бы , не допуская их использования в tasks.yml.
user85461

Я бы также применил проверку состояния @ bbaassssiiee и добавил update_password: on_createв этот ответ пользовательский модуль, чтобы предотвратить истечение срока действия паролей для уже созданных пользователей.
madhead

Спасибо за отличный пример, который привел меня на правильный путь. Тем не менее, мне пришлось сделать еще несколько вещей, чтобы заставить его работать на Mac с доступной версией 2.8.2. Прежде всего на Mac невозможно использовать crypt, поэтому необходимо установить библиотеку passlib с расширением pip install passlib. Тогда , чтобы иметь возможность использовать встроенные хранилище зашифрована строки я должен был переформатировать со следующим дополнением: password: {{ upassword | string | password_hash('sha512') }}. Это позволяет избежать сообщения об ошибкеsecret must be unicode or bytes, not ansible.parsing.yaml.objects.AnsibleVaultEncryptedUnicode
Майкл

несмотря на использование этого метода для установки пароля: "{{my_password | string | password_hash ('sha512')}}", я все равно получу - [ПРЕДУПРЕЖДЕНИЕ]: вводимый пароль, похоже, не был хеширован. Аргумент «пароль» должен быть зашифрован для правильной работы этого модуля.
openCivilisation

46

Хочу предложить еще одно решение:

- 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

Почему лучше? Как уже было здесь отмечено, игры с Ansible должны быть идемпотентными. Вы должны думать о них не как о последовательности действий в императивном стиле, а как о желаемом состоянии, декларативном стиле. В результате вы должны иметь возможность запускать его несколько раз и получать тот же результат, то же состояние сервера.

Звучит все отлично, но есть нюансы. Один из них - управление пользователями. «Желаемое состояние» означает, что каждый раз, когда вы запускаете игру, в которой создается пользователь, он будет обновляться, чтобы соответствовать именно этому состоянию. Под "обновленным" я подразумеваю, что его пароль тоже будет изменен. Но, скорее всего, это не то, что вам нужно. Обычно вам нужно создать пользователя, установить и истечь его пароль только один раз, дальнейшие запуски игры не должны обновлять его пароль.

К счастью, update_passwordв userмодуле Ansible есть атрибут , решающий эту проблему. Смешивая это с зарегистрированными переменными, вы также можете истечь его пароль только тогда, когда пользователь действительно обновлен.

Обратите внимание, что если вы вручную измените оболочку пользователя (предположим, вам не нравится оболочка, которую злой администратор заставил в своей игре), пользователь будет обновлен, поэтому его пароль будет истек.

Также обратите внимание, как вы можете легко использовать начальные пароли в виде обычного текста в играх. Нет необходимости кодировать их где-то еще и вставлять хеши, для этого можно использовать фильтр Jinja2 . Однако это может быть недостатком безопасности, если кто-то случайно войдет в систему до того, как вы это сделаете.


3
Я не мог заставить другое решение работать на меня. Все же ваш ответ прост и сработал. Я хотел бы дать вам 5 голосов, если можно.
leesei

Я не хочу, чтобы мой пароль был жестко запрограммирован таким образом :( Можно ли вытащить его из хранилища ansible и ввести здесь? Вложение вроде "{{ '{{vaulted_password}}' | password_hash('sha512') }}"не работает ...
dokaspar

Вы пробовали {{ vaulted_password | password_hash('sha512') }}, где vaulted_passwordключ к значению в хранилище?
madhead

update_password: on_createпохоже, не работает (есть открытая ошибка с 2017 года), поэтому пароли будут меняться каждый раз, когда происходит изменение состояния пользователя.
Дити

11

Модуль Ansible «user» управляет пользователями идемпотентным образом. В сборнике пьес ниже первая задача объявляет состояние = присутствует для пользователя. Обратите внимание, что ' register: newuser ' в первом действии помогает второму действию определить, является ли пользователь новым (newuser.changed == True) или существующим (newuser.changed==False ), чтобы сгенерировать пароль только один раз.

В сборнике Ansible есть:

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

У меня работает только одно решение с паролем хранилища. Большое тебе спасибо.
Денис Савенко

по крайней мере, последние дистрибутивы на основе Debian, похоже, не поддерживают длинную опцию GNU «--stdin» для двоичного файла passwd.
XXL

10

попробуй вот так

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
Мне нравится это решение, поскольку оно позволяет вводить пароль при запуске скрипта. Хорошее решение для сценария начальной загрузки, который не следует запускать каждый раз. Однако для Ubuntu я использовал sha512_crypt.
Gunnar

6

Цель роли в этом ответе - сгенерировать случайный пароль для new_user_name и немедленно истечь срок действия пароля. New_user_name требуется для изменения пароля при его первом входе в систему.

create_user.yml:

---
# create_user playbook

- hosts: your_host_group
  become: True
  user: ansible

  roles:
    - create_user

роли / create_user / tasks / 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

Если вы хотите создать нового пользователя:

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

3

Это простой способ:

---
- 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: всегда будет сообщать об изменении.
bbaassssiiee

@datasmid, вы можете добавить опцию no_log: True docs.ansible.com/ansible/…
Фил Паффорд

3

Вот как это сработало для меня

- 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

Для полноты картины я опубликую специальную команду с использованием ansible, поскольку там тоже есть уловка.

Сначала попробуйте сгенерировать зашифрованный пароль с помощью утилиты mkpasswd, доступной в большинстве систем Linux:

mkpasswd --method=SHA-512

Затем попробуйте команду ansible ad-hock:

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

Но убедитесь:

  1. Команда заключена в одинарные кавычки, а НЕ в двойные, иначе ваш пароль никогда не будет работать.
  2. Вы запускаете его с помощью --sudoили получаете ошибку, например ( useradd: cannot lock /etc/passwd; try again later)

спасибо, дружище, я специально искал специальную версию, и у меня
возникла та


2

Объединив несколько вышеперечисленных решений, я создал playbook, который автоматически генерирует правильные хэши паролей на основе паролей в виде открытого текста, хранящихся в зашифрованном локальном доступном файле хранилища:

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

Выполните эту команду, используя параметр «--ask-vault-pass», чтобы расшифровать файл хранилища (см. Ansible-vault для получения информации о том, как управлять зашифрованным хранилищем).


2

Как создать зашифрованный пароль для перехода к passwordvar в userзадачу Ansible (из комментария @Brendan Wood):

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

Результат будет выглядеть так:

$1$some_pla$lmVKJwdV3Baf.o.F0OOy71

Пример userзадачи:

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

UPD: шифрование с использованием SHA-512 смотрите здесь и здесь :

Python

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

Рубин

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

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

1
Разве это не генерирует хешированный пароль md5? Разве это не небезопасно?
Марк

2

Вы можете использовать ansible-vault для использования секретных ключей в playbooks. Задайте свой пароль в yml.

напр. пройти: секрет или

user:
  pass: secret
  name: fake

зашифруйте свой файл секретов с помощью:

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

ansible запросит пароль для его шифрования. (я объясню, как использовать этот пропуск)

И тогда вы можете использовать свои переменные где хотите. Никто не может их прочитать без ключа хранилища.

Использование ключа хранилища:

через передачу аргумента при запуске playbook.

--ask-vault-pass: secret

или вы можете сохранить в файл, например password.txt, и где-нибудь спрятать. (полезно для пользователей CI)

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

В вашем случае: включите vars yml и используйте свои переменные.

- include_vars: /path/credential.yml

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

Я пробовал именно это, и это не работает. Я считаю, что это потому, что он password={{user.pass}}будет расширен, чтобы включить фактический пароль, в то время как ansible ожидает там хеша.
texnic 05

2

Генерация случайного пароля для пользователя

сначала необходимо определить переменную пользователя, а затем следовать ниже

задачи:

- 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

Ответ Mxx правильный, но crypt.crypt()метод python небезопасен, когда задействованы разные операционные системы (связано с хеш-алгоритмом glibc, используемым в вашей системе).

Например, это не сработает, если вы сгенерируете свой хеш из MacOS и запустите playbook на Linux. В таком случае вы можете использовать passlib ( pip install passlibдля локальной установки).

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

Ни одно из решений не работало непосредственно на моем Mac, управляющем Ubuntu. Итак, для других, объединяя ответы Mxx и JoelB, вот текущее решение Python 3:

pip3 install passlib

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

Результат будет $1$SomeSalt$UqddPX3r4kH3UL5jq5/ZI., как в ответе Mxx.

Еще лучше использовать SHA512 вместо MD5:

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

Результат:

6 $ раундов = 656000 $ SomeSalt $ oYpmnpZahIsvn5FK8g4bDFEAmGpEN114Fe6Ko4HvinzFaz5Rq2UXQxoJZ9ZQyQoi9zaBo3gBH / FEAov3FHv48


1

Я создал ansible-playbook, который позволяет вам создать учетную запись linux, которая разрешает аутентификацию по паролю.

См. CreateLinuxAccountWithAnsible .

Хешированный пароль генерируется с помощью mkpasswdкоманды. Я предоставил способы установки mkpasswdв разных операционных системах.

Вот шаги, необходимые для использования моего скрипта:

  1. Замените <your_user_name>и <your_password>внутри run.shжелаемым именем пользователя и паролем.

  2. Измените информацию о подключении, inventoryчтобы ansible мог подключиться к машине для создания пользователя.

  3. Выполнить, ./run.shчтобы выполнить сценарий.


1
Файла больше нет на GitHub.
Янус

1

Пробовал много утилит, включая mkpasswd, Python и т. Д. Но похоже, что есть некоторая проблема совместимости с Ansible при чтении значений HASH, созданных другими инструментами. Итак, наконец, он работал с самим значением ansible #.

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

Пособие -

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

0

Если вы хотите выполнить это как специальную команду Ansible, вы можете сделать следующее:

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

Вывод из приведенной выше команды:

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

Я знаю, что опаздываю на вечеринку, но есть другое решение, которое я использую. Это может быть удобно для дистрибутивов, у которых нет --stdinдвоичного файла 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 }}"

Этикетка в loop_controlотвечает за печать только имени пользователя. Вся playbook или только пользовательские переменные (вы можете использовать vars_files:) должны быть зашифрованы с помощью ansible-vault.


0

Мое решение использует поиск и автоматическое создание пароля.

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

-1

Ну, я совсем опоздал на вечеринку :) Мне нужна была игра, которая создает несколько локальных пользователей со случайными паролями. Это то, что я придумал, использовал несколько примеров сверху и собрал их вместе с некоторыми изменениями.

создать-пользователя-с-паролем.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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.