Скрипт¶
Запуск¶
- Отредактировать конфигурацию.
- Необходимо вручную настроить /etc/bind/options.conf на hq-srv.
- На ISP не установлен python3, нужно ставить вручную, на всех остальных всё ок.
- HQ-CLI не рекомендуется настраивать через скрипт. Скрипт заточен конкретно под etcnet, с native это просто не сработает, тем более обычно тот и так задан на DHCP.
Скрипт¶
exam.py
#!/usr/bin/env python3
import os
import sys
import subprocess
import textwrap
# ==========================================
# КОНФИГУРАЦИОННЫЙ БЛОК
# ==========================================
CONFIG = {
# Основной домен сети
"domain": "au-team.irpo",
# Системная таймзона для всех узлов
"timezone": "Europe/Moscow",
# Пароли для учетных записей и протоколов маршрутизации
"passwords": {
"net_admin": "P@ssw0rd", # Пароль администратора сети (hq-rtr, br-rtr)
"sshuser": "P@ssw0rd", # Пароль пользователя SSH (hq-srv, br-srv)
"ospf": "aboba" # Ключ аутентификации для OSPF
},
# Настройки для сервиса SSH
"ssh": {
"port": 2026, # Кастомный порт SSH
"sshuser_uid": 2026, # Фиксированный UID для sshuser
"banner_text": "Authorized access only" # Текст баннера
},
# Номера VLAN
"vlans": {
"hq_srv": 100, # VLAN для серверов HQ
"hq_cli": 200, # VLAN для клиентов HQ
"mgmt": 999 # Управляющий VLAN
},
# Физические имена сетевых интерфейсов на виртуальных машинах
"ifaces": {
"isp_inet": "enp7s1", # Внешний интерфейс ISP
"isp_hq": "enp7s2", # Интерфейс ISP в сторону HQ-RTR
"isp_br": "enp7s3", # Интерфейс ISP в сторону BR-RTR
"hq_isp": "enp7s1", # Интерфейс HQ-RTR в сторону ISP
"hq_lan": "enp7s2", # Локальный интерфейс HQ-RTR (транк для VLAN)
"br_isp": "enp7s1", # Интерфейс BR-RTR в сторону ISP
"br_lan": "enp7s2", # Локальный интерфейс BR-RTR в сторону BR-SRV
"hq_srv_lan": "enp7s1", # Локальный интерфейс HQ-SRV
"hq_cli_lan": "enp7s1", # Локальный интерфейс HQ-CLI
"br_srv_lan": "enp7s1" # Локальный интерфейс BR-SRV
},
# Полная таблица IP-адресации подсетей
"ips": {
# Линк ISP <-> HQ-RTR
"isp_to_hq": {"net": "172.16.1.0", "mask": "28", "isp": "172.16.1.1", "hq": "172.16.1.2"},
# Линк ISP <-> BR-RTR
"isp_to_br": {"net": "172.16.2.0", "mask": "28", "isp": "172.16.2.1", "br": "172.16.2.2"},
# Сеть серверов HQ (VLAN 100)
"hq_srv": {"net": "192.168.1.0", "mask": "27", "gw": "192.168.1.1", "srv": "192.168.1.2"},
# Сеть клиентов HQ (VLAN 200) + настройки пула DHCP
"hq_cli": {"net": "192.168.2.0", "mask": "28", "gw": "192.168.2.1", "cli": "192.168.2.2", "dhcp_range": "192.168.2.2 192.168.2.15"},
# Управляющая сеть HQ (VLAN 999)
"hq_mgmt": {"net": "192.168.9.0", "mask": "29", "gw": "192.168.9.1"},
# Сеть серверов филиала BR
"br_srv": {"net": "192.168.3.0", "mask": "28", "gw": "192.168.3.1", "srv": "192.168.3.2"},
# Адресация внутри GRE туннеля
"gre": {"net": "192.168.4.0", "mask": "28", "hq": "192.168.4.1", "br": "192.168.4.2"},
# Дополнительные внешние IP для DNS записей (Docker / Web)
"docker": "172.16.2.1",
"web": "172.16.1.1"
}
}
# Соответствие префиксов CIDR и текстовых сетевых масок (для DHCP)
CIDR_TO_NETMASK = {
"24": "255.255.255.0",
"25": "255.255.255.128",
"26": "255.255.255.192",
"27": "255.255.255.224",
"28": "255.255.255.240",
"29": "255.255.255.248",
"30": "255.255.255.252"
}
def run(cmd, input_data=None):
print(f"[*] Выполнение: {cmd}")
subprocess.run(cmd, shell=True, text=True, input=input_data, check=True)
def write_file(path, content):
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, 'w') as f:
f.write(content.strip() + "\n")
print(f"[+] Файл сохранен: {path}")
def append_file(path, content):
with open(path, 'a') as f:
f.write("\n" + content.strip() + "\n")
print(f"[+] Добавлено в файл: {path}")
def create_etcnet_iface(iface_name, options, ipv4address=None, ipv4route=None):
base_dir = f"/etc/net/ifaces/{iface_name}"
write_file(f"{base_dir}/options", options)
if ipv4address:
write_file(f"{base_dir}/ipv4address", ipv4address)
if ipv4route:
write_file(f"{base_dir}/ipv4route", ipv4route)
def set_hostname(hostname):
full_name = f"{hostname}.{CONFIG['domain']}" if "srv" in hostname or "cli" in hostname or "rtr" in hostname else hostname
run(f"hostnamectl hostname {full_name}")
def inject_temp_dns():
"""Временный рабочий DNS для обновления apt на чистой ОС через шлюзы"""
write_file("/etc/resolv.conf", "nameserver 77.88.8.8")
def install_packages(packages):
"""Синхронизация apt, установка и настройка таймзоны"""
run(f"apt-get update && apt-get install -y tzdata {packages}")
run(f"timedatectl set-timezone {CONFIG['timezone']}")
def create_user(username, password, uid=None, is_admin=False):
uid_str = f"-u {uid}" if uid else ""
run(f"useradd -m {uid_str} {username} || true")
run(f"echo '{password}' | passwd {username} --stdin")
if is_admin:
run(f"usermod -aG wheel {username}")
write_file(f"/etc/sudoers.d/{username}", f"{username} ALL=(ALL) NOPASSWD: ALL")
def setup_nat(out_iface):
run(f"iptables -t nat -A POSTROUTING -o {out_iface} -j MASQUERADE")
run("iptables-save >> /etc/sysconfig/iptables")
run("systemctl enable --now iptables")
def setup_ssh(username):
ssh_conf = textwrap.dedent(f"""
Port {CONFIG['ssh']['port']}
PermitRootLogin no
MaxAuthTries 2
AllowUsers {username}
Banner /etc/openssh/banner
""")
append_file("/etc/openssh/sshd_config", ssh_conf)
write_file("/etc/openssh/banner", CONFIG['ssh']['banner_text'])
run("systemctl restart sshd")
def setup_isp():
set_hostname("isp")
write_file("/etc/net/sysctl.conf", "net.ipv4.ip_forward = 1")
create_etcnet_iface(CONFIG['ifaces']['isp_inet'], textwrap.dedent("""
BOOTPROTO=dhcp
TYPE=eth
CONFIG_IPV4=yes
DISABLED=no
NM_CONTROLLED=no
SYSTEMD_BOOTPROTO=dhcp4
SYSTEMD_CONTROLLED=no
"""))
create_etcnet_iface(CONFIG['ifaces']['isp_hq'], textwrap.dedent("""
BOOTPROTO=static
TYPE=eth
CONFIG_IPV4=yes
DISABLED=no
NM_CONTROLLED=no
SYSTEMD_BOOTPROTO=static
"""), f"{CONFIG['ips']['isp_to_hq']['isp']}/{CONFIG['ips']['isp_to_hq']['mask']}")
create_etcnet_iface(CONFIG['ifaces']['isp_br'], textwrap.dedent("""
BOOTPROTO=static
TYPE=eth
CONFIG_IPV4=yes
DISABLED=no
NM_CONTROLLED=no
SYSTEMD_BOOTPROTO=static
"""), f"{CONFIG['ips']['isp_to_br']['isp']}/{CONFIG['ips']['isp_to_br']['mask']}")
run("systemctl restart network")
install_packages("iptables")
setup_nat(CONFIG['ifaces']['isp_inet'])
def setup_hq_rtr():
set_hostname("hq-rtr")
create_user("net_admin", CONFIG['passwords']['net_admin'], is_admin=True)
write_file("/etc/net/sysctl.conf", "net.ipv4.ip_forward = 1")
# Внешний интерфейс к ISP
create_etcnet_iface(CONFIG['ifaces']['hq_isp'], textwrap.dedent("""
BOOTPROTO=static
TYPE=eth
CONFIG_IPV4=yes
DISABLED=no
NM_CONTROLLED=no
"""), f"{CONFIG['ips']['isp_to_hq']['hq']}/{CONFIG['ips']['isp_to_hq']['mask']}",
f"default via {CONFIG['ips']['isp_to_hq']['isp']}")
# Физический интерфейс LAN (База для VLAN)
create_etcnet_iface(CONFIG['ifaces']['hq_lan'], "BOOTPROTO=static\nTYPE=eth\nCONFIG_IPV4=yes\nDISABLED=no\nNM_CONTROLLED=no")
# Нарезка VLAN интерфейсов
vlans = [
(CONFIG['vlans']['hq_srv'], CONFIG['ips']['hq_srv']['gw'], CONFIG['ips']['hq_srv']['mask']),
(CONFIG['vlans']['hq_cli'], CONFIG['ips']['hq_cli']['gw'], CONFIG['ips']['hq_cli']['mask']),
(CONFIG['vlans']['mgmt'], CONFIG['ips']['hq_mgmt']['gw'], CONFIG['ips']['hq_mgmt']['mask'])
]
for vid, ip, mask in vlans:
create_etcnet_iface(f"{CONFIG['ifaces']['hq_lan']}.{vid}", textwrap.dedent(f"""
BOOTPROTO=static
TYPE=vlan
CONFIG_IPV4=yes
DISABLED=no
NM_CONTROLLED=no
VID={vid}
HOST={CONFIG['ifaces']['hq_lan']}
"""), f"{ip}/{mask}")
# Поднятие GRE туннеля до филиала BR
create_etcnet_iface("tunnel1", textwrap.dedent(f"""
TYPE=iptun
CONFIG_IPV4=yes
DISABLED=no
TUNTYPE=gre
TUNLOCAL={CONFIG['ips']['isp_to_hq']['hq']}
TUNREMOTE={CONFIG['ips']['isp_to_br']['br']}
TUNTTL=32
TUNOPTIONS='ttl 32'
TUNMTU=1426
HOST={CONFIG['ifaces']['hq_isp']}
"""), f"{CONFIG['ips']['gre']['hq']}/{CONFIG['ips']['gre']['mask']}")
# Перезапуск сети для применения всех маршрутов и линков
run("systemctl restart network")
inject_temp_dns()
install_packages("iptables dhcp-server")
setup_nat(CONFIG['ifaces']['hq_isp'])
# Динамический расчет маски для DHCP-сервера на основе CONFIG
cli_cidr = CONFIG['ips']['hq_cli']['mask']
cli_netmask = CIDR_TO_NETMASK.get(cli_cidr, "255.255.255.0")
run("cp /etc/dhcp/dhcpd.conf.sample /etc/dhcp/dhcpd.conf || true")
write_file("/etc/dhcp/dhcpd.conf", textwrap.dedent(f"""
ddns-update-style none;
subnet {CONFIG['ips']['hq_cli']['net']} netmask {cli_netmask} {{
option routers {CONFIG['ips']['hq_cli']['gw']};
option subnet-mask {cli_netmask};
option domain-name "{CONFIG['domain']}";
option domain-name-servers {CONFIG['ips']['hq_srv']['srv']};
range dynamic-bootp {CONFIG['ips']['hq_cli']['dhcp_range']};
default-lease-time 21600;
max-lease-time 43200;
}}
"""))
write_file("/etc/sysconfig/dhcpd", f"DHCPARGS={CONFIG['ifaces']['hq_lan']}.{CONFIG['vlans']['hq_cli']}")
run("systemctl enable --now dhcpd")
# Запуск и конфигурация динамической маршрутизации OSPF (FRR)
write_file("/etc/frr/daemons", "ospfd=yes")
run("systemctl enable --now frr")
vtysh_cmd = textwrap.dedent(f"""
conf t
hostname hq-rtr.{CONFIG['domain']}
router ospf
passive-interface default
network {CONFIG['ips']['hq_srv']['net']}/{CONFIG['ips']['hq_srv']['mask']} area 0
network {CONFIG['ips']['hq_cli']['net']}/{CONFIG['ips']['hq_cli']['mask']} area 0
network {CONFIG['ips']['hq_mgmt']['net']}/{CONFIG['ips']['hq_mgmt']['mask']} area 0
network {CONFIG['ips']['gre']['net']}/{CONFIG['ips']['gre']['mask']} area 0
exit
interface tunnel1
ip ospf authentication
ip ospf authentication-key {CONFIG['passwords']['ospf']}
no ip ospf passive
end
wr mem
""")
run("vtysh", input_data=vtysh_cmd)
run("systemctl restart frr")
# Финальная перенастройка DNS на внутренний сервер HQ-SRV
write_file("/etc/resolv.conf", textwrap.dedent(f"""
nameserver {CONFIG['ips']['hq_srv']['srv']}
domain {CONFIG['domain']}
search {CONFIG['domain']}
"""))
def setup_hq_srv():
set_hostname("hq-srv")
create_user("sshuser", CONFIG['passwords']['sshuser'], uid=CONFIG['ssh']['sshuser_uid'], is_admin=True)
setup_ssh("sshuser")
create_etcnet_iface(CONFIG['ifaces']['hq_srv_lan'], textwrap.dedent("""
BOOTPROTO=static
TYPE=eth
CONFIG_IPV4=yes
DISABLED=no
"""), f"{CONFIG['ips']['hq_srv']['srv']}/{CONFIG['ips']['hq_srv']['mask']}",
f"default via {CONFIG['ips']['hq_srv']['gw']}")
run("systemctl restart network")
inject_temp_dns()
install_packages("bind bind-utils")
# ВЫВОД ИНСТРУКЦИЙ ДЛЯ /etc/bind/options.conf В КОНСОЛЬ (не перезаписываем файл)
print("\n" + "="*60)
print(" ВНИМАНИЕ: НЕОБХОДИМО ВРУЧНУЮ ОТРЕДАКТИРОВАТЬ /etc/bind/options.conf")
print(" Добавьте или измените внутри блока options {} следующие строки:")
print("-"*60)
print(textwrap.dedent("""
dnssec-validation no;
forwarders { 77.88.8.8; };
allow-query { any; };
listen-on { any; };
""").strip())
print("="*60 + "\n")
bind_local_zones = textwrap.dedent(f"""
zone "{CONFIG['domain']}" {{
type master;
file "{CONFIG['domain']}";
}};
zone "168.192.in-addr.arpa" {{
type master;
file "168.192.in-addr.arpa";
}};
""")
append_file("/etc/bind/local.conf", bind_local_zones)
write_file(f"/etc/bind/zone/{CONFIG['domain']}", textwrap.dedent(f"""
$TTL 1D
@ IN SOA {CONFIG['domain']}. root.{CONFIG['domain']}. (
1 ; serial
12H ; refresh
1H ; retry
1W ; expire
1H ; ncache
)
IN NS hq-srv.{CONFIG['domain']}.
hq-rtr IN A {CONFIG['ips']['hq_srv']['gw']}
hq-rtr IN A {CONFIG['ips']['hq_cli']['gw']}
br-rtr IN A {CONFIG['ips']['br_srv']['gw']}
hq-srv IN A {CONFIG['ips']['hq_srv']['srv']}
hq-cli IN A {CONFIG['ips']['hq_cli']['cli']}
br-srv IN A {CONFIG['ips']['br_srv']['srv']}
docker IN A {CONFIG['ips']['docker']}
web IN A {CONFIG['ips']['web']}
"""))
# Динамический расчет PTR-записей для обратной зоны
def get_octets(ip): return ip.split('.')[2], ip.split('.')[3]
hqs_gw_3, hqs_gw_4 = get_octets(CONFIG['ips']['hq_srv']['gw'])
hqc_gw_3, hqc_gw_4 = get_octets(CONFIG['ips']['hq_cli']['gw'])
hqs_sr_3, hqs_sr_4 = get_octets(CONFIG['ips']['hq_srv']['srv'])
hqc_cl_3, hqc_cl_4 = get_octets(CONFIG['ips']['hq_cli']['cli'])
write_file("/etc/bind/zone/168.192.in-addr.arpa", textwrap.dedent(f"""
$TTL 1D
@ IN SOA {CONFIG['domain']}. root.{CONFIG['domain']}. (
1 ; serial
12H ; refresh
1H ; retry
1W ; expire
1H ; ncache
)
IN NS hq-srv.{CONFIG['domain']}.
{hqs_gw_4}.{hqs_gw_3} IN PTR hq-rtr.{CONFIG['domain']}.
{hqc_gw_4}.{hqc_gw_3} IN PTR hq-rtr.{CONFIG['domain']}.
{hqc_cl_4}.{hqc_cl_3} IN PTR hq-cli.{CONFIG['domain']}.
{hqs_sr_4}.{hqs_sr_3} IN PTR hq-srv.{CONFIG['domain']}.
"""))
run(f"chown root:named /etc/bind/zone/{CONFIG['domain']}")
run("chown root:named /etc/bind/zone/168.192.in-addr.arpa")
run("systemctl enable --now bind")
run("rndc reload || true")
write_file("/etc/resolv.conf", textwrap.dedent(f"""
nameserver 127.0.0.1
domain {CONFIG['domain']}
search {CONFIG['domain']}
"""))
def setup_br_rtr():
set_hostname("br-rtr")
create_user("net_admin", CONFIG['passwords']['net_admin'], is_admin=True)
write_file("/etc/net/sysctl.conf", "net.ipv4.ip_forward = 1")
create_etcnet_iface(CONFIG['ifaces']['br_isp'], textwrap.dedent("""
BOOTPROTO=static
TYPE=eth
CONFIG_IPV4=yes
DISABLED=no
"""), f"{CONFIG['ips']['isp_to_br']['br']}/{CONFIG['ips']['isp_to_br']['mask']}",
f"default via {CONFIG['ips']['isp_to_br']['isp']}")
create_etcnet_iface(CONFIG['ifaces']['br_lan'], textwrap.dedent("""
BOOTPROTO=static
TYPE=eth
CONFIG_IPV4=yes
DISABLED=no
"""), f"{CONFIG['ips']['br_srv']['gw']}/{CONFIG['ips']['br_srv']['mask']}")
create_etcnet_iface("tunnel1", textwrap.dedent(f"""
TYPE=iptun
CONFIG_IPV4=yes
DISABLED=no
TUNTYPE=gre
TUNLOCAL={CONFIG['ips']['isp_to_br']['br']}
TUNREMOTE={CONFIG['ips']['isp_to_hq']['hq']}
TUNTTL=32
TUNOPTIONS='ttl 32'
TUNMTU=1426
HOST={CONFIG['ifaces']['br_isp']}
"""), f"{CONFIG['ips']['gre']['br']}/{CONFIG['ips']['gre']['mask']}")
run("systemctl restart network")
inject_temp_dns()
install_packages("iptables")
setup_nat(CONFIG['ifaces']['br_isp'])
write_file("/etc/frr/daemons", "ospfd=yes")
run("systemctl enable --now frr")
vtysh_cmd = textwrap.dedent(f"""
conf t
hostname br-rtr.{CONFIG['domain']}
router ospf
passive-interface default
network {CONFIG['ips']['br_srv']['net']}/{CONFIG['ips']['br_srv']['mask']} area 0
network {CONFIG['ips']['gre']['net']}/{CONFIG['ips']['gre']['mask']} area 0
exit
interface tunnel1
ip ospf authentication
ip ospf authentication-key {CONFIG['passwords']['ospf']}
no ip ospf passive
end
wr mem
""")
run("vtysh", input_data=vtysh_cmd)
run("systemctl restart frr")
write_file("/etc/resolv.conf", textwrap.dedent(f"""
nameserver {CONFIG['ips']['hq_srv']['srv']}
domain {CONFIG['domain']}
search {CONFIG['domain']}
"""))
def setup_br_srv():
set_hostname("br-srv")
create_user("sshuser", CONFIG['passwords']['sshuser'], uid=CONFIG['ssh']['sshuser_uid'], is_admin=True)
setup_ssh("sshuser")
create_etcnet_iface(CONFIG['ifaces']['br_srv_lan'], textwrap.dedent("""
BOOTPROTO=static
TYPE=eth
CONFIG_IPV4=yes
DISABLED=no
"""), f"{CONFIG['ips']['br_srv']['srv']}/{CONFIG['ips']['br_srv']['mask']}",
f"default via {CONFIG['ips']['br_srv']['gw']}")
run("systemctl restart network")
inject_temp_dns()
install_packages("")
write_file("/etc/resolv.conf", textwrap.dedent(f"""
nameserver {CONFIG['ips']['hq_srv']['srv']}
domain {CONFIG['domain']}
search {CONFIG['domain']}
"""))
def setup_hq_cli():
set_hostname("hq-cli")
create_etcnet_iface(CONFIG['ifaces']['hq_cli_lan'], textwrap.dedent("""
BOOTPROTO=dhcp
TYPE=eth
CONFIG_IPV4=yes
DISABLED=no
NM_CONTROLLED=no
SYSTEMD_BOOTPROTO=dhcp4
"""))
run("systemctl restart network")
install_packages("")
write_file("/etc/resolv.conf", textwrap.dedent(f"""
nameserver {CONFIG['ips']['hq_srv']['srv']}
domain {CONFIG['domain']}
search {CONFIG['domain']}
"""))
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Использование: python3 setup_exam.py <ИМЯ_УЗЛА>")
print("Доступные узлы: isp, hq-rtr, hq-srv, hq-cli, br-rtr, br-srv")
sys.exit(1)
node = sys.argv[1].lower()
if os.geteuid() != 0:
print("ОШИБКА: Скрипт необходимо запускать от пользователя root (или через sudo).")
sys.exit(1)
print(f"=== Запуск настройки для узла: {node.upper()} ===")
if node == "isp": setup_isp()
elif node == "hq-rtr": setup_hq_rtr()
elif node == "hq-srv": setup_hq_srv()
elif node == "br-rtr": setup_br_rtr()
elif node == "br-srv": setup_br_srv()
elif node == "hq-cli": setup_hq_cli()
else:
print(f"Неизвестный узел: {node}")
sys.exit(1)
print(f"=== Настройка {node.upper()} успешно завершена! ===")