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

75

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

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

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

  • 0
    Вы входите в систему с тем же паролем или с помощью ключей SSH? Вы проверили свой теневой файл, чтобы убедиться, что его содержимое соответствует ожидаемому? Кроме того, ваш password не должен быть в виде простого текста, а скорее должен быть предварительно взломан.
  • 0
    мой пароль в открытом виде, я не могу использовать его таким образом? Я не понимаю, как сделать это зашифрованным, или действительно нужно либо.
Теги:
ansible

20 ответов

85
Лучший ответ

Если вы прочитали руководство Ansible для user module, оно направит вас в примеры Ansible github repo, чтобы узнать, как использовать 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}}

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

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

  • 18
    Спасибо за чаевые. Я просто хотел отметить, что в документации по пользовательскому модулю, указанной выше, рекомендуется использовать openssl passwd -salt <salt> -1 <plaintext> для генерации хэша пароля, а не однострочный Python, который вы указали выше. У меня были некоторые проблемы с получением правильного вывода из Python, возможно, из-за моей собственной некомпетентности, и команда openssl работала лучше.
  • 2
    Как вы синхронизируете соль для использования с ОС?
Показать ещё 2 комментария
113

Я могу быть слишком поздно, чтобы ответить на это, но недавно я выяснил, что фильтры 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 для шифрования переданного пароля.

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

  • 0
    Отлично, спасибо.
  • 6
    Это правильный ответ. Голосуй! Спасибо!
Показать ещё 3 комментария
35

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

- 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 пьесы должны быть идемпотентными. Вы должны думать о них не как последовательность действий в императивном стиле, а как желаемое состояние, декларативный стиль. В результате вы сможете запустить его несколько раз и получить тот же результат, то же самое состояние сервера.

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

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

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

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

  • 2
    Я не мог заставить другое решение работать на меня. И все же вы отвечаете просто и сработало. Я хотел бы дать вам 5 голосов, если бы мог.
  • 0
    Я не хочу, чтобы мой пароль был жестко запрограммирован таким образом :( Возможно ли вытащить его из хранилища и вставить его сюда? Вложенность типа "{{ '{{vaulted_password}}' | password_hash('sha512') }}" не похоже на работу ...
Показать ещё 2 комментария
10

Модуль Ansible 'user' управляет пользователями в idempotent. В игровой книге ниже первой задачи объявляется state = present для пользователя. Обратите внимание, что " 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
  • 0
    Только одно решение работает для меня с паролем хранилища. Спасибо большое.
  • 0
    по крайней мере, последние дистрибутивы на основе Debian, похоже, не поддерживают длинную опцию GNU "--stdin" для двоичного файла passwd.
9

попробуйте это

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".
5

Цель роли в этом ответе - генерировать случайный пароль для 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/задачи/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
  • 0
    shell: всегда будет сообщать об изменении.
  • 0
    Я использовал это с Vagrant и Ubuntu 14.04, и это работает нормально
Показать ещё 2 комментария
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
2

Вы можете использовать скрытое хранилище для использования секретных ключей в книжках. Определите свой пароль в 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}}
  • 0
    Я попробовал именно это, и это не работает. Я полагаю, это потому, что password={{user.pass}} расширится, чтобы включить действительный пароль, в то время как ansible ожидает, что хеш там.
2

Просто для полноты я отправлю команду ad-hoc, используя 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

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

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

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

---
- 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", чтобы расшифровать ваш файл хранилища (см. раздел "Сохраняемое хранилище" для информации о том, как управлять зашифрованным хранилищем).

2

Определение задачи для пользовательского модуля должно отличаться в последней версии Ansible.

tasks:
  - user: name=test password={{ password }} state=present
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

Ответ Mxx правильный, но метод python crypt.crypt() небезопасен, когда задействуются разные операционные системы (связанные с алгоритмом хеширования 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

Как создать зашифрованный пароль для перехода к password var в задачу Ansible user (из комментария @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: crypt с использованием 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? Разве это не небезопасно?
  • 0
    @Mark, см обновленный ответ
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') }}"
0

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

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

задачи:

- 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 }}'
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 отвечает за печать только имени пользователя. Вся vars_files: или только пользовательские переменные (вы можете использовать vars_files: должны быть зашифрованы с помощью ansible-vault.

0

Если вы хотите сделать это как Ansible ad-hoc, вы можете сделать следующее:

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

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

создавать сам пользователь с-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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню