528 - Más herramientas para proteger tu Linux

528 - Más herramientas para proteger tu Linux

Dos herramientas para proteger tu servidor #linux , la clásica #fail2ban y #crowdsec ambas para intentar evitar ataques de terceros e intentos de acceso

1:25
-3:15

Después del episodio del podcast número 526, titulado sobre seguridad en Docker y selfhosted, no te creas que me quedé muy tranquilo. En ningún caso, quería dar la impresión que servidor Linux es inaccesible. Mas bien, el objetivo, era dar importancia a cada uno de los actores que intervienen en la ecuación. Y es que básicamente, en la gran mayoría de las ocasiones, el responsable es el octavo pasajero, se trata de un error de capa 8, es decir, que normalmente somos los usuarios, que descuidamos nuestras obligaciones. Así, que para ayudarte con esto, en este episodio te quiero hablar de dos herramientas mas para proteger tu Linux. Ya sea un servidor que esté expuesto a Internet como tu propio equipo.

Ya te habrás imaginado, que esto tiene mas sentido para equipos expuestos a internet, pero esto no quita, que cualquier equipo sea susceptible de un ataque. Sin embargo, lo está claro que un servidor que tiene servicios expuestos a internet, es mas susceptible, que otro que está desconectado de internet, e incluso completamente desconectado.

Más herramientas para proteger tu Linux

Un poquito de background

Hace ya algún tiempo que tengo instaladas las herramientas que en este episodio del podcast te quiero comentar. Sin embargo, durante estos últimos días, les he estado dando algo mas de cariño. Mas que nada, por tener las cosas frescas, antes de contarlas.

La cuestión, que he estado diferentes pruebas, pero sobre todo lo que he estado haciendo ha sido banearme una y otra vez. Tan es así, que en un momento determinado, estaba tan preocupado, que no sabía si había terminado con mi VPS… Hasta que me di cuenta de que estaba baneado.

Sobre fail2ban

La primera de las herramientas de las que te quiero hablar es fail2ban. Esta es una vieja conocida de atareao.es. En concreto te hablé sobre ella en un artículo titulaod bloquear accesos indeseables en tu servidor. Pero también, te hablé en el episodio 292 del podcast, titulado seguridad básica en tu servidor, o incluso en uno episodio dedicado a securizar y homogeneizar la Raspberry.

Sin embargo, en casi todos estos artículos y episodios del podcast, lo encontrarás instalado directamente sobre la máquina. Sin embargo, con la migración de muchos de mis servicios a Docker, este también se vino con ellos, aunque no como yo esperaba.

Actualmente estoy utilizando Traefik como mi proxy inverso de referencia para poner todos mis servicios en funcionamiento de forma eficiente. Así en el episodio 439, te hablé sobre Dashboards, Flatnotes y Traefik con fail2ban.

En este episodio te comentaba que se había implementado un plugin que hacía las cosas de fail2ban, pero utilizando directamente Traefik. Es decir, ante algunas de las acciones que se pudieran hacer directamente este plugin, se encargaba de denegar el acceso.

fail2ban como complemento

Utilizar fail2ban como complemento de Traefik, me resulta sumamente interesante, en tanto en cuanto no es necesario dar mas acceso al socket de Docker, del necesario, pero sobre todo, porque fail2ban no tiene que tocar los iptables, simplemente se tienes que hacer cargo de denegar el servicio. Esto, ya lo comenté en el episodio anterior del podcast.

Sin embargo, este complemento de Traefik, es un quiero y no puedo, es un principio de lo que puede llegar a ser, pero que todavía no es. Ahora mismo, solo impide o permite el acceso a determinadas direcciones, realmente muy flojo y decepcionante.

Sinceramente, espero, que en futuras versiones, esto se mejore, para no tener que gestionar las iptables únicamente para esto.

Igual que te digo esto, también te tengo que decir que además de esto, puedes encontrar todo tipo de complementos para Traefik, para mejorar sinceramente la seguridad y mucho mas. Desde complementos que impiden el acceso desde la red Tor, como otros complementos que bloquean acceso en función del origen.

Tengo que confesarte que existen una barbaridad de complementos, y todavía no he tenido la oportunidad de revisarlos todos, pero es una auténtica pasada.

