У меня есть одна задача, которая создает нового пользователя на ubuntu 12.04;
- name: Add deployment user
action: user name=deployer password=mypassword
он завершается так, как ожидалось, но когда я вхожу в систему в качестве этого пользователя и пытаюсь использовать пароль, который я установил, он всегда говорит, что он неверен. Что я делаю неправильно?
Если вы прочитали руководство 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 относительно некоторых нюансов параметра пароля и того, как правильно его использовать.
openssl passwd -salt <salt> -1 <plaintext>
для генерации хэша пароля, а не однострочный Python, который вы указали выше. У меня были некоторые проблемы с получением правильного вывода из Python, возможно, из-за моей собственной некомпетентности, и команда openssl работала лучше.
Я могу быть слишком поздно, чтобы ответить на это, но недавно я выяснил, что фильтры 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 для шифрования переданного пароля.
Я добавил ниже учебник, связанный с этим в мой блог
Я хочу предложить еще одно решение:
- 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. Однако это может быть недостатком безопасности, если кто-то случайно заходит в систему, прежде чем вы это сделаете.
"{{ '{{vaulted_password}}' | password_hash('sha512') }}"
не похоже на работу ...
Модуль 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
попробуйте это
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"
Цель роли в этом ответе - генерировать случайный пароль для 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"
Это простой способ:
---
- 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
Вот как это сработало для меня
- 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
Вы можете использовать скрытое хранилище для использования секретных ключей в книжках. Определите свой пароль в 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 ожидает, что хеш там.
Просто для полноты я отправлю команду 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
)Объединив несколько решений сверху, я создал учебник, который автоматически генерирует правильные хэши паролей на основе паролей открытого текста, хранящихся в зашифрованном локальном файле незаменимых хранилищ:
---
- 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.
tasks:
- user: name=test password={{ password }} state=present
Ни один из решений не работал непосредственно на моем 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
Ответ 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.'
Как создать зашифрованный пароль для перехода к 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 -c "import crypt, getpass, pwd; print crypt.crypt('password', '\$6\$saltsalt\$')"
$6$saltsalt$qFmFH.bQmmtXzyBY0s9v7Oicd2z4XSIecDzlB5KiA2/jctKu9YterLp8wwnSq.qc.eoxqOmSuNp2xS0ktL3nh/
$ 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/
Мое решение использует поиск и автоматически генерировать пароль.
---
- 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') }}"
Генерация случайного пароля для пользователя
сначала нужно определить переменную пользователя, а затем следовать ниже
задачи:
- 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 }}'
Я знаю, что опаздываю на вечеринку, но я использую другое решение. Это может быть полезно для дистрибутивов, у которых нет --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.
Если вы хотите сделать это как 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
}
Ну, я совсем опоздал на вечеринку :) У меня была потребность в умелой игре, которая создает нескольких локальных пользователей с случайными паролями. Это то, что я придумал, использовал некоторые примеры сверху и соединил их с некоторыми изменениями.
создавать сам пользователь с-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
password
не должен быть в виде простого текста, а скорее должен быть предварительно взломан.