CrowdSec 야호~!

peterTheAnteater·2026년 6월 5일

기타

목록 보기
2/2
post-thumbnail

AI때문에 점점 쉬워지는 해킹. 어떻게 방지해볼수있는 방법이 없을까?

글을 쓰게 된 동기

독자 여러분 안녕하세요! 독자 야호
9개월만에 글을 쓰게 됐습니다.

요즘 일이 너무 많아서 글을 쓰기 점점 힘들어지는거 같습니다. 사실 일이 많아지는건 AI때문인거 같습니다.

AI때문에 회사에서 일을 더 많이 시키기 보다는 AI때문에 요즘 전세계 보안 업계가 난리가 나서 그런거같습니다.

요즘 Claude나 Codex성능이 너무 좋아져서 그 친구들을 활용해 많은 분야에서 보안 취약점을 찾는거 같습니다. 덕분에 CVE가 마를 날이 없습니다...

그리고 그 보안 취약점들을 고치려면 시간을 많이 써야하는데 고치는 와중에 새로운 취약점이 찾아지는....

진짜 작작 찾으라고!!!!

하여튼 그런 일이 좀 많이 있는데 그 와중에 제 홈서버는 어떻게 취약점 관리를 해야할까 생각하다가 모두가 사용해볼수 있는 툴을 소개해드릴까 합니다.

CrowdSec?

CrowdSec은 서버, 웹사이트 및 IT 인프라를 외부 공격으로부터 보호하기 위해 설계된 오픈소스 기반의 협업형 침입 탐지 및 방지 시스템(IDS/IPS)입니다.

간단하게 생각하면 해킹 방지 시스템입니다.

그리고 AppSec라는 친구와 같이 사용하면 WAF (방화벽) 처럼 사용할수도 있죠!

크게 몇가지 기능으로 나뉘어 있습니다

CrowdSec API

API는 전체적으로 CrowdSec을 관리하고 외부 데이터를 갖고오는 역할을 합니다. 여기서 외부 데이터란 각종 CVE와 해킹 패턴들을 저장하고 있는 중앙 서버에 있는 데이터를 말합니다.

Parser

Parser는 대부분 로그를 파싱해서 들어온 요청이 공격 요청인지 아닌지 구분을 할때 사용합니다. Parser로 데이터를 파싱하고 CrowdSec API서버에서 해킹 공격이 아니다 맞다를 정한다고 생각하면 편하겠죠?

Bouncer

Bouncer는 공격을 막는 역할을 합니다. iptables나 리버스프록시든 앞단에서 공격자 IP요청을 막거나 하는 기능을 제공해줍니다. 즉 Parser가 데이터를 수집사고, API서버가 판단을 내리고, Bouncer가 막는 역할인거죠.

AppSec

AppSec은 CrowdSec내부에서 익스텐션으로 사용할수 있는 기능입니다. CrowdSec은 기본적으로 IP필터링을 통해서 봇이나 해커 IP를 중앙서버에서 데이터를 받아서 막아주는 역할을 하면 AppSec은 패킷을 분석해서 요청이 이상하면 막아주는 역할을 합니다.

이해가 잘 안되시죠?

CrowdSec vs AppSec

제가 예시를 한번 보여드리겠습니다.

만약에 해커가 서버에 GET https://my-server.com/login 이라고 요청을 보낸다고 합시다.

이 요청 자체는 문제가 없어보이죠? 하지만 이 해커의 IP가 만약에 CrowdSec중앙서버에 저장이 되어있는 IP면 CrowdSec이 Bouncer한테 막으라고 요청을 보냅니다. 그러면 해커는 403 페이지를 보게될겁니다.

근데 만약에 해커가 VPN같은거를 사용해서 IP Masking을 하면 어떻게 될가요?

누군지 맞출수 있을까요?

CrowdSec중앙 서버에는 등록이 안되어있는 IP라면 그냥 아무문제 없이 GET https://my-server.com/login 요청이 성공을 할겁니다.

그리고 만약에 GET https://my-server.com/.env 같은 이상한 요청도 흔하게 보이는 공격 문제 없이 성공할겁니다. 물론 대부분의 상황에서는 404가 나오겠죠. (/.env가 404 안나오면 님 서버 꼭 확인하삼)