fail2ban en Docker

Después de haber tenido fail2ban directamente en la máquina, finalmente decidí implementarlo en Docker, e integrarlo con Traefik, para de esta manera evitar accesos indeseados.

Dicho esto, tengo que decirte que hasta el momento, lo único que he conseguido ha sido banearme a mi en varias ocasiones, y que como te decía anteriormente asustarme, porque no conseguía acceder de ninguna de las maneras.

Lo que si me sorprende es la cantidad de intentos de acceso que hay vía ssh, por supuesto utilizando usuario y contraseña. Esta es la principal razón para recomendarte que deshabilites este acceso y siempre accedas vía clave público-privada.

El docker-compose.yml, que estoy utilizando es el esiguiente,

version: "3.7"

services:
  fail2ban:
    image: crazymax/fail2ban:latest
    container_name: fail2ban
    init: true
    network_mode: "host"
    cap_add:
    - NET_ADMIN
    - NET_RAW
    environment:
      - TZ=Europe/Madrid
    volumes:
    - ./data:/data
    - /var/log:/var/log/:ro
    - traefik_logs:/traefik_logs/:ro

volumes:
  traefik_logs:
    external: true

Aquí lo interesante es que tienes que montar el volumen traefik_logs, que es donde van los logs de Traefik como un volumen externo. En cuanto al jail para Traefik, es el siguiente,

[traefik-auth]
enabled = true
chain = DOCKER-USER
ignoreip = XXX.XXX.XXX.XXX
port = http,https
filter = traefik-auth
mode = aggressive
logpath = /traefik_logs/access.log
bantime = 24h
findtime = 1h
maxretry = 2

[traefik-auth-ddos]

filter = traefik-auth[mode=ddos]

[traefik-botsearch]

enabled = true chain = DOCKER-USER port = http,https filter = traefik-botsearch logpath = /traefik_logs/access.log bantime = 24h findtime = 1h maxretry = 2

Fíjate que aquí he incluído mi IP, para evitar que me vuelva a banear.

Por otro lado, en el caso del docker-compose.yml de Traefik el volumen, lo tengo definido de la siguiente forma,

services:
  traefik:
    ..
    volumes:
    - logs:/var/log/traefik

volumes:
  logs: {}

Con esto tengo resuelto tanto los intentos de acceso vía ssh, como los intentos de acceso a los distintos sitios. A partir de aquí, simplemente se trata de ir añadiendo reglas específicas para cada uno de los servicios que tenemos, ya sea WordPress, Filebrowser, etc.

Admeás utilizando just, tengo un par de comandos que me dan información sobre lo que sucede, así como quitarme el baneo,

unban ip:
    docker exec fail2ban fail2ban-client set traefik-auth unbanip {{ip}}
stats:
    docker exec fail2ban fail2ban-client status sshd
    docker exec fail2ban fail2ban-client status traefik-auth
    docker exec fail2ban fail2ban-client status traefik-botsearch
    docker exec fail2ban fail2ban-client status wordpress

Crowdsec

Sobre Crowdsec tienes un interesante conjunto de artículos de Héctor en bujarra.como, y en particular el primero de ellos dedica a proteger nuestras máquinas con Crowdsec.

Si no conoces Crowdsec, indicarte que se trata de una herramienta que detecta y bloquea accesos a máquinas, con independencias de que sea una red interna, que una máquina en internet, un Linux, un Windows, un contenedor… Lo que sea.

Así, esta herramienta está vigilante, de forma que ya sea que detecte un ataque de denegación de servicio, que detecte un escaneo de puertos, o de vulnerabilidades, o accesos incorrectos, o lo que sea, bloqueará el acceso.

Crowdsec y Traefik

Como te decía con fail2ban, lo que no me gusta es que altera los iptables. Sin embargo, Crowdsec, precisamente la ventaja que tiene es que se integra con Traefik, y no necesita ni acceso al socket de Docker, ni acceso al host, ni nada, de nada… simplemente, necesita acceso a los logs de Traefik. Una maravilla.

Así, mi configuración del docker-compose.yml, es la siguiente,

