metalnikovg.ru
MetalnikovG.ru

Повышение безопасности Docker с помощью CrowdSec и Traefik

Banner.png
Опубликовано
//
7 мин. чтения

CrowdSec — это бесплатный, современный и совместный механизм обнаружения угроз, связанный с глобальной сетью репутации IP-адресов. Он основан на философии fail2ban, но совместим с IPv6 и в 60 раз быстрее, так как написан на Go. CrowdSec разработан для современных инфраструктур на основе облака / контейнеров / виртуальных машин. После обнаружения вы можете устранить угрозы с помощью различных баунсеров (блокировка брандмауэра, nginx http 403, Captcha и т. д.), в то время как агрессивный IP-адрес может быть отправлен в CrowdSec для курирования, прежде чем будет распространен среди всех пользователей для дальнейшего повышения безопасности каждого.

Crowdsec состоит из 3 компонентов:

  • Local API (LAPI)
  • CSCLI - консоль управления
  • Bouncer (вышибала)

В этой заметке будет показан пример использования вместе с Traefik

1. Запуск Crowdsec

Запускать Crowdsec будем в docker-контейнере, для этого создадим файл со следующим содержимым:

docker-compose.yaml
---
services:
  crowdsec:
    image: crowdsecurity/crowdsec:latest
    container_name: crowdsec
    environment:
      GID: "${GID-1000}"
      COLLECTIONS: "crowdsecurity/linux crowdsecurity/traefik crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules"
      TZ: Europe/Moscow
    volumes:
      - ./acquis.yaml:/etc/crowdsec/acquis.yaml
      - ./db:/var/lib/crowdsec/data/
      - ./config:/etc/crowdsec/
      - /home/<user>/docker/traefik/logs:/var/log/traefik/:ro
    networks:
      - proxy
    security_opt:
      - no-new-privileges:true
    restart: unless-stopped

networks:
  proxy:
    external: true

После этого создаем файл конфигурации acquis.yaml:

