
Привет, Habr! Меня зовут Андрей, системный администратор в электрических сетях, со всеми вытекающими — сети, сервера, пользователи, программы. Как и у всех — какие то скрипты на python для сбора инфы с активки, ежедневного бэкапа конфигов, задач «а добавь вот этот IP в ACL на все устройства»
Везде использую свой модуль для работы с файлами конфигурации. Вы скажете OmegaConf Dynaconf, да и PYAML никто не отменял. Не торопитесь. Я попросил AI сравнить и воодушевился — а вдруг мой велосипед будет кому то полезен?
В начале было слово
Знакомство с python началось с книги Натальи Самойленко Python для сетевых инженеров
эксперименты ставил на своей сети, очень скоро осознал что для десятков устройств надо каждый раз готовить словарь device для ConnectHandler(**device), начал создавать такой в YAML файле. Формат этот мне больше всего понравился, принял для себя как «внутренний стандарт»
Это вылилось в создание своего модуля для работы с активкой, в котором в самом начале был класс StartOptions:
class StartOptions:
def __init__(self, fi):
from os import path
import psutil
if not path.dirname(fi):
p = psutil.Process().exe()
path_to_ini = path.abspath(path.join(path.dirname(p), fi))
else:
path_to_ini = fi
with open(path_to_ini, encoding="utf8") as f:
d = yaml.safe_load(f)
for key in d.keys():
setattr(self, key, d[key])
myini = StartOptions('cb.yml')
Создаем объект и устанавливаем ему атрибуты из keys() values() нашего конфига.
Погуглить имеющиеся решения на PYPi ума в тот момент и не хватило и хотелось что то свое написать.
пример конфига cb.yml:
language: ru
localpath: /opt/mypython/
main_backup_server:
ftp_root: /var/ftp/CISCO/
local_root: /var/ftp/CISCO/
name: loganalyzer
password: gAAAAABn7NmePUXNP7Yxni9dKi2H_ZqeQmAgv3AmbrNADgY23XrBVKB_rgmohFK321I9fbB_2bCAz5ShTJN3QSMGlwz5jVUNnA==^M
user: gAAAAABn7Nme9PyPeK5Tm406au9B5NaN8FtnP33MAYo3DYkOTRnJKw0lBOROaw2iuKhSgDudHWePvWQ74WJi7iELvFglcvcE4g==^M
password: gAAAAABn7Nme6Kb4cI-sqsyApPFm2JsqLtp-2Hds7Jov8MY50XBx3s1VKOIXgA3FKjIa_FjpqkbdDsG6bWwzobwhw9SOrSwHOA==^M
phone_mac:
- 805e
- 001a
second_backup_server:
ftp_root: /
name: NOES-RPBSRV
password: gAAAAABn7NmeOj75h2NeM8zzuySko3lVgEzEzTHkETALzcMv6s32XusxdRe9xseDFtJh0GPJpuuFEyeMmNq9h5vECRNgJicnsQ==^M
user: gAAAAABn7NmeWRGa7UCv29ApgekzhYZdwXoN_PS_VJPjekvA72zzeQrJDv8GjsXKGHVT2_tfqJZHg0TgdoDaPhIvRSp7sJD-9w==^M
templpath: /opt/mypython/TEMPLATES/^M
user: gAAAAABn7NmekcfGhIjrwJRXL6v0QRm3SAz4dz-GSm16gu7dpBIyw5omo-A1d3-LjaNwPwTN6Vg-1jzW5_0aPeFbwe0p6TZtsQ=
Это реальный конфиг для скрипта бэкапа конфигураций всей активки. И пусть вас не удивляет не только main но и second backup server. Это цена опыта :-)
Зашифрованные строки появились уже потом. Используя свой модуль написал скрипт который по fh some_ip
или fh some_host_name
показывает в какой порт какого коммутатора (и путь от меня до него по сети) включен хост и, если это пользовательский АРМ в домене, еще и имя пользователя этого компьютера и имя хоста. Он полезен не только мне, но в конфиге в открытом виде мои учетки на tacacs и в AD,
Можно, конечно, создать ограниченные учетки для поиска (для AD у нас такая есть), но у меня лично один конфиг и для «покажи мне» и для «добавь на 100 500 устройств новый ACL
Поэтому прикрутил cryptography.fernet с созданием, обновлением «секрета» по ключу запуска с сохранением... в тело самой программы. Не понравилось. Стал хранить в отдельном файле. Пару раз менял принцип поиска, где лежит этот файл с секретом.
А потом попросил AI сравнить мой модуль с другими, он показал на какие‑то плюсы и началось — а хочешь добавим парсер/декодер, а хочешь добавим подсказки при наборе вида
ac.main_backup_server
language password templpath
localpath phone_mac user
main_backup_server second_backup_server
а хочешь еще и поддержку JSON? согласился, сам подумывал. Не устоял еще и от .env от TOML отказался, но добавить не проблема.
И вот что поучилось:
Python module astarconf
Безопасный, подключаемый загрузчик конфигураций для YAML, JSON, .env и Python словарей - с шифрованием на уровне полей, поддержкой CLI и гибридным доступом.
Особенности
🔐 Шифрование/дешифрование полей в YAML
🔌 Загрузка из .yaml, .json, .env или dict
✅ Доступ к атрибутам (config.key) и ключам (config['key'])
🧰 CLI-интерфейс для рабочих процессов шифрования.
Пример использования:
from astarconf import Astarconf
conf = Astarconf("config.yaml")
print(conf.database.user)
print(conf["database"]["user"])
Ключ для шифрования/дешифрования может лежать в
переменной окружения ASTARCONF_SECRET
~/.astarconf/secret.key
/etc/astarconf/secret.key
в файле secret.key в любом каталоге в $PATH доступном пользователю от имени которого запускается скрипт
astarconf.py -g ~/.astarconf/secret.key # генерация секретного ключа
astarconf.py -c config.yaml # шифрование полей (по умолчанию
- user, passowrd)
astarconf.py -c config.yaml token api_key # шифрование конкретных указанных полей
astarconf.py -d config.yaml # дешифрование конфига (в тот же файл)
astarconf.py -d config.yaml -o output.yaml # дешифрование конфига,
запись в output файл
astarconf.py -o output.yaml -f # перезапись output если существует
Модуль astarconf
имеет несколько интересных особенностей, которые отличают его от omegaconf
и dynaconf
. Сравнение по ключевым аспектам:
1. Основные возможности:
Функционал |
|
|
|
---|---|---|---|
Поддержка форматов | YAML, JSON, | YAML, JSON (через OmegaConf) | YAML, JSON, TOML, |
Шифрование данных | Да (Fernet) | Нет | Да (частично, через Vault) |
Доступ к данным | Атрибуты ( | Атрибуты + индексы + точки ( | Атрибуты + индексы |
Динамическая загрузка | Нет (можно добавлять новые атрибуты), | Да (можно обновлять конфиг) | Да (динамическое перечитывание) |
Валидация схемы | Нет | Да (через | Да (через |
Переменные окружения | Через | Через интерполяцию ( | Через |
Иерархическая конфигурация | Да (через | Да (вложенные структуры) | Да (многоуровневые настройки) |
Плюсы моего модуля (astarconf):
✅ Встроенное шифрование
Позволяет шифровать чувствительные данные (например,
user
,password
) прямо в YAML/JSON.omegaconf
иdynaconf
не имеют встроенного шифрования (вdynaconf
есть поддержка HashiCorp Vault, но это внешний сервис).
✅ Гибкий доступ к данным
Поддержка как
obj.key
, так иobj["key"]
.В
omegaconf
тоже есть оба варианта, но вdynaconf
предпочтительнееobj.key
.
✅ Простота использования
Ваш модуль легче освоить, так как он фокусируется на базовых задачах (загрузка + шифрование).
omegaconf
сложнее из-за поддержкиpydantic
и интерполяции.
Когда использовать astarconf?
Если нужно простое решение с шифрованием (например, для хранения паролей в конфиге).
Если не нужна сложная валидация или динамическое обновление.
Когда выбрать omegaconf или dynaconf?
Если нужна интеграция с
pydantic
→omegaconf
.Если нужна поддержка Vault или динамическое перечитывание конфига →
dynaconf
.Если важна интерполяция переменных (например,
${env:DB_HOST}
) →omegaconf
.
Для моих быстрых задач мне вполне хватает astarconf
Например у меня есть словарь различных команд для разного оборудования, он гораздо больше примера
commands:
"mac_addr_tbl_bymac":
desc: 'show mac addres table and filter by mac'
cisco_ios: 'show mac address-table | in {}'
huawei_vrrp8: 'display mac-address | in {}'
huawei_ce: 'display mac-address | in {}'
eltex: 'show mac address-table | in {}'
"mac_addr_tbl_byport":
desc: 'show mac addres table on defined port'
cisco_ios: 'show mac address-table interface {}'
huawei_vrrp8: 'display mac-address {}'
huawei_ce: 'display mac-address interface {}'
eltex: 'show mac address-table | in {}'
а в конфиге программы fh (findHost) есть атрибут - путь до этого файла
dict_cmd_path: /some...path/commands.yml
а в коде использую например так
(в моем конфиге fh изначально отcутсвует атрибут commands):
import yaml
from astar import Astarconf
ac = Astarconf('/home/astar/mypython/fh.yml')
commands = {}
with open(ac.dict_cmd_path) as f:
ac.commands = yaml.safe_load(f)['commands']
#и дальше объект представляющий всё наше оборудование myactivka
#имеет функцию получения информации с устройства
myactivka.getinfo(device, func, *args)
# где func - абревиатуры команды из commands.yml типа mac_addr_tbl_byport
port = 'Gi0/0/10'
#и код не зависит от того что такое device - huawei, cisco, eltex router or switch
command = ac.commands[func][dev['device_type']].format(port)
Если вам понравился такой подход к работе с конфигами
исходный код здесь: https://github.com/AstarAiki/astarconf
модуль на PYPi: https://pypi.org/project/astarconf/
установка: pip install astarconf
А больше всего хочется
Ваших отзывов и комментариев. Да, я изобрел велосипед, но по мне так удобный :-)
И я им пользуюсь!