Скрипт для автоматического сканирования и анализа SSL/TLS сертификатов.
- Рекурсивное сканирование директорий для поиска .crt файлов
- Анализ дат начала и истечения сертификатов
- Группировка по статусу (просроченные, истекающие, действительные)
- Отправка уведомлений в Telegram
- Отправка email уведомлений (HTML + plain text)
- Гибкая настройка через .env файл
- Режим отладки с детальным логированием
- Поддержка PEM и DER форматов
- Python 3.12+
- Пакеты общие: pip install poetry poetry-plugin-shell poetry-dotenv-plugin ruff mypy
- Пакеты проекта: niquests, cryptography, pyOpenSSL, python-dotenv
git clone <repo-url>
cd certificate-expiry-checker
python -m venv venv
source venv/bin/activate
pip install niquests cryptography pyOpenSSL python-dotenvСоздайте файл .env:
SCAN_DIRECTORY=/etc/ssl/certs
VERBOSE=false
EXPIRING_DAYS=30
TELEGRAM_BOT_TOKEN=your_token
TELEGRAM_CHAT_ID=your_chat_id
EMAIL_ENABLED=true
EMAIL_SMTP_HOST=smtp.gmail.com
EMAIL_SMTP_PORT=587
EMAIL_USE_TLS=true
EMAIL_USERNAME=your_email@gmail.com
EMAIL_PASSWORD=your_password
EMAIL_FROM=noreply@example.com
EMAIL_TO=admin@example.compoetry run check-certs
poetry run check-certs /path/to/.env.custom
poetry run python src/check_expire_certs/main.py
poetry run python src/check_expire_certs/main.py /path/to/.env.custom| Аргумент | Описание |
|---|---|
| env_file | Путь к .env файлу (опционально) |
Обязательные:
- SCAN_DIRECTORY - путь к директории с сертификатами
Опциональные:
- VERBOSE - режим отладки (false по умолчанию)
- EXPIRING_DAYS - порог истечения в днях
Telegram:
- TELEGRAM_BOT_TOKEN - токен бота
- TELEGRAM_CHAT_ID - ID чата
Email:
- EMAIL_ENABLED - включить email (false)
- EMAIL_SMTP_HOST - SMTP сервер
- EMAIL_SMTP_PORT - порт (587)
- EMAIL_USE_TLS - использовать TLS (true)
- EMAIL_USERNAME - имя пользователя
- EMAIL_PASSWORD - пароль
- EMAIL_FROM - отправитель
- EMAIL_TO - получатели через запятую
- EMAIL_SUBJECT - тема письма
Telegram использует Markdown с эмодзи:
- 🔴 критично (7 дней и меньше)
- 🟡 средне (8-14 дней)
- 🟠 низко (15-30 дней)
- ❌ просрочен
Email отправляется в HTML и plain text форматах.
- INFO - основная информация
- DEBUG - детальная информация (при VERBOSE=true)
Формат: YYYY-MM-DD HH:MM:SS - LEVEL - message
| Ошибка | Результат |
|---|---|
| Нет SCAN_DIRECTORY | выход с кодом 1 |
| Директория не существует | выход с кодом 1 |
| Нет прав на чтение | выход с кодом 1 |
| Ошибки сертификатов | пропуск файла |
| Ошибки уведомлений | логирование, продолжение |
MIT © 2026
Основной модуль для сканирования и анализа SSL/TLS сертификатов.
Этот модуль предоставляет функциональность для:
- Парсинга аргумента командной строки, указание кастомного .env.custom
- Загрузки переменных окружения из .env в корне проекта
- Сканирования каталога с сертификатами
- Анализа сроков действия сертификатов
- Отправки уведомлений о проблемных сертификатах (telegram/email)
def load_environment(env_file_path: str | None = None,
verbose: bool = False) -> NoneЗагружает переменные окружения из .env файла.
Логика:
- Если передан env_file_path, загружается ТОЛЬКО этот файл (очищаются существующие переменные)
- Если env_file_path не передан, ищется .env в стандартных местах
Arguments:
env_file_pathstr | None - Путь к .env файлу (из аргументов командной строки) может быть и Noneverbosebool - Логировать ли процесс загрузки
Returns:
None
Raises:
SystemExit- Если указанный файл не существует
def setup_logging(verbose: bool = False) -> NoneНастройка системы логирования.
Arguments:
verbosebool - Если True, устанавливается уровень DEBUG, иначе INFO
Returns:
None
def scan_certificates(directory_path: str) -> list[Path]Сканирует указанный каталог и возвращает список всех файлов с расширением .crt.
Arguments:
directory_pathstr - Путь к директории для сканирования
Returns:
List[Path]- Список путей к файлам сертификатов
Raises:
FileNotFoundError- Если указанный путь не существуетNotADirectoryError- Если указанный путь не является каталогом
def get_certificate_expiry(
cert_path: Path) -> tuple[datetime, datetime] | NoneПолучает даты начала и истечения срока действия сертификата.
Arguments:
cert_pathPath - Путь к файлу сертификата
Returns:
tuple[datetime, datetime] | None: Кортеж (дата_начала, дата_истечения) или None при ошибке
def parse_certificates_expiry(
certificate_paths: list[Path]
) -> list[tuple[Path, datetime | None, datetime | None]]Анализирует список сертификатов и возвращает информацию о сроках их действия.
Arguments:
certificate_pathslist[Path] - Список путей к сертификатам
Returns:
list[tuple[Path, datetime | None, datetime | None]]: Список кортежей (путь, дата_начала, дата_истечения)
def display_certificate_detail(cert_path: Path, start_date: datetime | None,
expiry_date: datetime | None,
current_date_utc: datetime) -> NoneОтображает детальную информацию об одном сертификате.
Arguments:
cert_pathPath - Путь к файлу сертификатаstart_datedatetime | None - Дата начала действияexpiry_datedatetime | None - Дата истеченияcurrent_date_utcdatetime - Текущая дата для расчета статуса
Returns:
None
def build_notification_message(expired_certs: list[tuple[Path, datetime | None,
datetime | None]],
expiring_certs: list[tuple[Path,
datetime | None,
datetime | None]],
expiring_days: int,
format_type: str = "text") -> strФормирует сообщение уведомления о проблемных сертификатах.
Arguments:
expired_certslist[tuple[Path, datetime | None, datetime | None]] - Список просроченных сертификатовexpiring_certslist[tuple[Path, datetime | None, datetime | None]] - Список сертификатов, истекающих в ближайшее времяexpiring_daysint - Количество дней для фильтрации "скоро истекающих"format_typestr - Формат сообщения ('text' или 'html')
Returns:
str- Сформированное сообщение
Raises:
ValueError- Если указан неподдерживаемый формат
def send_email_notification(
expired_certs: list[tuple[Path, datetime | None, datetime | None]],
expiring_certs: list[tuple[Path, datetime | None, datetime | None]],
expiring_days: int,
smtp_host: str,
smtp_port: int,
use_tls: bool,
username: str,
password: str,
from_addr: str,
to_addrs: list[str],
subject: str = "🔔 Уведомление о сертификатах") -> boolОтправляет уведомление по email о проблемных сертификатах.
Arguments:
expired_certslist[tuple[Path, datetime | None, datetime | None]] - Список просроченных сертификатовexpiring_certslist[tuple[Path, datetime | None, datetime | None]] - Список сертификатов, истекающих в ближайшее времяexpiring_daysint - Количество дней для фильтрации "скоро истекающих"smtp_hoststr - SMTP серверsmtp_portint - Порт SMTP сервераuse_tlsbool - Использовать ли TLSusernamestr - Имя пользователя для авторизацииpasswordstr - Пароль для авторизацииfrom_addrstr - Email отправителяto_addrslist[str] - Список email получателейsubjectstr - Тема письма
Returns:
bool- True если сообщение успешно отправлено, False в противном случае
def send_telegram_notification(expired_certs: list[tuple[Path, datetime | None,
datetime | None]],
expiring_certs: list[tuple[Path,
datetime | None,
datetime | None]],
expiring_days: int, bot_token: str,
chat_id: str) -> boolОтправляет уведомление в Telegram о проблемных сертификатах.
Arguments:
expired_certslist[tuple[Path, datetime | None, datetime | None]] - Список просроченных сертификатовexpiring_certslist[tuple[Path, datetime | None, datetime | None]] - Список сертификатов, истекающих в ближайшее времяexpiring_daysint - Количество дней для фильтрации "скоро истекающих"bot_tokenstr - Токен Telegram ботаchat_idstr - ID чата/канала для отправки сообщения
Returns:
bool- True если сообщение успешно отправлено, False в противном случае
def display_grouped_certificate_info(
expired_certs: list[tuple[Path, datetime | None, datetime | None]],
expiring_certs: list[tuple[Path, datetime | None, datetime | None]],
valid_certs: list[tuple[Path, datetime | None, datetime | None]]
| None = None,
expiring_days: int = 30) -> NoneОтображает информацию о сертификатах в сгруппированном виде с единой статистикой.
Arguments:
expired_certslist[tuple[Path, datetime | None, datetime | None]] - Список просроченных сертификатовexpiring_certslist[tuple[Path, datetime | None, datetime | None]] - Список сертификатов, истекающих в ближайшее времяvalid_certslist[tuple[Path, datetime | None, datetime | None]] | None = None - Список действительных сертификатов (опционально)expiring_daysint - Количество дней для фильтрации "скоро истекающих"
Returns:
None
def parse_arguments() -> argparse.NamespaceПарсинг аргументов командной строки - принимает только путь к .env файлу.
Returns:
argparse.Namespace- Объект с аргументами командной строки
def main() -> NoneОсновная функция программы для сканирования и анализа сертификатов.
Выполняет следующие шаги:
- Парсит аргументы командной строки (путь к .env файлу)
- Загружает переменные окружения из .env файла
- Настраивает систему логирования
- Проверяет наличие обязательных параметров (SCAN_DIRECTORY)
- Сканирует указанный каталог для поиска .crt файлов
- Анализирует каждый найденный сертификат (даты начала и истечения)
- Фильтрует сертификаты по сроку истечения (если указан EXPIRING_DAYS)
- Отображает результаты проверки в консоли
- Отправляет уведомления о проблемных сертификатах в Telegram и/или Email
- Завершает работу с соответствующим кодом возврата
Arguments:
None (использует аргументы командной строки и переменные окружения)
Returns:
None
Raises:
SystemExit- Выход из программы с кодом:- 0: Успешное завершение, ошибок нет
- 1: Ошибка (отсутствует SCAN_DIRECTORY, файл не найден, ошибка доступа и т.д.)
Notes:
Переменные окружения, используемые в функции:
- SCAN_DIRECTORY (обязательный): Путь к каталогу с сертификатами
- VERBOSE (опциональный): Режим отладки (true/false, по умолчанию false)
- EXPIRING_DAYS (опциональный): Порог истечения в днях для фильтрации
- TELEGRAM_BOT_TOKEN (опциональный): Токен Telegram бота
- TELEGRAM_CHAT_ID (опциональный): ID чата Telegram
- EMAIL_ENABLED (опциональный): Включить Email уведомления
- EMAIL_SMTP_HOST (опциональный): SMTP сервер
- EMAIL_SMTP_PORT (опциональный): Порт SMTP (по умолчанию 587)
- EMAIL_USE_TLS (опциональный): Использовать TLS (по умолчанию true)
- EMAIL_USERNAME (опциональный): Имя пользователя для SMTP
- EMAIL_PASSWORD (опциональный): Пароль для SMTP
- EMAIL_FROM (опциональный): Email отправителя
- EMAIL_TO (опциональный): Список получателей (через запятую)
- EMAIL_SUBJECT (опциональный): Тема письма
Examples:
Базовый запуск: $ python main.py
Запуск с конкретным .env файлом: $ python main.py /path/to/.env
Запуск с переменными окружения: $ SCAN_DIRECTORY=/etc/ssl/certs python main.py