근데 AppSec을 사용하면 다릅니다.

GET https://my-server.com/.env 요청을 받으면 AppSec이 분석을 해서 기존에 존재하는 공격패턴인지 분석을 합니다. (CVE기반)

물론 저 공격패턴 데이터도 중앙서버에서 받아옵니다.

그리고 /.env는 흔한 공격 패턴이기 때문에 당연히 막힙니다. (403)

여기서 끝나지 않습니다. AppSec을 ssh로그와 연동 해두면 ssh Brute Force공격등도 막아줍니다.

간단한 예시

아래 간단한 설정 예시를 만들었습니다.

services:
  secured-traefik:
    image: traefik:v3.7.1
    container_name: secured-traefik
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--log.level=DEBUG"
      - "--accesslog=true"
      - "--accesslog.bufferingsize=100"
      - "--accesslog.format=json"
      - "--accesslog.filepath=/traefik/logs/access.log"
      - "--accesslog.fields.defaultmode=keep"
      - "--accesslog.fields.headers.defaultmode=keep"
      - "--accesslog.fields.headers.names.X-Forwarded-For=keep"
      - "--api.dashboard=true"
      - "--experimental.plugins.crowdsec-bouncer-traefik-plugin.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
      - "--experimental.plugins.crowdsec-bouncer-traefik-plugin.version=v1.6.0"
    ports:
      - "80:80"
      - "8090:8080"
      - "8091:8091"
    networks:
      - traefik-network
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - traefik-logs:/traefik/logs
    restart: unless-stopped

  secured-crowdsec:
    image: crowdsecurity/crowdsec:v1.7.8-debian
    container_name: secured-crowdsec
    environment:
      COLLECTIONS: |
        crowdsecurity/traefik
        crowdsecurity/http-cve
        crowdsecurity/sshd
        crowdsecurity/appsec-virtual-patching
        crowdsecurity/appsec-generic-rules
        crowdsecurity/linux
        crowdsecurity/iptables
      BOUNCER_KEY_TRAEFIK: "traefik-secret-key"  # 꼭 바꾸삼
      BOUNCER_KEY_FIREWALL: "firewall-secret-key"  # 꼭 바꾸삼
      CROWDSEC_LAPI_URL: http://127.0.0.1:8080
      API_SERVER_URL: http://127.0.0.1:8080
    networks:
      - traefik-network
    volumes:
      - crowdsec-db:/var/lib/crowdsec/data
      - crowdsec-config:/etc/crowdsec
      - ./config/config.yaml:/etc/crowdsec/config.yaml.local:ro
      - ./config/appsec.yaml:/etc/crowdsec/acquis.d/appsec.yaml:ro
      - ./config/sshd.yaml:/etc/crowdsec/acquis.d/sshd.yaml:ro
      - ./config/acquis.yaml:/etc/crowdsec/acquis.d/acquis.yaml:ro
      - traefik-logs:/var/log/traefik:ro
      - /var/log/journal:/var/log/journal:ro
      - /run/log/journal:/run/log/journal:ro
      - /etc/machine-id:/etc/machine-id:ro
    ports:
      - "8080:8080"
      - "6060:6060"
      - "7422:7422"
    restart: unless-stopped
  
  secured-crowdsec-firewall-bouncer:
    image: ghcr.io/shgew/cs-firewall-bouncer-docker:v0.0.34
    container_name: secured-crowdsec-firewall-bouncer
    network_mode: host
    cap_add:
      - NET_ADMIN
      - NET_RAW
    security_opt:
      - no-new-privileges:true
    environment:
      API_URL: "http://127.0.0.1:8080"
      API_KEY: "firewall-secret-key" # 꼭 바꾸삼
    volumes:
      - ./config/crowdsec-firewall-bouncer.yaml:/config/crowdsec-firewall-bouncer.yaml:ro
      - /etc/localtime:/etc/localtime:ro
    restart: unless-stopped

  secured-whoami:
    image: traefik/whoami
    container_name: secured-whoami
    restart: unless-stopped
    networks:
      - traefik-network
    labels:
      traefik.enable: "true"
      traefik.docker.network: "traefik-network"
      traefik.http.services.whoami.loadbalancer.server.port: "80"
      traefik.http.routers.whoami.rule: "PathPrefix(`/`)"
      traefik.http.routers.whoami.entrypoints: "web"
      traefik.http.routers.whoami.middlewares: "crowdsec@docker"
      traefik.http.middlewares.crowdsec.plugin.crowdsec-bouncer-traefik-plugin.enabled: true
      traefik.http.middlewares.crowdsec.plugin.crowdsec-bouncer-traefik-plugin.crowdseclapikey: "traefik-secret-key" # 꼭 바꾸삼
      traefik.http.middlewares.crowdsec.plugin.crowdsec-bouncer-traefik-plugin.crowdseclapischeme: "http"
      traefik.http.middlewares.crowdsec.plugin.crowdsec-bouncer-traefik-plugin.crowdseclapihost: "secured-crowdsec:8080"
      traefik.http.middlewares.crowdsec.plugin.crowdsec-bouncer-traefik-plugin.crowdsecappsecenabled: "true"
      traefik.http.middlewares.crowdsec.plugin.crowdsec-bouncer-traefik-plugin.crowdsecappsechost: "secured-crowdsec:7422"

