Обновить playbooks/scan_inventory.yml

This commit is contained in:
2025-12-10 11:33:07 +00:00
parent 7b4053d8c5
commit 2cae218bdb

View File

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