Рефакторинг роли и файлов переменных для управления учетными записями на группах хостов

1,00
р.
Общая ситуация
Есть отдел из N различных сотрудников + M бездушных машин (типа сервера интеграции). Есть множество хостов. Часть используются для тестов, другие на бою, те и те можно группировать по выполняемым задачам. Нужно управлять доступом пользователей к хостам, сохраняя конфигурацию в одном месте. Может быть необходимо:
Предоставить пользователю доступ к хосту или группе, создавая в системе пользователя и регистрируя ssh-ключ. Отозвать доступ, например удаляя ssh-ключ, Включить или отключить sudo, Ограничить sudo, Включить или отключить NOPASSWD.

Текущее решение
Сейчас для регистрации пользователей я использую такую схему (пока что пробую всего на двух хостах и двух пользователях):
Собственный плейбук и роль, в котором используются стандартные модули:
user (создает пользователя, может передать хэш пароля, создаваемый через passwd --method=SHA-512) authorized_key (нужный публичный ключ добавляется в .ssh/authorized_hosts создаваемого пользователя) Плюс собственная задача, которая создает /etcudoers.d/username: copy: content: "{{ item.key }} ALL=(ALL) NOPASSWD:ALL" dest: "/etcudoers.d/{{ item.key }}" owner: root group: root mode: 0400 with_dict: "{{ users_list }}" when: users_list is defined become: true
Общие файлы inventory (те же, что и для других плейбуков) Файлы group_vars/hostname.yaml, в которых хранятся публичные ключи и хеши паролей пользователей. Хранятся они в виде словаря: users_list: username: ssh_key: "ssh-rsa ..." password: "$6$..." comment: "User Name"

Такая реализация вынуждает меня для каждого хоста или группы хостов хранить отдельный документ, в котором повторяются данные по пользователям. Это невероятно усложняет поддержку.
Желаемый результат
Я бы хотел реализовать это примерно в таком виде:
Файл user_credentials.yaml, один на всех:
user_credentials: username: ssh_key: "ssh-rsa ..." password: "$6$..." comment: "User Name" username_2: ...
В каждом group_vars/hostname.yaml:
users_list: username: sudoer: yes nopasswd: yes username_2: sudoer: yes nopasswd: no some_fired_employee: state: absent
Теперь когда права меняются, нужно просто поменять конфиг в одном месте и выполнить плейбук на нужной группе хостов.
Проблема
Не понимаю, как писать конкретные таски, чтобы они забирали значения из нужных файлов. Как-то надо сформировать на ходу словарь, в котором будут данные из user_credentials.yaml, отфильтрованные по признаку того, что пользователь есть в users_list, объединенные с данными из users_list.

Ответ
Точности в то решение, которое видится вам идеальным написать может быть и реально, но оно точно будет громоздким из-за вложенности lookup'ов и проверки различных условий.
Зато если немного подкорректировать ваше видение идеального решения, то можно обойтись легким и изящным решением. И уж точно оно будет проще, чем текущее.
Давайте я попробую предложить несколько мелких кубиков, из которых вы без труда подберёте наиболее подходящее для вас решение.

Преставьте, что у вас есть папка files\peoples\ в которой лежат папки ivanov и petrov. В папке ivanov два файла: key.pub и pass.txt
В файлах хоста у нас будет записи типа:
ans_users: - user: username: ivanov ssh_key_file: "files/people/ivanov/key.pub" password_file: "files/people/ivanov/pass.txt" - user: username: petrov ssh_key_file: "files/people/petrov/key.pub" password_file: "files/people/petrov/pass.txt"
А создавать учётки мы будем простым скриптом:
- name: adding users user: name={{ item.username}} password="{{ lookup('file', '"files/people/{{ item.username }}/key.pub"') }}" with_items: - "{{ ans_users }}"
- name: add ssh keys authorized_key: user={{ item.username}} key="{{ lookup('file', '{{ item.ssh_key_file }}') }}" state=present with_items: - "{{ ans_users }}"
Согласитесь, что мы уже намного улучшили читаемость скрипта за счёт того, что имя файла читаемее, чем sha512_hash.
Давайте попробуем понять, насколько вы готовы пожертвовать сверхцентрализацией. У вас нет никакого централизованного конфиг-файла user_credentials.yaml, который бы описывал всех пользователей. На мой взгляд -- невелика и потеря: этот файл вообще не был нужен изначально и лучшим доказательством этого служит тот факт, что конфиги хостов у меня получились точно такими же, как и в вашем идеальном решении. Эта сверхцентрализация -- излишне жёсткая вещь и тут она бесполезна.

Двигаемся рефакторить дальше. Мы упростили создание пользователей и управление их ключами, дальше нужно разобраться с тем, как мы будем управлять sudo.
Предварительно пару слов о best practice. Вместо того, чтобы модулем lineinfile ковырять постоянно файл sudoers рекомендуется управлять группами пользователей. Вам понадобится всего две группы: sudo с паролем и passwordless sudo. Разово настроили и забыли.
Я предлагаю вместо ДВУХ параметров (sudoers, password) пользователям в конфиг-файле просто прописывать ОДИН параметр - группы пользователя. Конфиг становится компактнее, читаемее. Код задания тоже сильно упрощается.

Дальше мы рассмотрим вопросы модификации прав, в особенности -- удаление.
Добавление нового пользователя -- тривиально Модификация паролей, ключей, sudo -- тривиально Убрать права из одной группы хостов -- держим в files\people два файла с ключом от которого пароль никто не знает и хэш неизвестного никому пароля: достаточно в конфиге увидеть ssh_key_file: "files/people/null_key.pub" и сразу будет понятно, что этот пользователь на эту группу хостов уже не зайдёт Увольнение сотрудника -- шагом номер раз убираем права со всех групп хостов, доступ убран но в конфигах остался мусор, пусть полежит до дня уборки. В день уборки запускаем отдельный плейбук, который принимает имя пользователя, а затем проходит по всем хостам, удаляя под нож учётку - и как только отработает - чистим конфиги от пользователя и каталог files.

В общем-то и всё, пожалуй. Мне кажется, что общее направление понятно и дальше детали сами продумаете. Если же я неправильно угадал ваши вводные -- попробуйте добавить больше деталей в описание задачи, покажу, что ещё можно предложить.