222 lines
8.9 KiB
YAML
222 lines
8.9 KiB
YAML
---
|
||
- name: Сканирование сети через SNMP (Community: public)
|
||
hosts: localhost
|
||
connection: local
|
||
gather_facts: no
|
||
become: yes # Нужно для сканирования UDP (SNMP)
|
||
vars:
|
||
# --- SEMAPHORE API ---
|
||
semaphore_url: "http://192.168.0.198:9999"
|
||
semaphore_project_id: 1
|
||
#semaphore_key_id: 7
|
||
semaphore_api_token: "9ojexqiwt1xkemig7j1bd1pe-frh7hkre4reryk2occ="
|
||
inventory_name: "Smart Network Scan"
|
||
|
||
# --- ID КЛЮЧЕЙ ДЛЯ БУДУЩИХ ПОДКЛЮЧЕНИЙ ---
|
||
# Даже если мы нашли устройство по SNMP, для управления им позже нужен ключ.
|
||
# Если ключей нет, можно указать ID "пустого" ключа или любого существующего.
|
||
key_windows: 7
|
||
key_linux: 8
|
||
key_mikrotik: 9
|
||
key_printers: 7 # Можно тот же, принтерами обычно ansible не управляет
|
||
|
||
# --- СЕТИ ---
|
||
subnets: [
|
||
"192.168.0.0/24"
|
||
"192.168.0.0/23"
|
||
"192.168.2.0/24"
|
||
"192.168.3.0/24"
|
||
"172.19.8.0/24"
|
||
"172.19.9.0/24"
|
||
"172.19.10.0/24"
|
||
"172.19.24.0/24"
|
||
"172.19.26.0/24"
|
||
"172.19.40.0/24"
|
||
"172.19.42.0/24"
|
||
"172.19.56.0/24"
|
||
"172.19.58.0/24"
|
||
"172.19.90.0/24"
|
||
]
|
||
|
||
# SNMP Community (пароль для чтения)
|
||
snmp_community: "public"
|
||
|
||
tasks:
|
||
# ----------------------------------------------------------------
|
||
# ШАГ 1: Поиск живых хостов (Ping)
|
||
# ----------------------------------------------------------------
|
||
- name: Ping Sweep
|
||
command: "nmap -sn -n --min-rate 1000 -T4 -oG - {{ subnets | join(' ') }}"
|
||
register: ping_scan
|
||
changed_when: false
|
||
|
||
- name: Список IP
|
||
set_fact:
|
||
active_ips: "{{ ping_scan.stdout | regex_findall('Host: ([0-9.]+)') | unique | list }}"
|
||
|
||
- fail: msg="Сеть пуста" when: active_ips|length == 0
|
||
|
||
# ----------------------------------------------------------------
|
||
# ШАГ 2: Опрос через SNMP + Проверка портов
|
||
# -sU -p 161: Сканируем UDP порт SNMP
|
||
# --script snmp-sysdescr: Скрипт, который тянет описание ОС
|
||
# ----------------------------------------------------------------
|
||
- name: SNMP Discovery
|
||
shell: |
|
||
nmap -sU -sS -p U:161,T:22,T:445,T:8291,T:9100 \
|
||
--script snmp-sysdescr \
|
||
--script-args snmpcommunity={{ snmp_community }} \
|
||
-Pn -n -T4 {{ item }}
|
||
loop: "{{ active_ips }}"
|
||
register: scan_results
|
||
changed_when: false
|
||
|
||
# ----------------------------------------------------------------
|
||
# ШАГ 3: Классификация на основе ответа SNMP
|
||
# ----------------------------------------------------------------
|
||
- name: Анализ устройств
|
||
set_fact:
|
||
classified_hosts: "{{ classified_hosts | default([]) + [ host_data ] }}"
|
||
vars:
|
||
out: "{{ item.stdout }}"
|
||
ip: "{{ item.item }}"
|
||
|
||
# Пытаемся вытащить строку sysDescr из вывода Nmap
|
||
# Пример: "SNMPv2-MIB::sysDescr.0: RouterOS rb750..."
|
||
snmp_desc: "{{ out | regex_search('sysDescr\\.0: ([^\\n]+)', '\\1') | first | default('') }}"
|
||
|
||
# Определяем тип на основе SNMP ответа (или открытых портов, если SNMP молчит)
|
||
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
|
||
{% else %}other{% endif %}
|
||
|
||
# Формируем имя: Либо берем из SNMP, либо генерируем host_IP
|
||
# Часто в SNMP имя есть в sysName, но для упрощения оставим генерацию или возьмем первое слово из описания
|
||
host_data:
|
||
ip: "{{ ip }}"
|
||
type: "{{ detected_type }}"
|
||
desc: "{{ snmp_desc | replace('\"', '') | default('No SNMP info') }}"
|
||
name: "{{ detected_type }}_{{ ip | replace('.', '_') }}"
|
||
loop: "{{ scan_results.results }}"
|
||
no_log: true
|
||
|
||
# ----------------------------------------------------------------
|
||
# ШАГ 4: Разбиение на группы
|
||
# ----------------------------------------------------------------
|
||
- set_fact:
|
||
list_win: "{{ classified_hosts | selectattr('type', 'equalto', 'windows') | list }}"
|
||
list_lin: "{{ classified_hosts | selectattr('type', 'equalto', 'linux') | list }}"
|
||
list_tik: "{{ classified_hosts | selectattr('type', 'equalto', 'mikrotik') | list }}"
|
||
list_prn: "{{ classified_hosts | selectattr('type', 'equalto', 'printer') | list }}"
|
||
|
||
# ----------------------------------------------------------------
|
||
# ШАГ 5: Отправка в Semaphore (Windows)
|
||
# ----------------------------------------------------------------
|
||
- block:
|
||
- set_fact:
|
||
content_win: |
|
||
[windows]
|
||
{% for h in list_win %}
|
||
{{ h.name }} ansible_host={{ h.ip }} # SNMP: {{ h.desc }}
|
||
{% endfor %}
|
||
[windows:vars]
|
||
ansible_connection=ssh
|
||
ansible_shell_type=powershell
|
||
ansible_port=22
|
||
|
||
- copy:
|
||
content: |
|
||
{
|
||
"name": "SNMP Windows {{ 1000 | random }}",
|
||
"project_id": {{ semaphore_project_id }},
|
||
"type": "static",
|
||
"ssh_key_id": {{ key_windows }},
|
||
"become_key_id": null,
|
||
"repository_id": null,
|
||
"inventory": {{ content_win | to_json }}
|
||
}
|
||
dest: /tmp/p_win.json
|
||
|
||
- 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_win.json
|
||
ignore_errors: yes
|
||
when: list_win | length > 0
|
||
|
||
# ----------------------------------------------------------------
|
||
# ШАГ 6: Отправка в Semaphore (MikroTik)
|
||
# ----------------------------------------------------------------
|
||
- block:
|
||
- set_fact:
|
||
content_tik: |
|
||
[routers]
|
||
{% for h in list_tik %}
|
||
{{ h.name }} ansible_host={{ h.ip }} # {{ h.desc }}
|
||
{% endfor %}
|
||
[routers:vars]
|
||
ansible_connection=network_cli
|
||
ansible_network_os=routeros
|
||
|
||
- copy:
|
||
content: |
|
||
{
|
||
"name": "SNMP MikroTik {{ 1000 | random }}",
|
||
"project_id": {{ semaphore_project_id }},
|
||
"type": "static",
|
||
"ssh_key_id": {{ key_mikrotik }},
|
||
"become_key_id": null,
|
||
"repository_id": null,
|
||
"inventory": {{ content_tik | to_json }}
|
||
}
|
||
dest: /tmp/p_tik.json
|
||
|
||
- 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_tik.json
|
||
ignore_errors: yes
|
||
when: list_tik | length > 0
|
||
|
||
# ----------------------------------------------------------------
|
||
# ШАГ 7: Отправка в Semaphore (Принтеры)
|
||
# Принтеры полезно видеть, но ansible ими обычно не управляет
|
||
# ----------------------------------------------------------------
|
||
- block:
|
||
- set_fact:
|
||
content_prn: |
|
||
[printers]
|
||
{% for h in list_prn %}
|
||
{{ h.name }} ansible_host={{ h.ip }} # {{ h.desc }}
|
||
{% endfor %}
|
||
[printers:vars]
|
||
ansible_connection=local
|
||
|
||
- copy:
|
||
content: |
|
||
{
|
||
"name": "SNMP Printers {{ 1000 | random }}",
|
||
"project_id": {{ semaphore_project_id }},
|
||
"type": "static",
|
||
"ssh_key_id": {{ key_printers }},
|
||
"become_key_id": null,
|
||
"repository_id": null,
|
||
"inventory": {{ content_prn | to_json }}
|
||
}
|
||
dest: /tmp/p_prn.json
|
||
|
||
- 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_prn.json
|
||
ignore_errors: yes
|
||
when: list_prn | length > 0
|
||
|
||
- name: Очистка
|
||
shell: rm -f /tmp/p_*.json |