Files
semaphore/playbooks/scan_inventory.yml

176 lines
7.6 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: Умное сканирование сети и классификация устройств
hosts: localhost
connection: local
gather_facts: no
become: yes # !!! ВАЖНО: Для определения OS (nmap -O) нужны права root
vars:
# --- НАСТРОЙКИ SEMAPHORE ---
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"
# --- СЕТИ ---
subnets:
- "192.168.0.0/24"
# добавьте другие подсети
# Порты для проверки (добавил 8291 для MikroTik, 80/443 для веб-морд, 631 для принтеров)
scan_ports: [22, 445, 5985, 80, 443, 8291, 631]
tasks:
# ----------------------------------------------------------------
# ШАГ 1: Быстрый поиск живых хостов (Ping Sweep)
# Это нужно, чтобы не сканировать пустоту тяжелым сканом
# ----------------------------------------------------------------
- name: Быстрый поиск активных IP
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 }}"
- name: Проверка
fail:
msg: "Живых хостов не найдено."
when: active_ips | length == 0
# ----------------------------------------------------------------
# ШАГ 2: Глубокий анализ каждого IP (ОС, Версии, Имена)
# Используем -O (OS), -sV (Versions) и скрипты
# ----------------------------------------------------------------
- name: Глубокое сканирование найденных хостов
shell: |
# Запускаем Nmap с определением ОС и скриптами SMB/Banner
# -O: Определение ОС (требует sudo)
# --osscan-guess: Пытаться угадать, если не уверен
# --script: Скрипты для точного имени Windows и SSH баннеров
nmap -O -sV -p {{ scan_ports | join(',') }} --script=smb-os-discovery,banner -Pn -n -T4 {{ item }}
loop: "{{ active_ips }}"
register: deep_scan_results
changed_when: false
# ----------------------------------------------------------------
# ШАГ 3: Анализ и классификация (Магия Ansible + Jinja2)
# ----------------------------------------------------------------
- name: Классификация хостов
set_fact:
classified_hosts: []
- name: Разбор результатов сканирования
set_fact:
classified_hosts: "{{ classified_hosts + [ host_data ] }}"
vars:
output: "{{ item.stdout }}"
ip: "{{ item.item }}"
# --- ЛОГИКА ОПРЕДЕЛЕНИЯ ИМЕНИ ---
# Пытаемся найти имя через SMB, если нет - DNS, если нет - IP
smb_name: "{{ output | regex_search('Computer name: ([\\w-]+)', '\\1') | first | default('') }}"
dns_name_cmd: "nslookup {{ ip }} 192.168.1.250 | grep 'name =' | awk '{print $NF}' | sed 's/\\.$//'"
# (В реальном плейбуке nslookup внутри loop медленно, тут упрощено)
final_name: >-
{% if smb_name != '' %}{{ smb_name | lower }}
{% else %}host_{{ ip | replace('.', '_') }}{% endif %}
# --- ЛОГИКА ОПРЕДЕЛЕНИЯ ТИПА ---
host_type: >-
{% if 'Windows' in output or 'Microsoft Windows' in output or '445/tcp open' in output %}windows
{% elif 'MikroTik' in output or 'RouterOS' in output or '8291/tcp open' in output %}mikrotik
{% elif 'Linux' in output or 'Ubuntu' in output or 'Debian' in output %}linux
{% elif 'HP' in output or 'Printer' in output or '631/tcp open' in output %}printer
{% else %}other{% endif %}
# --- СОБИРАЕМ ОБЪЕКТ ---
host_data:
ip: "{{ ip }}"
name: "{{ final_name }}"
type: "{{ host_type }}"
raw_os: "{{ output | regex_search('OS details: ([^\\n]+)', '\\1') | first | default('Unknown') }}"
loop: "{{ deep_scan_results.results }}"
no_log: true
# ----------------------------------------------------------------
# ШАГ 4: Генерация инвентаря по группам
# ----------------------------------------------------------------
- name: Генерация текста инвентаря
set_fact:
inventory_content: |
# === Windows Systems ===
[windows]
{% for host in classified_hosts if host.type == 'windows' %}
{{ host.name }} ansible_host={{ host.ip }} # Detected: {{ host.raw_os }}
{% endfor %}
[windows:vars]
ansible_connection=ssh
ansible_shell_type=powershell
ansible_user=o.grechko
ansible_port=22
# === Linux Systems ===
[linux]
{% for host in classified_hosts if host.type == 'linux' %}
{{ host.name }} ansible_host={{ host.ip }} # Detected: {{ host.raw_os }}
{% endfor %}
[linux:vars]
ansible_connection=ssh
ansible_user=root
# === MikroTik Routers ===
[routers_mikrotik]
{% for host in classified_hosts if host.type == 'mikrotik' %}
{{ host.name }} ansible_host={{ host.ip }}
{% endfor %}
[routers_mikrotik:vars]
ansible_connection=network_cli
ansible_network_os=routeros
ansible_user=admin
# === Printers & Others ===
[others]
{% for host in classified_hosts if host.type == 'printer' or host.type == 'other' %}
{{ host.name }} ansible_host={{ host.ip }} # Type: {{ host.type }}, OS: {{ host.raw_os }}
{% endfor %}
# ----------------------------------------------------------------
# ШАГ 5: Отправка в Semaphore (Ваш рабочий метод через файл)
# ----------------------------------------------------------------
- name: Сохранение JSON
copy:
content: |
{
"name": "{{ inventory_name }} {{ 1000 | random }}",
"project_id": {{ semaphore_project_id | int }},
"type": "static",
"ssh_key_id": {{ semaphore_key_id | int }},
"become_key_id": null,
"repository_id": null,
"inventory": {{ inventory_content | to_json }}
}
dest: /tmp/semaphore_smart_payload.json
- name: Отправка через CURL
command: >
curl -v -X POST "{{ semaphore_url }}/api/project/{{ semaphore_project_id }}/inventory"
-H "Authorization: Bearer {{ semaphore_api_token }}"
-H "Content-Type: application/json"
-H "Accept: application/json"
-d @/tmp/semaphore_smart_payload.json
register: curl_result
ignore_errors: yes
- name: Очистка
file: path=/tmp/semaphore_smart_payload.json state=absent
- name: Результат
debug:
msg: "Проверьте инвентарь! Создан ID, если статус 200/201"