acquis.yaml
filenames:
  - /var/log/traefik/*
labels:
  type: traefik

---
listen_addr: 0.0.0.0:7422
appsec_config: crowdsecurity/virtual-patching
name: myAppSecComponent
source: appsec
labels:
  type: appsec

---
source: docker
container_name:
 - authentik-server-1
labels:
  type: authentik
docker_host: tcp://192.168.78.100:2375

---
source: docker
container_name:
  - traefik
labels:
  type: traefik
docker_host: tcp://192.168.78.100:2375

---
source: docker
container_name:
  - vaultwarden
labels:
  type: Vaultwarden
docker_host: tcp://192.168.78.102:2375

---
source: docker
container_name:
  - grafana
labels:
  type: Grafana
docker_host: tcp://192.168.78.101:2375

---
listen_addr: 0.0.0.0:7422
appsec_config: crowdsecurity/virtual-patching
name: myAppSecComponent
source: appsec
labels:
  type: appsec

Теперь можем запускать контейнер

docker compose up -d

2. Подключаем плагин в Traefik

В качестве вышибалы будем использовать плагин Crowdsec Bouncer Traefik plugin. Для подключения, откроем файл статической конфигурации Traefik и добавим в конец следующие строки:

traefik.yaml
experimental:
  plugins:
    crowdsec-bouncer-traefik-plugin:
      moduleName: "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
      version: "v1.4.1"

Перезапускаем контейнер на всякий случай с флагом пересоздания:

docker compose up -d --force-recreate

Проверяем что плагин загрузился в /log/traefik.log

2024-10-11T17:51:26+03:00 INF Loading plugins... plugins=["crowdsec-bouncer-traefik-plugin"]
2024-10-11T17:51:26+03:00 INF Plugins loaded. plugins=["crowdsec-bouncer-traefik-plugin"]

Проверяем что Crowdsec получает метрики из Traefik:

docker exec crowdsec cscli metrics

WARNING

Чтобы crowdsec смог считать логи из traefik, сначала должен быть запущен контейнер crowdsec

3. Подключаем Bouncer:

Для подключение баунсера необходимо получить LAPI-key, для этого используем команду:

docker exec crowdsec cscli bouncers add crowdsecBouncer

Копируем и сохраняем полученный ключ.

Создаем файл динамической конфигурации traefik crowdsec.yml

crowdsec.yml
http:
  middlewares:
    crowdsec:
      plugin:
        crowdsec-bouncer-traefik-plugin:
          enabled: true
          logLevel: INFO
          updateIntervalSeconds: 15
          updateMaxFailure: 0
          defaultDecisionSeconds: 15
          httpTimeoutSeconds: 10
          crowdsecMode: stream
          crowdsecAppsecEnabled: true
          crowdsecAppsecHost: crowdsec:7422
          crowdsecAppsecFailureBlock: true
          crowdsecAppsecUnreachableBlock: true
          crowdsecLapiKey: your-lapi-key    # Replace CrowdSec API key (docker exec crowdsec cscli bouncers add crowdsecBouncer)
 #         crowdsecLapiKeyFile: /etc/traefik/cs-privateKey-foo
          crowdsecLapiHost: crowdsec:8080
          crowdsecLapiScheme: http
          forwardedHeadersTrustedIPs: # List of IPs of trusted Proxies that are in front of traefik (ex: Cloudflare)
            - 73.245.48.0/20
            - 103.21.244.0/22
            - 103.22.200.0/22
            - 103.31.4.0/22
            - 141.101.64.0/18
            - 108.162.192.0/18
            - 190.93.240.0/20
            - 188.114.96.0/20
            - 197.234.240.0/22
            - 198.41.128.0/17
            - 162.158.0.0/15
            - 104.16.0.0/13
            - 104.24.0.0/14
            - 172.64.0.0/13
            - 131.0.72.0/22
          clientTrustedIPs: # List of client IPs to trust, they will bypass any check from the bouncer or cache (useful for LAN or VPN IP)
            - 192.168.78.0/24

Вставляем полученный lapi-key в строку crowdsecLapiKey, в clientTrustedIPs указываем нашу локальную подсеть или VPN, а в forwardedHeadersTrustedIPs указываем список IP адресов Cloudflare которые используются для проксирования.

TIP

Так как мы используем Cloudflare в качестве прокси перед нашим Traefik, важно настроить forwardedHeadersTrustedIPs так, чтобы Traefik доверял IP-адресам Cloudflare. Это необходимо для корректного определения реального IP-адреса клиента через заголовок X-Forwarded-For и корректной работы баунсера crowdsec.

NOTE

Cloudflare предоставляет список своих IP-адресов, которые используются для проксирования трафика. Эти IP-адреса нужно добавить в forwardedHeadersTrustedIPs, чтобы Traefik мог доверять заголовкам, переданным от Cloudflare.

Теперь открываем файл статической конфигурации traefik.yml добавляем в него промежуточный слой - crowdsec@file и forwardedHeadersTrustedIPs:

traefik.yml
api:
  dashboard: true
  debug: true
entryPoints:
  http:
    address: ":80"
    forwardedHeaders:
      trustedIPs:
        - 73.245.48.0/20
        - 103.21.244.0/22
        - 103.22.200.0/22
        - 103.31.4.0/22
        - 141.101.64.0/18
        - 108.162.192.0/18
        - 190.93.240.0/20
        - 188.114.96.0/20
        - 197.234.240.0/22
        - 198.41.128.0/17
        - 162.158.0.0/15
        - 104.16.0.0/13
        - 104.24.0.0/14
        - 172.64.0.0/13
        - 131.0.72.0/22
    http:
      middlewares:
        - crowdsec@file
      redirections:
        entryPoint:
          to: https
          scheme: https
  https:
    address: ":443"
    forwardedHeaders:
      trustedIPs:
        - 73.245.48.0/20
        - 103.21.244.0/22
        - 103.22.200.0/22
        - 103.31.4.0/22
        - 141.101.64.0/18
        - 108.162.192.0/18
        - 190.93.240.0/20
        - 188.114.96.0/20
        - 197.234.240.0/22
        - 198.41.128.0/17
        - 162.158.0.0/15
        - 104.16.0.0/13
        - 104.24.0.0/14
        - 172.64.0.0/13
        - 131.0.72.0/22
    http:
      middlewares:
        - crowdsec@file
  metrics:
    address: ":8082"

serversTransport:
  insecureSkipVerify: true
providers:
  file:
    directory: /config
    watch: true
certificatesResolvers:
  cloudflare:
    acme:
      email: mail@example.com #add your rmail
      storage: acme.json
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - "1.1.1.1:53"
          - "1.0.0.1:53"
metrics:
  prometheus:
    entryPoint: metrics
log:
  level: "DEBUG"
  filePath: "/var/log/traefik/traefik.log"
accessLog:
  filePath: "/var/log/traefik/access.log"

experimental:
  plugins:
    crowdsec-bouncer-traefik-plugin:
      moduleName: "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
      version: "v1.4.1"

Перезапускаем Traefik:

docker compose up -d

Чтобы убедиться что Traefik определяет реальные IP адреса клиентов, откройте любой из ваших опубликованных ресурсов и посмотрите логи:

cat /home/user/docker/traefik/logs/access.log

Вы должны увидеть в них внешний IP-адрес предоставляемый вашим провайдером.

4. Автоматическое обновление баз Crowdsec

Для лучшей защиты нам необходимо получать постоянные обновления баз Crowdsec. Чтобы настроить автоматическое обновление баз Crowdsec, воспользуемся cron

crontab -e

Выбираем пункт 1 и вставляем в конец файла строку:

* 3 * * * docker exec crowdsec cscli hub update && docker exec crowdsec cscli hub upgrade
Это означает что локальные базы crowdsec будут обновляться каждые 3 часа.

5. Подключение дашборда

Для визуализации и алертов, Crowdsec предлагает свой онлайн панель управления. Чтоб подключить ее переходим на https://app.crowdsec.net/sign-in и создаем аккаунт. После входа в аккаунт нам предложат подключить наш Crowdsec Engine и дадут готовую команду для этого:

Но так как у нас Crowdsec запущен в docker-контейнере, мы ее немного изменим:

docker exec crowdsec cscli console enroll -e context cm24-----------------kzbi

Возвращаемся а личный кабинет и нажимаем Accept enroll

После этого внизу появится панелька:

Чтобы отобразились алерты надо перезапустить контейнер crowdsec.

6. Прогрессивное увеличение времени бана для Crowdsec

Для динамического увеличения продолжительности бана угрозы обнажаемой crowdsek необходимо изменить в файле /crowdsek/config/profiles.yaml строку параметра:

duration_expr: "Sprintf('%dh', (GetDecisionsCount(Alert.GetValue()) + 1) * 8)"

означает следующее:

  • GetDecisionsCount(Alert.GetValue()) — это функция, которая возвращает количество предыдущих решений (банов) для данного источника (например, IP-адреса).
  • + 1 — добавляет 1 к количеству предыдущих решений, чтобы учитывать текущее решение.
  • * 8 — умножает общее количество решений на 8, что означает, что время бана будет увеличиваться на 8 часа за каждое предыдущее решение.
  • Sprintf('%dh', ...) — форматирует результат в строку, представляющую количество часов.

Подробнее в документации: Format | CrowdSec

7. Команды crowdsec cscli

Для получения статуса системы:

docker exec crowdsec cscli metrics

Список заблокированных

docker exec crowdsec cscli decisions list

Ручная блокировка по IP

docker exec crowdsec cscli decisions add --ip <ip>

Снятие блокировки

docker exec crowdsec cscli decisions delete --ip <ip>

Обновление базы данных выполняется командами:

docker exec crowdsec cscli hub update && docker exec crowdsec cscli hub upgrade

Проверка конфигурации CrowdSec (позволяет нам увидеть, какие парсеры и сценарии развернуты):

docker exec crowdsec cscli hub list

Показ списка всех сработавших алертов:

docker exec crowdsec cscli alerts list

Показ более подробной информации о конкретном алерте:

docker exec crowdsec cscli alerts inspect -d <ALERT ID>

Заключение

Мы настроили защиту нашего сервера с помощью Crowdsec и плагина-баунсера для Traefik. Настроили автоматическое обновление баз и подключили онлайн панель управления.

Спустя какое-то время зайдя в дашборд вы убедитесь в необходимости Crowdsec.

← Предыдущая заметкаCоздание Cloudflare Tunnel
Следующая заметка →Реализация SSO с помощью Authentik