Казалось бы, что может быть сложного в мониторинге сертификатов? Выдан сертификат – следите за его сроком действия. Многие по старинке используют календари, напоминания, иногда даже физические заметки. Но ручные методы неидеальны, ведь люди ошибаются, забывают и теряют информацию.

И если не автоматизировать такие моменты, то однажды можете проснуться и узнать, что сервис недоступен из-за протухшего сертификата. Давайте разберёмся, что к чему.

Глубже в технику: 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. Погружаемся в мир экспортеров: выбор инструмента

Каждый экспортер имеет свои плюсы и минусы. Ведь как говорится, каждая кисть хороша
на своем холсте. Разберемся, какой из них лучше всего подойдет для вас:

Итак, какой инструмент выбрать? Выбор инструмента – это искусство, и, как и в любом искусстве, здесь есть свои тонкости и нюансы. Выбирайте то, что соответствует вашим потребностям и не бойтесь экспериментировать.

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:

В панели SSL Certificates отображается таблица с данными о каждом сертификате: его имя, инстанс, имя эмитента, выдавшего сертификат, серийный номер и время жизни. Экспортер имеет обширный набор метрик, позволяющих настроить панель под любые потребности.
В панели SSL Certificates отображается таблица с данными о каждом сертификате: его имя, инстанс, имя эмитента, выдавшего сертификат, серийный номер и время жизни. Экспортер имеет обширный набор метрик, позволяющих настроить панель под любые потребности.

Как не проспать проблемы

Что у нас в планах? Поднимем невероятно простой, но очень полезный сервис на 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. Крафтим бота:

  1. Запустим @BotFather в Telegram.

  2. /newbot, даем ему имя и вуаля! У вас в руках: ТОКЕН_БОТА.

  3. Выясним свой 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:

Вот и всё! Теперь у вас в арсенале есть бот, который держит руку на пульсе ваших сервисов и, в случае чего, моментально бьет тревогу! Ну что, вы ведь тоже чувствуете этот аромат возможностей?

Заключение

Мониторинг сертификатов — это не мания, это забота. Наслаждайтесь комфортом, технологичностью, не забывайте поливать свои растения и мониторить сертификаты.

Комментарии (12)


  1. mr_zibit
    25.09.2023 19:50
    +4

    на мой взгляд в заголовке ошибка: "Grafana: искусство мониторинга сертификатов" -> "Prometheus: искусство мониторинга сертификатов", т.к. МОНИТОРИНГ будет работать и без Grafana

    а еще я бы использовал https://github.com/prometheus/blackbox_exporter/blob/master/CONFIGURATION.md#tls_config в качестве основы (более того, уже был материал на эту тему - https://habr.com/ru/companies/hostkey/articles/729898/)


    1. znhv Автор
      25.09.2023 19:50

      Здравствуйте, согласен, с заголовком промахнулся, уже поправил. Спасибо.


  1. 321785
    25.09.2023 19:50
    -2

    А зачем мониторить то, что должно автоматически обновляться, например тем же certbot?
    А вот отказ/просрочка обновления сертификата мониторить интересно.


    1. aborouhin
      25.09.2023 19:50
      +2

      Ну так с тем же certbot / acme.sh что-то пойти не так может как минимум на трёх этапах:

      • не отработал сам certbot / acme.sh (используемый по умолчанию последним zerossl, скажем, в один прекрасный момент прекратил выдачу сертификатов для доменов ru);

      • не отработало преобразование сертификатов в форматы, необходимые разным сервисам (кому-то Java keystore подавай, кому-то что-то ещё);

      • не отработало копирование сертификатов с сервера, на котором мы обновляем сертификаты, на серверы, где они используются (Ansible playbook или что там для этого используется).

      У меня это всё автоматизировано через тот самый Ansible, скажем, но всегда полезно заранее узнать, если что-то не так.


    1. BugM
      25.09.2023 19:50

      Мониторить нужно все работа чего для вас важна. Непротухшие сертификаты точно важны. Мало ли что пошло не так. Всякое бывает в этом мире.


  1. saboteur_kiev
    25.09.2023 19:50
    +2

    Капец, что только не наворотят, лишь бы скрипты на баше не писать. (шутка).

    У меня несколько источников. Папка с сертификатами, секреты в опенщифте, сертификаты в роутах, наконец урл-ы. Секреты могут лежать в p12 или jks формате, с разными паролями.

    Не знаю, зачем для мониторинга поднимать пачку компосов и сервисов. Скрипт на баше, который пробегает по всему, генерирует удобный html отчет, параллельно может скинуть статистику в инфлюкс для графаны, и отправить алерт на емайл.

    Для тех, у кого автоматом цертбот - есть конторы, где сертификаты выдает корпоративный авторити. К нему может существовать какой-нить API, а может наоборот существовать только бюрократизированный подход с ручным аппрувалом. Поэтому мониторинг не равен автозамене, и может быть важен.


  1. AzamatKomaev
    25.09.2023 19:50

    У меня все TLS сертификаты от Let's Encrypt и алерты о том, что скоро один из них истечет приходят на почту которую я указал при создании.

    Есть также сертификаты, созданные в Yandex Cloud, туда же можно добавить свои собственные. И через систему мониторинга облака накинуть алерт. Единственный минус - алерт будет приходить либо как push уведомление, либо как смс.


    1. aborouhin
      25.09.2023 19:50

      Только если сертификат успешно выпущен, но не встал или криво встал на сервер (а этот процесс иногда довольно замысловат, если это не просто nginx на публично доступном адресе, а какая-нибудь java, которой keystore подавай, в докере) - такой мониторинг Вам об этом не расскажет.


  1. heroOfOurTime
    25.09.2023 19:50
    +5

    Непонятно, зачем нужен отдельный питон-сервис, если алертменеджер сам умеет в телегу и в тексте даже есть прямая ссылка на <telegram_config>


    1. znhv Автор
      25.09.2023 19:50
      -1

      Здравствуйте, да, можно сделать сразу через Alertmanager. Отдельный сервис будет полезен, если захочется обработать какой-то случай по-особенному.


  1. Inoriol
    25.09.2023 19:50
    +1

    Если уж Grafan'у использовать, то лучше её внутренний Alertmanager, как по мне. Интерфейс почеловечнее, да и можно к дашборду прицепить проще


    1. aborouhin
      25.09.2023 19:50

      Да, удобнее. И алерты прямо из панелей создавать удобно, PromQL запрос сразу переносится и ссылка на дашборд прикрепляется. У меня у самого именно так.

      Но вот если масштабироваться и Prometheus'ов будет уже несколько, а Grafana на них одна - то использование её встроенного алертинга снижает надёжность такой системы.