diff --git a/playbooks/scan_inventory.yml b/playbooks/scan_inventory.yml index 6725895..802a205 100644 --- a/playbooks/scan_inventory.yml +++ b/playbooks/scan_inventory.yml @@ -1,9 +1,9 @@ --- -- name: "Сканирование сети через SNMP (Community: public)" +- name: "Сканирование сети (Rootless Mode - TCP Only)" hosts: localhost connection: local gather_facts: no - become: yes # МЫ ВЕРНУЛИ ЭТО (нужны права root для nmap -sU / -O) + # become: yes <--- УДАЛЕНО: Работаем без прав root vars: # --- SEMAPHORE API --- semaphore_url: "http://192.168.0.198:9999" @@ -33,24 +33,12 @@ - "172.19.58.0/24" - "172.19.90.0/24" - snmp_community: "public" - tasks: - # ТЕСТ ПРАВ: Проверяем, работает ли become после настройки Environment - - name: Проверка прав root - command: id - register: id_check - changed_when: false - - - name: Показать пользователя (должен быть root) - debug: - msg: "Я работаю от имени: {{ id_check.stdout }}" - # ---------------------------------------------------------------- # ШАГ 1: Поиск живых хостов + # Используем -sn (обычный пользователь сделает TCP ping, это ок) # ---------------------------------------------------------------- - - name: Ping Sweep (быстрый поиск) - # УБРАЛИ 'sudo', ОСТАВИЛИ ТОЛЬКО nmap (права дает become: yes выше) + - name: Ping Sweep command: "nmap -sn -n --min-rate 1000 -T4 -oG - {{ subnets | join(' ') }}" register: ping_scan changed_when: false @@ -65,49 +53,58 @@ when: active_ips | length == 0 # ---------------------------------------------------------------- - # ШАГ 2: Опрос через SNMP + # ШАГ 2: Сканирование портов (TCP Connect) + # Используем -sT (не требует root) вместо -sS/-sU # ---------------------------------------------------------------- - - name: SNMP Discovery - # УБРАЛИ 'sudo' + - name: TCP Port Scan & Name Discovery shell: | - nmap -sU -sS -p U:161,T:22,T:445,T:8291,T:9100 \ - --script snmp-sysdescr \ - --script-args snmpcommunity={{ snmp_community }} \ + # Сканируем ключевые TCP порты: + # 22 (SSH/Linux), 445 (SMB/Windows), 8291 (Winbox/MikroTik), 9100 (JetDirect/Printer) + # --script smb-os-discovery пытается узнать имя Windows (работает по TCP, root не нужен) + nmap -sT -p 22,445,8291,9100 \ + --script smb-os-discovery \ -Pn -n -T4 {{ item }} loop: "{{ active_ips }}" register: scan_results changed_when: false # ---------------------------------------------------------------- - # ШАГ 3: Классификация + # ШАГ 3: Классификация (по открытым портам) # ---------------------------------------------------------------- - - name: Анализ устройств и классификация + - name: Анализ результатов set_fact: classified_hosts: "{{ classified_hosts | default([]) + [ host_data ] }}" vars: out: "{{ item.stdout }}" ip: "{{ item.item }}" - snmp_desc: "{{ out | regex_search('sysDescr\\.0: ([^\\n]+)', '\\1') | first | default('') }}" + + # Пытаемся найти имя компьютера через SMB (для Windows) + smb_name: "{{ out | regex_search('Computer name: ([\\w-]+)', '\\1') | first | default('') }}" + # ЛОГИКА ОПРЕДЕЛЕНИЯ ТИПА (По открытым портам) detected_type: >- - {% if 'Windows' in snmp_desc or '445/tcp open' in out %}windows - {% elif 'RouterOS' in snmp_desc or 'MikroTik' in snmp_desc or '8291/tcp open' in out %}mikrotik - {% elif 'Linux' in snmp_desc or 'Ubuntu' in snmp_desc or '22/tcp open' in out %}linux - {% elif 'JetDirect' in snmp_desc or 'LaserJet' in snmp_desc or 'Samsung' in snmp_desc or 'Kyocera' in snmp_desc or '9100/tcp open' in out %}printer + {% if '445/tcp open' in out %}windows + {% elif '8291/tcp open' in out %}mikrotik + {% elif '9100/tcp open' in out %}printer + {% elif '22/tcp open' in out %}linux {% else %}other{% endif %} - + + # Формируем имя + final_name: >- + {% if detected_type == 'windows' and smb_name != '' %}{{ smb_name | lower }} + {% else %}{{ detected_type }}_{{ ip | replace('.', '_') }}{% endif %} + host_data: ip: "{{ ip }}" type: "{{ detected_type }}" - desc: "{{ snmp_desc | replace('\"', '') | default('No SNMP info') }}" - name: "{{ detected_type }}_{{ ip | replace('.', '_') }}" + name: "{{ final_name }}" loop: "{{ scan_results.results }}" no_log: true # ---------------------------------------------------------------- # ШАГ 4: Группировка # ---------------------------------------------------------------- - - name: Группировка хостов + - name: Группировка списков set_fact: list_win: "{{ classified_hosts | selectattr('type', 'equalto', 'windows') | list }}" list_lin: "{{ classified_hosts | selectattr('type', 'equalto', 'linux') | list }}" @@ -118,23 +115,23 @@ # ШАГ 5: Отправка Windows # ---------------------------------------------------------------- - block: - - name: Генерация текста инвентаря Windows + - name: Генерация инвентаря Windows set_fact: content_win: | [windows] {% for h in list_win %} - {{ h.name }} ansible_host={{ h.ip }} # SNMP: {{ h.desc }} + {{ h.name }} ansible_host={{ h.ip }} {% endfor %} [windows:vars] ansible_connection=ssh ansible_shell_type=powershell ansible_port=22 - - name: Сохранение JSON для Windows + - name: Сохранение JSON (Windows) copy: content: | { - "name": "SNMP Windows {{ 1000 | random }}", + "name": "Auto Windows {{ 1000 | random }}", "project_id": {{ semaphore_project_id }}, "type": "static", "ssh_key_id": {{ key_windows }}, @@ -144,7 +141,7 @@ } dest: /tmp/p_win.json - - name: Отправка Windows API + - name: Отправка API (Windows) command: > curl -X POST "{{ semaphore_url }}/api/project/{{ semaphore_project_id }}/inventory" -H "Authorization: Bearer {{ semaphore_api_token }}" @@ -157,22 +154,22 @@ # ШАГ 6: Отправка MikroTik # ---------------------------------------------------------------- - block: - - name: Генерация текста инвентаря MikroTik + - name: Генерация инвентаря MikroTik set_fact: content_tik: | [routers] {% for h in list_tik %} - {{ h.name }} ansible_host={{ h.ip }} # {{ h.desc }} + {{ h.name }} ansible_host={{ h.ip }} {% endfor %} [routers:vars] ansible_connection=network_cli ansible_network_os=routeros - - name: Сохранение JSON для MikroTik + - name: Сохранение JSON (MikroTik) copy: content: | { - "name": "SNMP MikroTik {{ 1000 | random }}", + "name": "Auto MikroTik {{ 1000 | random }}", "project_id": {{ semaphore_project_id }}, "type": "static", "ssh_key_id": {{ key_mikrotik }}, @@ -182,7 +179,7 @@ } dest: /tmp/p_tik.json - - name: Отправка MikroTik API + - name: Отправка API (MikroTik) command: > curl -X POST "{{ semaphore_url }}/api/project/{{ semaphore_project_id }}/inventory" -H "Authorization: Bearer {{ semaphore_api_token }}" @@ -192,24 +189,24 @@ when: list_tik | length > 0 # ---------------------------------------------------------------- - # ШАГ 7: Отправка Принтеров + # ШАГ 7: Отправка Принтеров (если нужны) # ---------------------------------------------------------------- - block: - - name: Генерация текста инвентаря Принтеров + - name: Генерация инвентаря Принтеров set_fact: content_prn: | [printers] {% for h in list_prn %} - {{ h.name }} ansible_host={{ h.ip }} # {{ h.desc }} + {{ h.name }} ansible_host={{ h.ip }} {% endfor %} [printers:vars] ansible_connection=local - - name: Сохранение JSON для Принтеров + - name: Сохранение JSON (Принтеры) copy: content: | { - "name": "SNMP Printers {{ 1000 | random }}", + "name": "Auto Printers {{ 1000 | random }}", "project_id": {{ semaphore_project_id }}, "type": "static", "ssh_key_id": {{ key_printers }}, @@ -219,7 +216,7 @@ } dest: /tmp/p_prn.json - - name: Отправка Принтеров API + - name: Отправка API (Принтеры) command: > curl -X POST "{{ semaphore_url }}/api/project/{{ semaphore_project_id }}/inventory" -H "Authorization: Bearer {{ semaphore_api_token }}" @@ -228,5 +225,43 @@ ignore_errors: yes when: list_prn | length > 0 - - name: Очистка временных файлов + # ---------------------------------------------------------------- + # ШАГ 8: Отправка Linux + # ---------------------------------------------------------------- + - block: + - name: Генерация инвентаря Linux + set_fact: + content_lin: | + [linux] + {% for h in list_lin %} + {{ h.name }} ansible_host={{ h.ip }} + {% endfor %} + [linux:vars] + ansible_connection=ssh + ansible_user=root + + - name: Сохранение JSON (Linux) + copy: + content: | + { + "name": "Auto Linux {{ 1000 | random }}", + "project_id": {{ semaphore_project_id }}, + "type": "static", + "ssh_key_id": {{ key_linux }}, + "become_key_id": null, + "repository_id": null, + "inventory": {{ content_lin | to_json }} + } + dest: /tmp/p_lin.json + + - name: Отправка API (Linux) + command: > + curl -X POST "{{ semaphore_url }}/api/project/{{ semaphore_project_id }}/inventory" + -H "Authorization: Bearer {{ semaphore_api_token }}" + -H "Content-Type: application/json" + -d @/tmp/p_lin.json + ignore_errors: yes + when: list_lin | length > 0 + + - name: Очистка shell: rm -f /tmp/p_*.json \ No newline at end of file