- hosts: all become: yes vars: # Путь к ПУБЛИЧНОМУ ключу User CA на вашей Ansible-машине local_ssh_user_ca_pub_path: "/etc/step-ca/ssh_user_ca_key.pub" pre_tasks: - name: Инициализация пустых списков перед сбором set_fact: _raw_users: [] _raw_projects: [] - name: Сбор пользователей из всех активных групп хоста # Фильтр 'replace('-', '_')' превратит "proj-b" в "proj_b", и Ansible найдет "proj_b_users" set_fact: _raw_users: "{{ _raw_users + (hostvars[inventory_hostname][(item | replace('-', '_')) ~ '_users'] | default([])) }}" loop: "{{ group_names }}" when: hostvars[inventory_hostname][(item | replace('-', '_')) ~ '_users'] is defined - name: Сбор проектов из всех активных групп хоста set_fact: _raw_projects: "{{ _raw_projects + (hostvars[inventory_hostname][(item | replace('-', '_')) ~ '_projects'] | default([])) }}" loop: "{{ group_names }}" when: hostvars[inventory_hostname][(item | replace('-', '_')) ~ '_projects'] is defined - name: Фиксация уникальных массивов set_fact: project_users: "{{ _raw_users | unique }}" allowed_projects: "{{ _raw_projects | unique }}" - name: Дебаг получившейся матрицы доступов (Опционально) debug: msg: "Хост {{ inventory_hostname }} получит юзеров {{ project_users }} и принципалы {{ allowed_projects }}" tasks: - name: Создание системной директории для принципалов file: path: /etc/ssh/auth_principals state: directory owner: root group: root mode: '0755' - name: Создание локальных пользователей из списка проекта user: name: "{{ item.name }}" shell: /bin/bash create_home: yes state: present loop: "{{ project_users }}" - name: Генерация файлов auth_principals с маппингом проектов copy: dest: "/etc/ssh/auth_principals/{{ item.name }}" content: "{{ allowed_projects | join('\n') }}\n" owner: root group: root mode: '0644' loop: "{{ project_users }}" - name: Настройка беспарольного sudo для администраторов проекта copy: dest: "/etc/sudoers.d/project-ssh-{{ item.name }}" content: "{{ item.name }} ALL=(ALL) NOPASSWD:ALL" validate: /usr/sbin/visudo -cf %s mode: '0440' loop: "{{ project_users }}" when: item.sudo | bool - name: Копирование публичного ключа User CA на хост copy: src: "{{ local_ssh_user_ca_pub_path }}" dest: /etc/ssh/ca.pub owner: root group: root mode: '0644' - name: Сбор имен всех разрешенных пользователей для AllowUsers set_fact: allow_users_list: "{{ project_users | map(attribute='name') | join(' ') }}" - name: Настройка sshd_config для авторизации пользователей по сертификатам blockinfile: path: /etc/ssh/sshd_config block: | TrustedUserCAKeys /etc/ssh/ca.pub AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u AllowUsers {{ allow_users_list }} hogweed1 PasswordAuthentication no PubkeyAuthentication yes marker: "# {mark} ANSIBLE MANAGED USER CERTIFICATE BLOCK #" notify: Restart SSH - name: Получить список всех файлов принципалов на машине find: paths: /etc/ssh/auth_principals file_type: file register: found_principals_files - name: Удаление файлов принципалов для пользователей, которые выбыли из проекта file: path: "{{ item.path }}" state: absent loop: "{{ found_principals_files.files }}" # Фильтр проверяет: если имя файла на диске НЕ входит в текущий список project_users, файл удаляется when: item.path | basename not in (project_users | map(attribute='name') | list) handlers: - name: Restart SSH service: name: sshd state: restarted