--- # ============================================================================== # ЭТАП 1: Сбор сертификатов с хоста storm.bit-it.ru на ваш ПК # ============================================================================== - name: Безопасный сбор всех SSL-сертификатов с эталонного хоста hosts: storm.bit-it.ru become: true vars: local_tmp_dir: "/tmp/ansible_certs" # По умолчанию пустой список означает: обрабатываем ВСЕ найденные домены target_certs: [] tasks: - name: Динамический поиск папок доменов ansible.builtin.find: paths: "/etc/letsencrypt/live" file_type: directory recurse: false excludes: "all,README" register: found_live_dirs - name: Формирование списка доменов с учетом фильтрации ansible.builtin.set_fact: dynamic_domains: >- {% if target_certs | length > 0 %} {{ found_live_dirs.files | map(attribute='path') | map('basename') | intersect(target_certs) | list }} {% else %} {{ found_live_dirs.files | map(attribute='path') | map('basename') | list }} {% endif %} cacheable: true - name: Проверка, что список доменов для переноса не пуст ansible.builtin.meta: end_play when: dynamic_domains | length == 0 comment: "Скрипт остановится, если переданных доменов нет на сервере-источнике" - name: Вывод списка доменов, выбранных для синхронизации ansible.builtin.debug: msg: "Будут синхронизированы следующие сертификаты: {{ dynamic_domains }}" - name: Создание изолированной папки на вашем ПК ansible.builtin.file: path: "{{ local_tmp_dir }}/{{ item }}" state: directory mode: '0700' delegate_to: localhost loop: [ 'archive', 'live', 'renewal' ] - name: Скачивание папок archive на ваш ПК ansible.builtin.fetch: src: "/etc/letsencrypt/archive/{{ item }}/" dest: "{{ local_tmp_dir }}/archive/{{ item }}/" flat: false loop: "{{ dynamic_domains }}" - name: Скачивание конфигураций обновления renewal на ваш ПК ansible.builtin.fetch: src: "/etc/letsencrypt/renewal/{{ item }}.conf" dest: "{{ local_tmp_dir }}/renewal/{{ item }}.conf" flat: true loop: "{{ dynamic_domains }}" - name: Скачивание папок live на ваш ПК ansible.builtin.fetch: src: "/etc/letsencrypt/live/{{ item.0 }}/{{ item.1 }}.pem" dest: "{{ local_tmp_dir }}/live/{{ item.0 }}/{{ item.1 }}.pem" flat: true loop: "{{ dynamic_domains | product(['cert', 'chain', 'fullchain', 'privkey']) | list }}" # ============================================================================== # ЭТАП 2: Раскатка сертификатов с вашего ПК и ПОЛНАЯ ЗАЧИСТКА ХВОСТОВ # ============================================================================== - name: Раскатка SSL-сертификатов с ПК на целевые хосты и зачистка hosts: mail_servers become: true vars: local_tmp_dir: "/tmp/ansible_certs" source_host_inventory_name: "storm.bit-it.ru" tasks: - name: Основной блок выполнения раскатки block: - name: Сбор информации о запущенных сервисах на целевом хосте ansible.builtin.service_facts: - name: Автоматическое создание всей иерархии папок Let's Encrypt на целевом хосте ansible.builtin.file: path: "/etc/letsencrypt/{{ item }}" state: directory owner: root group: root mode: '0755' loop: [ 'archive', 'live', 'renewal' ] - name: Копирование содержимого папки archive на целевой сервер ansible.builtin.copy: src: "{{ local_tmp_dir }}/archive/{{ hostvars[source_host_inventory_name]['inventory_hostname'] }}/etc/letsencrypt/archive/{{ item }}/" dest: "/etc/letsencrypt/archive/{{ item }}/" owner: root group: root mode: '0600' loop: "{{ hostvars[source_host_inventory_name]['dynamic_domains'] }}" - name: Копирование конфигураций renewal на целевой сервер ansible.builtin.copy: src: "{{ local_tmp_dir }}/renewal/{{ item }}.conf" dest: "/etc/letsencrypt/renewal/{{ item }}.conf" owner: root group: root mode: '0644' loop: "{{ hostvars[source_host_inventory_name]['dynamic_domains'] }}" - name: Создание папок доменов внутри директории live ansible.builtin.file: path: "/etc/letsencrypt/live/{{ item }}" state: directory owner: root group: root mode: '0700' loop: "{{ hostvars[source_host_inventory_name]['dynamic_domains'] }}" - name: Нативная сборка относительных символических ссылок в папке live ansible.builtin.file: src: "../../archive/{{ item.0 }}/{{ item.1 }}1.pem" dest: "/etc/letsencrypt/live/{{ item.0 }}/{{ item.1 }}.pem" state: link force: true loop: "{{ hostvars[source_host_inventory_name]['dynamic_domains'] | product(['cert', 'chain', 'fullchain', 'privkey']) | list }}" - name: Автоматический перезапуск активных веб- и почтовых служб ansible.builtin.systemd: name: "{{ item }}" state: restarted loop: - dovecot - nginx - apache2 - httpd when: - ansible_facts.services[item + '.service'] is defined - ansible_facts.services[item + '.service'].state == 'running' always: - name: Полное удаление секретных ключей с ПК администратора ansible.builtin.file: path: "{{ local_tmp_dir }}" state: absent delegate_to: localhost run_once: true