셀프호스팅 환경에서 AI 에이전트를 돌리면서 네트워크 보안을 직접 설계해본 경험이 없다면, 이 글이 실질적인 출발점이 될 것이다. Claude Code가 알아서 npm install이나 curl을 날리는 상황을 막지 못하면, 어느 순간 검증되지 않은 외부 패키지가 워크스페이스에 조용히 들어와 있다.
왜 격리가 필요한가 — 에이전트는 허락 없이 움직인다
에이전트가 코드를 작성하는 과정에서 pip install, npm install, curl 같은 명령을 스스로 실행한다. 누군가 허락한 게 아니다. 할 수 있으니까 하는 것이다.
클라우드 환경이라면 VPC나 보안 그룹이 일정 부분 막아주지만, Ollama와 Draw Things를 셀프호스팅으로 돌리는 순간 그 방어막은 사라진다. 에이전트가 접근할 수 있는 외부 도메인 수를 실측해봤다.
| 상태 | 세션당 외부 도메인 접근 수 |
|---|---|
| 격리 전 | 평균 12개 |
| 격리 후 (Anthropic API만 허용) | 1개 |
이 수치가 격리의 이유를 모두 설명한다.
Docker 브리지 네트워크로 울타리 치기
핵심은 --internal 플래그 하나다. 이 플래그가 붙은 Docker 네트워크는 컨테이너끼리만 통신하고, 외부 인터넷으로의 라우팅 자체가 불가능해진다.
# 에이전트 전용 격리 네트워크 생성
docker network create \
--driver bridge \
--internal \
--subnet 172.30.0.0/24 \
claude-agent-net
# Ollama 컨테이너를 같은 네트워크에 연결
docker network connect claude-agent-net ollama
# Claude Code 에이전트 컨테이너 실행
docker run --rm \
--network claude-agent-net \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
-v $(pwd)/workspace:/workspace \
claude-agent:latest
실행 후 격리가 제대로 됐는지 확인하는 방법은 간단하다. 에이전트 컨테이너 안에서 외부로 ping을 날려보면 된다.
# 컨테이너 안에서 실행 — 응답 없으면 격리 성공
docker exec -it <container_id> ping -c 3 8.8.8.8
# PING 8.8.8.8: Network unreachable
iptables 화이트리스트 — Anthropic API만 뚫어주기
--internal 만으로는 Anthropic API 호출도 막힌다. 에이전트가 동작하려면 api.anthropic.com으로의 443 포트는 열어줘야 한다. iptables 규칙으로 정밀 제어한다.
# claude-agent-net 브리지 인터페이스 이름 확인
BRIDGE=$(docker network inspect claude-agent-net \
--format '{{.Options}}' | grep -o 'br-[a-z0-9]*')
# 기본 정책: 외부 포워딩 전부 차단
iptables -I FORWARD -i $BRIDGE -o eth0 -j DROP
# Anthropic API 대역만 443 허용 (18.238.0.0/15)
iptables -I FORWARD -i $BRIDGE -o eth0 \
-d 18.238.0.0/15 -p tcp --dport 443 -j ACCEPT
# 규칙 확인
iptables -L FORWARD -n --line-numbers
기대 출력:
Chain FORWARD (policy ACCEPT)
num target prot opt source destination
1 ACCEPT tcp -- 0.0.0.0/0 18.238.0.0/15 tcp dpt:443
2 DROP all -- 0.0.0.0/0 0.0.0.0/0
순서가 중요하다. ACCEPT 규칙을 DROP보다 앞 번호에 놓아야 Anthropic API 요청이 통과된다. iptables는 위에서부터 순서대로 매칭한다.
차단 로그로 에이전트 행동 실시간 감시
격리를 걸었다고 끝이 아니다. 에이전트가 실제로 어떤 외부 주소를 호출하려 했는지 확인해야 설계가 올바른지 검증할 수 있다.
# DROP된 패킷 로깅 규칙 추가
iptables -I FORWARD -i $BRIDGE -o eth0 -j LOG \
--log-prefix '[AGENT-BLOCKED] ' --log-level 4
# 실시간 차단 로그 확인
journalctl -k -f | grep 'AGENT-BLOCKED'
실제 로그 예시:
[AGENT-BLOCKED] IN=br-a3f2 OUT=eth0 SRC=172.30.0.3 DST=151.101.1.57
[AGENT-BLOCKED] IN=br-a3f2 OUT=eth0 SRC=172.30.0.3 DST=104.18.32.68
151.101.1.57은 Fastly CDN이고, 104.18.32.68은 Cloudflare다. 에이전트가 PyPI나 npm 레지스트리를 호출하려 한 흔적이다. 이 로그를 보고 나면 "그냥 쓰면 안 되나요"라는 질문이 사라진다.
운영 팁 — 환경별 주의사항
Mac에서 Docker Desktop 사용 시: iptables 명령이 컨테이너 안 리눅스 레이어에서만 동작한다. Mac 호스트 방화벽(pf)과는 별개다. Docker Desktop VM 안에 접속해서 규칙을 적용해야 한다.
재부팅 후 iptables 규칙 유지: 기본적으로 재부팅하면 iptables 규칙이 초기화된다. iptables-persistent 패키지를 설치하거나 Docker Compose의 restart: always 컨테이너에서 규칙을 재적용하는 스크립트를 엔트리포인트에 넣어두는 것이 낫다.
Ollama가 GPU 서버에 따로 있는 경우: --internal 플래그 대신 특정 내부 IP 대역만 허용하는 iptables 규칙으로 전환한다. GPU 서버 IP를 화이트리스트에 추가하면 된다.
마무리
셀프호스팅으로 에이전트를 운영한다는 건 보안 설계도 직접 한다는 의미다. Docker --internal 네트워크와 iptables 화이트리스트 조합은 설정 비용이 낮고 효과는 확실하다. Mac4 실측 기준 외부 트래픽 차단율 100%, 내부 Ollama 통신 지연 증가 없음.
에이전트를 신뢰하되 울타리는 반드시 쳐야 한다. 다음 글에서는 격리된 환경에서 패키지 캐시를 내부 미러로 구성하는 방법을 다룬다.
🐦 X에서 더 빠르게: @baegseungh7061
📚 이 시리즈 더 보기: Code 활용
💌 새 글 알림: X 팔로우 또는 블로그 RSS 구독
'Code 활용' 카테고리의 다른 글
| Claude Code 커스텀 커맨드에 프로젝트 정보를 자동으로 심는 법 (0) | 2026.05.11 |
|---|---|
| 병렬 에이전트 결과를 하나로 합치는 MapReduce 설계 — Claude Code 실전 패턴 (0) | 2026.05.10 |
| 작업 무게에 따라 Haiku·Sonnet·Opus를 골라 쓰는 Claude 모델 티어 라우팅 비용 설계 (0) | 2026.05.07 |
| Claude Code로 에러 고치는 루프 완전 자동화하기 (0) | 2026.04.29 |
| CLAUDE.md로 시작하는 Claude Code 프로젝트 장악 전략 (0) | 2026.04.29 |