version: '3.8'
services:
  crowdsec:
    image: crowdsecurity/crowdsec:latest
    container_name: crowdsec
    init: true
    environment:
      GID: "${GID-1000}"
      COLLECTIONS: "crowdsecurity/linux crowdsecurity/traefik"
    volumes:
      - ./config/acquis.yml:/etc/crowdsec/acquis.yaml
      - crowdsec-db:/var/lib/crowdsec/data/
      - crowdsec-config:/etc/crowdsec/
      - traefik_logs:/var/log/traefik/:ro
    networks:
      - proxy
    restart: unless-stopped

  bouncer-traefik:
    image: docker.io/fbonalair/traefik-crowdsec-bouncer:latest
    container_name: bouncer-traefik
    init: true
    environment:
      CROWDSEC_BOUNCER_API_KEY: XXXXXXXXXXXXXXXXXXXXXX
      CROWDSEC_AGENT_HOST: crowdsec:8080
    networks:
      - proxy # same network as traefik + crowdsec
    depends_on:
      - crowdsec
    restart: unless-stopped

volumes:
  crowdsec-db:
  crowdsec-config:
  traefik_logs: # this will be the name of the volume from trarfic logs
    external: true # remove if traefik is running on same stack

networks:
  proxy:
    external: true

Configuración con Traefik

La configuración con traefik, es algo mas compleja, ya que tienes que declarar en varios sitios. Por un lado, en la configuración estática, que en mi caso es la siguiente, traefik.yml,

api:
  dashboard: true

entryPoints:
  http:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: https
          scheme: https
          permanent: true
      middlewares:
        - crowdsec-bouncer@file
  https:
    address: ":443"
    http:
      middlewares:
      - crowdsec-bouncer@file


serversTransport:
  maxIdleConnsPerHost: 1

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    network: proxy
  file:
    directory: /conf
    watch: true

log:
  level: INFO
  filePath: "/var/log/traefik/traefik.log"
accessLog:
  filePath: "/var/log/traefik/access.log"
  bufferingSize: 100
  fields:
    defaultMode: keep
    names:
      ClientUsername: keep
    headers:
      defaultMode: keep
      names:
        Content-Type: keep
        X-Forwarded-For: keep
  filters:
    statusCodes:
      - "300-302"
      - "400-409"
    retryAttempts: true
    minDuration: "10ms"


certificatesResolvers:
  myresolver:
    acme:
      email: lorenzo.carbonell.cerezo@gmail.com
      storage: acme.json
      httpChallenge:
        entryPoint: http

experimental:
  plugins:
    fail2ban:
      moduleName: "github.com/tomMoulard/fail2ban"
      version: "v0.6.6"

Mientras que la configuración dinámica es como sigue,

http:
  middlewares:
    crowdsec-bouncer:
      forwardauth:
        address: http://bouncer-traefik:8080/api/v1/forwardAuth
        trustForwardHeader: true
    http2https:
      redirectScheme:
        scheme: https
        permanent: true
    test-errors:
      errors:
        status:
          - "400-499"
          - "500-599"
        service: serviceError
        query: "/{status}.html"
    my-torblock:
      plugin:
        torblock:
          enabled: true
    traefik-real-ip:
      plugin:
        traefik-real-ip:
          excludednets:
            - "1.1.1.1/24"
    my-fail2ban:
      plugin:
        fail2ban:
          loglevel: "INFO"
          blacklist:
            ip:
              - 192.168.0.0/24
          rules:
            urlregexps:
            - regexp: "/whoami"
              mode: allow
            - regexp: "/do-not-access"
              mode: block
            - regexp: "/no"
              mode: block
            - regexp: "/yes"
              mode: allow
            bantime: "3h"
            findtime: "10m"
            maxretry: 4
            enabled: true
          whitelist:
            ip:
              - ::1
              - 127.0.0.1

Algunas herramientas complementarias

En mi caso, utilizo just, para la ejecución y mantenimiento de scripts. Para el caso de Crowdsec

decisions:
    docker exec crowdsec cscli decisions list
metrics:
    docker exec crowdsec cscli metrics
alerts:
    docker exec crowdsec cscli alerts list

Más información,

bujarra.com

Espero que te haya gustado este nuevo episodio del podcast. Si puedes, te agradecería una valoración en iVoox y/o en Apple Podcast.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *