Files
semaphore/playbooks/scan_inventory.yml

222 lines
8.9 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
- 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