volumes:
  traefik-logs:
  crowdsec-db:
  crowdsec-config:

networks:
  traefik-network:
    external: true
    name: traefik-network

조합은 보시다 시피 Traefik + CrowdSec + whoami (혹은 간단한 웹서버) 입니다.

CrowdSec컨테이너에 COLLECTIONS라고 적혀있는 부분이 있는 그 부분이 중앙서버에서 어떤 데이터를 받아올지와 어떤 툴을 사용하는지 정하는 부분입니다. 저같은 경우에는

  1. crowdsecurity/traefik: 트레픽 툴 사용
  2. crowdsecurity/http-cve: http cve (취약점) 데이터
  3. crowdsecurity/sshd: ssh 공격 관련
  4. crowdsecurity/appsec-virtual-patching: appsec기반 실시간 업데이트
  5. crowdsecurity/appsec-generic-rules: 기본 appsec 공격 데이터
  6. crowdsecurity/linux: 리눅스 관련
  7. crowdsecurity/iptables: iptables기반 방화벽 설정

대충 이렇게 생각하면 편합니다. CrowdSec 홈페이지에 들어가시면 사용할수있는 컬랙션이 뭐가 있는지 자세하게 알려줍니다.

그리고 이제 볼륨에 적혀있는 config 파일들입니다.
sshd.yaml

#sshd.yaml - ssh관련 설정
source: journalctl

journalctl_filter:
  - "_SYSTEMD_UNIT=ssh.service" # 이 부분은 어떤 Linux를 사용하는지에 따라서 좀 다릅니다.

labels:
  type: syslog

crowdsec-firewall-bouncer.yaml

# crowdsec-firewall-bouncer.yaml
mode: nftables

api_url: ${API_URL}
api_key: ${API_KEY}

disable_ipv6: false
blacklists_ipv4: crowdsec-blacklists
blacklists_ipv6: crowdsec6-blacklists
update_frequency: 10s

deny_action: drop

log_mode: stdout
log_level: info

appsec.yaml

# appsec.yaml - appsec관련 설정
appsec_config: crowdsecurity/appsec-default
labels:
  type: appsec
listen_addr: 0.0.0.0:7422
source: appsec
name: myAppSecComponent

acquis.yaml

# acquis.yaml - traefik관련 기본 설정
filenames:
  - /var/log/traefik/access.log
labels:
  type: traefik

좀 더 자세한건 AI한테 물어보시면서 해보시면 될겁니다.

결론

저는 CrowdSec을 사용하면서 나름(?) 공격을 좀 막을수있었습니다.

공격 들어오는거보소

보시다 시피 1주일 동안 총 1203건의 공격을 감지를 했습니다.

물론 클라우드를 사용하시면 자체 L4/L7 WAF와 보안 제품을 사용할수 있습니다. 하지만 이렇게 직접 해보는거도 나름 할만한거같습니다

오랜만인데 읽어주셔서 감사합니다.

모두 해킹 공격 조심하세요!

profile
소프트웨어 개발과 밀당하는 개발자

1개의 댓글

comment-user-thumbnail
2026년 6월 5일

CrowdSec 좋네요

답글 달기