허니팟 운영 삽질기 — UFW·Docker·iptables에서 만난 함정들
10일간 공격을 못 받은 이유, systemd에서 iptables가 안 되는 이유, 5만 건 로그를 소급 처리한 방법.
목차
허니팟을 올려두고 10일 동안 아무 데이터도 안 쌓였다. 방화벽 문제인가 싶어서 포트를 열어봐도, Cowrie를 재시작해봐도 아무 반응이 없었다. 원인을 찾는 데 꽤 걸렸다.
함정 1 — UFW가 Docker 트래픽을 막고 있었다
Ubuntu에서 UFW를 기본 설정으로 쓰면 /etc/default/ufw에 이런 줄이 있다:
DEFAULT_FORWARD_POLICY="DROP"
Docker 컨테이너로 들어오는 패킷은 INPUT 체인이 아니라 FORWARD 체인을 탄다. UFW의 기본 포워딩 정책이 DROP이면 외부에서 컨테이너로 오는 패킷이 전부 조용히 버려진다. ufw status에는 아무 이상이 없어 보이고, 포트도 열려 있는 것처럼 보인다.
인터넷 → 호스트 NIC
→ PREROUTING
→ FORWARD 체인 ← 여기서 DROP
→ 컨테이너 (도달 못 함)
수정은 간단하다:
# /etc/default/ufw
DEFAULT_FORWARD_POLICY="ACCEPT"
sudo ufw reload
이걸 고치고 나서야 허니팟이 공격을 받기 시작했다. 10일치 로그가 파일에만 쌓여 있고 DB에는 아무것도 없었다.
함정 2 — systemd 서비스에서 iptables가 Permission denied
공격 탐지 시 자동으로 iptables로 차단하는 Python 데몬을 systemd 서비스로 등록했다. 로컬에서 직접 실행하면 문제없이 동작하는데, 서비스로 띄우면:
iptables v1.8.9: can't initialize iptables table 'filter': Permission denied
iptables는 네트워크 설정 변경 권한이 필요하다. 일반 프로세스에는 없고, root로 실행하거나 CAP_NET_ADMIN capability를 부여해야 한다.
systemd 서비스 파일에 한 줄 추가하면 된다:
[Service]
User=honeypot
AmbientCapabilities=CAP_NET_ADMIN
CapabilityBoundingSet=CAP_NET_ADMIN
AmbientCapabilities는 프로세스가 실행되면서 상속받을 capability를 지정한다. CapabilityBoundingSet으로 범위를 CAP_NET_ADMIN으로만 제한하면, root 권한 없이 iptables만 쓸 수 있는 최소 권한 서비스가 된다.
sudo systemctl daemon-reload
sudo systemctl restart honeypot-aggregator
자동 차단 파이프라인 검증
설정이 다 됐으면 실제로 동작하는지 확인해야 한다. 테스트 이벤트를 Cowrie 로그에 직접 주입하는 방식으로 검증했다.
echo '{
"eventid": "cowrie.command.input",
"src_ip": "1.2.3.4",
"input": "xmrig --url stratum+tcp://pool.example.com:3333"
}' >> /opt/honeypot/cowrie/var/log/cowrie/cowrie.json
6초 안에 순서대로 일어났다:
aggregator.py로그 테일에서 감지크립토 마이너시그니처 (xmrig|stratum\+tcp) 매칭iptables -I INPUT 1 -s 1.2.3.4 -j DROP실행iptables-save > /etc/iptables/rules.v4(재부팅 후에도 유지)- Discord 웹훅 알림 전송
# 차단 확인
sudo iptables -L INPUT -n --line-numbers | grep 1.2.3.4
# 1 DROP all -- 1.2.3.4 0.0.0.0/0
5만 건 로그 백필
UFW 버그를 고치고 보니 10일치 로그가 Cowrie JSON 파일에 그대로 쌓여 있었다. DB에는 아무것도 없는 상태.
Python으로 파일을 읽어서 밀어 넣었다. aggregator.py 자체가 표준 라이브러리만 써서 그냥 가져다 쓸 수 있었다.
import json, sqlite3
DB = "/opt/honeypot/dashboard/honeypot.db"
LOG = "/opt/honeypot/cowrie/var/log/cowrie/cowrie.json.2026*"
import glob
conn = sqlite3.connect(DB)
cur = conn.cursor()
for log_file in sorted(glob.glob(LOG)):
with open(log_file) as f:
for line in f:
try:
ev = json.loads(line)
cur.execute("""
INSERT OR IGNORE INTO events
(timestamp, src_ip, event_type, raw)
VALUES (?, ?, ?, ?)
""", (
ev.get("timestamp"),
ev.get("src_ip"),
ev.get("eventid"),
line.strip()
))
except json.JSONDecodeError:
pass
conn.commit()
conn.close()
총 50,768건이 DB에 들어왔다. 백필 후 대시보드 누적 수치가 59,637건으로 올라갔다.
정리
| 문제 | 원인 | 해결 |
|---|---|---|
| 컨테이너가 트래픽 못 받음 | UFW DEFAULT_FORWARD_POLICY=DROP | ACCEPT로 변경 후 ufw reload |
| iptables Permission denied | systemd 서비스에 capability 없음 | AmbientCapabilities=CAP_NET_ADMIN 추가 |
| 10일치 데이터 누락 | 위 두 문제의 여파 | Python 백필 스크립트 |
세 가지 모두 문서에 명확하게 나와 있는 내용이다. 그럼에도 실제로 만나면 원인 찾는 데 시간이 걸린다. UFW + Docker 조합은 특히 조용히 실패해서 더 그렇다.