Казалось бы, что может быть сложного в мониторинге сертификатов? Выдан сертификат – следите за его сроком действия. Многие по старинке используют календари, напоминания, иногда даже физические заметки. Но ручные методы неидеальны, ведь люди ошибаются, забывают и теряют информацию.
И если не автоматизировать такие моменты, то однажды можете проснуться и узнать, что сервис недоступен из-за протухшего сертификата. Давайте разберёмся, что к чему.
Глубже в технику: Grafana, Prometheus и наши экспортеры
Сначала запустим Grafana и Prometheus - это наши главные инструменты для мониторинга. Затем поболтаем об экспортерах и подключим один из них, добавим крутую панельку с графиками. Чтобы всё это дело не пропустить, научим Alertmanager слать нам уведомления в Telegram.
1. Начнем с основ: Grafana + Prometheus и Docker Compose
Для тех, кто в теме и уже тысячу раз слышал о awesome-compose/prometheus-grafana, шаг можно пропустить. Для остальных - вам понадобится compose.yml
файл:
services:
prometheus:
image: prom/prometheus
container_name: prometheus
command:
- "--config.file=/etc/prometheus/prometheus_config.yml"
ports:
- 9090:9090
restart: unless-stopped
volumes:
- ./prometheus:/etc/prometheus
- prom_data:/prometheus
grafana:
image: grafana/grafana
container_name: grafana
ports:
- 3000:3000
restart: unless-stopped
env_file: .env
environment:
- GF_SECURITY_ADMIN_USER=${GF_SECURITY_ADMIN_USER}
- GF_SECURITY_ADMIN_PASSWORD=${GF_SECURITY_ADMIN_PASSWORD}
volumes:
- ./grafana:/etc/grafana/provisioning/datasources
volumes:
prom_data:
Теперь создайте директорию prometheus
с файлом prometheus_config.yml
:
global:
scrape_interval: 15s
scrape_timeout: 10s
evaluation_interval: 15s
И то же самое для директории grafana
и файла datasource.yml
:
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
url: http://prometheus:9090
isDefault: true
access: proxy
editable: true
В примере будем хранить секреты в файле:
.env
. Но лучше так не делать, потому что файл может легко попасть в открытый доступ. Используйте для хранения секретов специальные инструменты, шифруйте файлы и все будет хорошо.
Создайте файл .env
и добавьте ИМЯ_ПОЛЬЗОВАТЕЛЯ_GRAFANA
и ПАРОЛЬ_ПОЛЬЗОВАТЕЛЯ_GRAFANA
:
GF_SECURITY_ADMIN_USER=<ИМЯ_ПОЛЬЗОВАТЕЛЯ_GRAFANA>
GF_SECURITY_ADMIN_PASSWORD=<ПАРОЛЬ_ПОЛЬЗОВАТЕЛЯ_GRAFANA>
Поднимаем всю эту красоту:
docker-compose up -d
Так, магия Docker сработала, и у нас есть Grafana на порту 3000 и Prometheus на 9090. Просто? Просто!
2. Погружаемся в мир экспортеров: выбор инструмента
Каждый экспортер имеет свои плюсы и минусы. Ведь как говорится, каждая кисть хороша
на своем холсте. Разберемся, какой из них лучше всего подойдет для вас:
ssl_exporter: его задача — сертификаты и только. Дает богатую информацию о сертификатах: даты истечения, алгоритмы, подписи и многое другое. Поддерживает различные моды для проверки: TCP, HTTPS, SMTP и так далее. Но если нужно больше, чем просто мониторинг SSL/TLS, придется искать дополнительные инструменты.
blackbox_exporter: умеет делать многое, он все проверит, в том числе и сертификаты. Если сравнивать с ssl_exporter, детализация данных и возможности могут показаться слабее. Избыточен, если нужен только мониторинг сертификатов, но отлично подойдет для комплексного мониторинга.
node-cert-exporter: если вам нужно отслеживать сертификаты на диске, это ваш выбор. Очень прост в использовании и не требует больших знаний.
x509-certificate-exporter: дает подробную информацию о сертификатах. Гибкий, может извлекать данные файлов или секретов Kubernetes. Сложнее в настройке и эксплуатации по сравнению с некоторыми другими инструментами.
cert_exporter: поддерживает множество источников сертификатов, включая файловую систему, Kubernetes и другие. Весьма универсален для разных сценариев использования.
Итак, какой инструмент выбрать? Выбор инструмента – это искусство, и, как и в любом искусстве, здесь есть свои тонкости и нюансы. Выбирайте то, что соответствует вашим потребностям и не бойтесь экспериментировать.
3. Работа с ssl_exporter
Мы уже обсудили, что представляет собой ssl_exporter. Следит за сертификатами хорошо
и по-разному. Давайте добавим его в compose.yml
:
ssl_exporter:
image: ribbybibby/ssl-exporter
ports:
- "9219:9219"
Сегодня нашей целью будет prometheus.io
. Добавляем scrape_configs
в prometheus_config.yml
:
scrape_configs:
- job_name: "ssl-exporter"
metrics_path: /probe
static_configs:
- targets:
- prometheus.io:443
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: ssl_exporter:9219
Так, перезапускаем наш compose.yml
:
docker-compose restart
В Prometheus выполняем PromQL запрос – ssl_probe_success
и если мы видим следующее, то значит настроили все верно:
ssl_probe_success{instance="prometheus.io:443", job="ssl-exporter"}
По умолчанию экспортер создает TCP-соединение с целью. В большинстве случаев этого хватает, но если вы хотите использовать проксирование через http, используйте модуль https
. Кроме того, можно с помощью file
следить за сертификатами на диске:
scrape_configs:
- job_name: "ssl-files"
metrics_path: /probe
params:
module: ["file"]
target: ["/etc/ssl/cert.pem"]
kubernetes_sd_configs:
- role: node
relabel_configs:
- source_labels: [__address__]
regex: ^(.*):(.*)$
target_label: __address__
replacement: ${1}:9219
Если сертификатов несколько, можно использовать глоб-поиск, что позволяет захватить сразу несколько файлов:
scrape_configs:
- job_name: "ssl-files"
metrics_path: /probe
params:
module: ["file"]
target: ["/etc/ssl/**/*.pem"]
kubernetes_sd_configs:
- role: node
relabel_configs:
- source_labels: [__address__]
regex: ^(.*):(.*)$
target_label: __address__
replacement: ${1}:9219
Также можно использовать в связке с Kubernetes, в документации больше информации.
4. Добавляем панель в Grafana
Велосипед изобретать не будем, а просто авторизовываемся и импортируем готовую панель из репозитория ssl_exporter:
Как не проспать проблемы
Что у нас в планах? Поднимем невероятно простой, но очень полезный сервис на Flask'е, который будет ловить уведомления от Alertmanager и пересылать их в Telegram. Создадим бот и настроим Alertmanager на отправку уведомлений.
1. Взлетаем с Flask
Ладно, не будем мелочиться, заводим директорию telegram
и кидаем туда файлик app.py
с элегантным, минималистичным и в стиле true pythonista кодом:
import os
import requests
from flask import Flask, request, jsonify
app = Flask(__name__)
TELEGRAM_TOKEN = os.environ["TELEGRAM_TOKEN"]
CHAT_ID = os.environ["TELEGRAM_CHAT_ID"]
TELEGRAM_URL = f"https://api.telegram.org/bot{TELEGRAM_TOKEN}/sendMessage"
@app.route("/alert", methods=["POST"])
def webhook():
data = request.json
alertname = data["alerts"][0]["labels"]["alertname"]
instance = data["alerts"][0]["labels"]["instance"]
summary = data["alerts"][0]["annotations"]["summary"]
text = f"⚠️ Alarm! {alertname} for {instance}. \n{summary}"
payload = {"chat_id": CHAT_ID, "text": text}
response = requests.post(TELEGRAM_URL, data=payload)
return jsonify(status="success"), 200
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
А еще пригодится Dockerfile
:
FROM python:3.10-alpine
WORKDIR /app
COPY . /app
RUN pip3 install -r requirements.txt
ENTRYPOINT ["python3"]
CMD ["app.py"]
Ну и, разумеется, незаменимый requirements.txt
:
flask
requests
2. Крафтим бота:
Запустим
@BotFather
в Telegram./newbot
, даем ему имя и вуаля! У вас в руках:ТОКЕН_БОТА
.Выясним свой chat_id, отправив
/start
своему боту и заглянув наhttps://api.telegram.org/bot<ТОКЕН_БОТА>/getUpdates
. Найдитеresult[0]message.chat.id
и запомните, это будет вашВАШ_ЧАТ_ID
.
Теперь добавьте всё это в compose.yml
:
telegram:
build:
context: telegram
stop_signal: SIGINT
env_file: .env
environment:
- TELEGRAM_TOKEN=${TELEGRAM_TOKEN}
- TELEGRAM_CHAT_ID=${TELEGRAM_CHAT_ID}
ports:
- "8000:8000"
А секреты ТОКЕН_БОТА
и ВАШ_ЧАТ_ID
в .env
:
TELEGRAM_TOKEN=<ТОКЕН_БОТА>
TELEGRAM_CHAT_ID=<ВАШ_ЧАТ_ID>
3. Дружим Alertmanager с Telegram
Пришло время разобраться, куда именно будем слать уведомления. Теоретически Alertmanager может отправлять сообщения куда угодно, но мы-то знаем, что сегодня наш выбор – Telegram.
Начнем с малого. Напишем правило, которое даст нам знать, когда у сертификата останется менее 90 дней жизни. Для желающих углубиться - в документации собраны разные запросы. В prometheus
создаем файл alert.rules.yml
и пишем туда:
groups:
- name: ssl-alerts
rules:
- alert: Expiry Soon
expr: ssl_cert_not_after - time() < 86400 * 90
for: 1m
labels:
severity: critical
annotations:
summary: "SSL certificate is expiring soon (less than 90 days)"
Допишем пару строк в prometheus_config.yml
:
rule_files:
- "/etc/prometheus/alert.rules.yml"
alerting:
alertmanagers:
- static_configs:
- targets:
- "alertmanager:9093"
Теперь давайте сделаем следующее: создадим директорию под названием alertmanager
и положим в нее файл alertmanager_config.yml
:
route:
group_by: ["instance"]
repeat_interval: 3h
receiver: "telegram-webhook"
receivers:
- name: "telegram-webhook"
webhook_configs:
- url: "http://telegram:8000/alert"
Что ж, наш compose.yml
тоже хочет внимания, добавляем контейнер alertmanager
:
alertmanager:
image: quay.io/prometheus/alertmanager
container_name: alertmanager
command:
- "--config.file=/etc/alertmanager/alertmanager_config.yml"
ports:
- "9093:9093"
volumes:
- ./alertmanager:/etc/alertmanager
А теперь — магия:
docker-compose down; docker-compose up -d
Итак, смотрим, что наш Alertmanager чувствует себя комфортно:
и правило в Prometheus заняло свою рабочую позицию:
Примерно через минуту Prometheus поймет, что есть какие-то проблемы:
И еще примерно через 30 секунд Alertmanager отправит уведомление в наш сервис:
Который перешлет его к вам в Telegram:
Вот и всё! Теперь у вас в арсенале есть бот, который держит руку на пульсе ваших сервисов и, в случае чего, моментально бьет тревогу! Ну что, вы ведь тоже чувствуете этот аромат возможностей?
Заключение
Мониторинг сертификатов — это не мания, это забота. Наслаждайтесь комфортом, технологичностью, не забывайте поливать свои растения и мониторить сертификаты.