Files
mukul975 27c6414ca5 Add folder anatomy (scripts/agent.py + references/api-reference.md) for 648 cybersecurity skills
Complete skill folder anatomy across all cybersecurity skills:
- scripts/agent.py: 80-150 line Python agents using real libraries (impacket,
  boto3, azure-mgmt-*, kubernetes, pefile, yara, scapy, shodan, stix2, etc.)
- references/api-reference.md: real API documentation with method signatures
- LICENSE: MIT license for all skill folders
2026-03-10 21:02:12 +01:00

205 lines
7.0 KiB
Python

#!/usr/bin/env python3
"""VLAN Network Segmentation Agent - Configures and audits VLAN segmentation on managed switches."""
import json
import logging
import argparse
from datetime import datetime
from netmiko import ConnectHandler
from napalm import get_network_driver
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
def connect_netmiko(host, username, password, device_type="cisco_ios"):
"""Establish SSH connection to network device via Netmiko."""
device = {
"device_type": device_type,
"host": host,
"username": username,
"password": password,
"timeout": 30,
}
conn = ConnectHandler(**device)
logger.info("Connected to %s (%s)", host, device_type)
return conn
def get_vlan_config(conn):
"""Retrieve current VLAN configuration from the switch."""
output = conn.send_command("show vlan brief", use_textfsm=True)
if isinstance(output, list):
vlans = []
for entry in output:
vlans.append({
"vlan_id": entry.get("vlan_id", ""),
"name": entry.get("name", ""),
"status": entry.get("status", ""),
"interfaces": entry.get("interfaces", []),
})
logger.info("Retrieved %d VLANs", len(vlans))
return vlans
return []
def create_vlan(conn, vlan_id, vlan_name):
"""Create a new VLAN on the switch."""
commands = [
f"vlan {vlan_id}",
f"name {vlan_name}",
]
output = conn.send_config_set(commands)
logger.info("Created VLAN %s (%s)", vlan_id, vlan_name)
return output
def configure_access_port(conn, interface, vlan_id):
"""Configure a switch port as an access port in a specific VLAN."""
commands = [
f"interface {interface}",
"switchport mode access",
f"switchport access vlan {vlan_id}",
"switchport port-security",
"switchport port-security maximum 2",
"switchport port-security violation restrict",
"spanning-tree portfast",
"spanning-tree bpduguard enable",
]
output = conn.send_config_set(commands)
logger.info("Configured %s as access port in VLAN %s", interface, vlan_id)
return output
def configure_trunk_port(conn, interface, allowed_vlans):
"""Configure a switch port as a trunk port with specific allowed VLANs."""
vlan_list = ",".join(str(v) for v in allowed_vlans)
commands = [
f"interface {interface}",
"switchport mode trunk",
"switchport trunk encapsulation dot1q",
f"switchport trunk allowed vlan {vlan_list}",
"switchport trunk native vlan 999",
"switchport nonegotiate",
]
output = conn.send_config_set(commands)
logger.info("Configured %s as trunk with VLANs %s", interface, vlan_list)
return output
def harden_unused_ports(conn, interfaces):
"""Shut down and assign unused ports to a quarantine VLAN."""
commands = []
for iface in interfaces:
commands.extend([
f"interface {iface}",
"switchport mode access",
"switchport access vlan 999",
"shutdown",
])
output = conn.send_config_set(commands)
logger.info("Hardened %d unused ports", len(interfaces))
return output
def configure_inter_vlan_acl(conn, acl_name, rules):
"""Configure access control lists for inter-VLAN routing."""
commands = [f"ip access-list extended {acl_name}"]
for rule in rules:
commands.append(rule)
output = conn.send_config_set(commands)
logger.info("Configured ACL %s with %d rules", acl_name, len(rules))
return output
def audit_vlan_security(conn):
"""Audit VLAN configuration for common security issues."""
findings = []
vlan_output = conn.send_command("show vlan brief")
if "VLAN0001" in vlan_output:
trunk_output = conn.send_command("show interfaces trunk")
if "1" in trunk_output:
findings.append({
"check": "Native VLAN",
"finding": "Default VLAN 1 may be used as native VLAN on trunks",
"severity": "Medium",
"remediation": "Change native VLAN to unused VLAN (e.g., 999)",
})
port_output = conn.send_command("show interfaces status")
if "notconnect" in port_output.lower():
findings.append({
"check": "Unused Ports",
"finding": "Ports in notconnect state may not be hardened",
"severity": "Low",
"remediation": "Assign to quarantine VLAN and shut down",
})
dtp_output = conn.send_command("show dtp")
if "DESIRABLE" in dtp_output or "AUTO" in dtp_output:
findings.append({
"check": "DTP Negotiation",
"finding": "DTP negotiation enabled - VLAN hopping risk",
"severity": "High",
"remediation": "Set all access ports to 'switchport nonegotiate'",
})
logger.info("Security audit: %d findings", len(findings))
return findings
def get_napalm_config(host, username, password, driver="ios"):
"""Retrieve device configuration using NAPALM for multi-vendor support."""
Driver = get_network_driver(driver)
device = Driver(host, username, password, timeout=30)
device.open()
facts = device.get_facts()
interfaces = device.get_interfaces()
vlans = device.get_vlans()
device.close()
return {"facts": facts, "interfaces": interfaces, "vlans": vlans}
def generate_report(host, vlans, audit_findings, actions):
"""Generate VLAN segmentation audit report."""
report = {
"device": host,
"timestamp": datetime.utcnow().isoformat(),
"vlans": vlans,
"security_findings": audit_findings,
"configuration_actions": actions,
}
print(f"VLAN SEGMENTATION REPORT: {len(vlans)} VLANs, {len(audit_findings)} findings")
return report
def main():
parser = argparse.ArgumentParser(description="VLAN Network Segmentation Agent")
parser.add_argument("--host", required=True, help="Switch management IP")
parser.add_argument("--username", required=True, help="SSH username")
parser.add_argument("--password", required=True, help="SSH password")
parser.add_argument("--device-type", default="cisco_ios", help="Netmiko device type")
parser.add_argument("--audit-only", action="store_true", help="Audit without changes")
parser.add_argument("--output", default="vlan_report.json")
args = parser.parse_args()
conn = connect_netmiko(args.host, args.username, args.password, args.device_type)
vlans = get_vlan_config(conn)
findings = audit_vlan_security(conn)
actions = []
if not args.audit_only:
logger.info("Audit-only mode not set - configuration changes require explicit commands")
report = generate_report(args.host, vlans, findings, actions)
conn.disconnect()
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
logger.info("Report saved to %s", args.output)
if __name__ == "__main__":
main()