악몽 시나리오
원격 Mac Mini에서 방화벽 규칙을 설정 중이다. Tailscale을 통해 SSH로 접속하고, 새 규칙을 활성화하기 위해 pfctl -e를 실행하고… 침묵. 터미널이 멈춘다. 방금 스스로 잠겼다.
방화벽 설정에서 하나의 잘못된 규칙이 모든 원격 접근을 차단할 수 있다. 서버는 여전히 실행 중이지만 접근할 수 없다. 데이터 센터까지 운전해야 할 시간이다.
간단한 패턴으로 이것을 예방할 수 있다: 사전 검증.
사전 검증 패턴
flowchart TD
subgraph SETUP["1. 설정 단계"]
S1["설정 파일 작성"]
S2["권한 설정"]
S3["변경 준비"]
S1 --> S2 --> S3
end
subgraph PREFLIGHT["2. 사전 검증"]
P1["의존성 존재 확인"]
P2["설정 문법 테스트"]
P3["탈출구 작동 확인"]
P4["현재 상태 확인"]
P1 --> P2 --> P3 --> P4
end
subgraph ACTIVATE["3. 활성화"]
A1["명시적 명령으로 활성화"]
A2["돌이킬 수 없는 지점"]
A1 --> A2
end
subgraph POST["4. 사후 검증"]
V1["새 상태 확인"]
V2["영향받는 서비스 테스트"]
V1 --> V2
end
subgraph ROLLBACK["5. 롤백 준비"]
R1["비상 비활성화 문서화"]
R2["롤백 절차 테스트"]
R1 --> R2
end
SETUP --> PREFLIGHT
PREFLIGHT -->|"모든 검증 통과"| ACTIVATE
PREFLIGHT -->|"검증 실패"| SETUP
ACTIVATE --> POST
POST --> ROLLBACK
style PREFLIGHT fill:#f59e0b,color:#000
style ACTIVATE fill:#ef4444,color:#fff
핵심 통찰: 검증과 실행을 분리한다. “안전한지 확인” 단계를 “위험한 것 실행” 단계 전에 명시적이고 포괄적으로 만든다.
1단계: 설정 (비파괴적)
활성화하지 않고 모든 설정 파일을 생성한다:
# pf.conf 규칙 작성
cat > /etc/pf.anchors/moltbot << 'EOF'
# Tailscale 허용 (100.x.x.x 범위)
pass in quick on utun+ from 100.64.0.0/10 to any
pass out quick on utun+ from any to 100.64.0.0/10
# 외부에서 나머지 모두 차단
block in on en0
EOF
# 올바른 권한 설정
chmod 644 /etc/pf.anchors/moltbot
이 시점에서 아무것도 변경되지 않았다. 규칙은 존재하지만 활성화되지 않았다.
2단계: 사전 검증 (읽기 전용)
활성화 전 모든 가정을 검증한다:
#!/bin/bash
# preflight-check.sh - 방화벽 활성화 전 검증
ERRORS=0
# 검증 1: Tailscale 인터페이스 존재
echo -n "Tailscale 인터페이스 확인 중... "
if ifconfig | grep -q "utun"; then
echo "OK (utun+ 발견)"
else
echo "실패 (utun 인터페이스 없음)"
((ERRORS++))
fi
# 검증 2: Tailscale IP 할당됨
echo -n "Tailscale IP 확인 중... "
TAILSCALE_IP=$(ifconfig | grep "inet 100\." | awk '{print $2}')
if [[ -n "$TAILSCALE_IP" ]]; then
echo "OK ($TAILSCALE_IP)"
else
echo "실패 (100.x.x.x IP 없음)"
((ERRORS++))
fi
# 검증 3: 설정 문법 유효
echo -n "pf.conf 문법 확인 중... "
if pfctl -n -f /etc/pf.conf 2>/dev/null; then
echo "OK"
else
echo "실패 (문법 오류)"
((ERRORS++))
fi
# 검증 4: 앵커 파일 존재
echo -n "앵커 파일 확인 중... "
if [[ -f /etc/pf.anchors/moltbot ]]; then
echo "OK"
else
echo "실패 (누락)"
((ERRORS++))
fi
# 검증 5: 현재 SSH 세션이 Tailscale을 통함
echo -n "SSH 연결 확인 중... "
SSH_CLIENT_IP=$(echo $SSH_CLIENT | awk '{print $1}')
if [[ "$SSH_CLIENT_IP" == 100.* ]]; then
echo "OK (Tailscale을 통해 연결됨: $SSH_CLIENT_IP)"
else
echo "경고 (Tailscale이 아님: $SSH_CLIENT_IP)"
echo " 방화벽 활성화 시 이 세션이 끊길 수 있음!"
((ERRORS++))
fi
# 요약
echo ""
if [[ $ERRORS -eq 0 ]]; then
echo "모든 검증 통과. 진행해도 안전함."
exit 0
else
echo "실패: $ERRORS개 검증 실패. 방화벽 활성화 금지."
exit 1
fi
검증 실행:
$ ./preflight-check.sh
Tailscale 인터페이스 확인 중... OK (utun+ 발견)
Tailscale IP 확인 중... OK (100.78.42.15)
pf.conf 문법 확인 중... OK
앵커 파일 확인 중... OK
SSH 연결 확인 중... OK (Tailscale을 통해 연결됨: 100.64.0.2)
모든 검증 통과. 진행해도 안전함.
모든 검증이 통과해야만 진행한다.
3단계: 활성화 (돌이킬 수 없는 지점)
이제 확신을 가지고 방화벽을 활성화한다:
# 위험한 명령
sudo pfctl -e -f /etc/pf.conf
# 실행 중인지 확인
sudo pfctl -s info | grep "Status"
설정과 분리해서 유지한다. 설정과 같은 스크립트에 활성화를 넣지 않는다.
4단계: 사후 검증
활성화 직후 새 상태를 검증한다:
# 방화벽 활성화됨 확인
sudo pfctl -s info | grep "Status: Enabled"
# Tailscale 연결 테스트 (다른 기기에서)
ping 100.78.42.15
# 규칙 로드됨 확인
sudo pfctl -s rules | grep "pass in quick on utun+"
5단계: 롤백 준비
활성화 전에 비활성화 방법을 문서화한다:
# 비상 비활성화 명령 (저장해두라!)
sudo pfctl -d
# 또는 영구 변경을 위해 launchctl 사용
sudo launchctl unload /System/Library/LaunchDaemons/com.apple.pfctl.plist
롤백 절차를 필요하기 전에 테스트한다. 위기 상황에서는 알아낼 시간이 없다.
완전한 워크플로우
# 1. 설정 (안전)
sudo ./setup-firewall-config.sh
# 2. 사전 검증 (안전)
./preflight-check.sh || exit 1
# 3. 활성화 (위험)
echo "5초 후 방화벽 활성화. 중단하려면 Ctrl+C."
sleep 5
sudo pfctl -e -f /etc/pf.conf
# 4. 검증 (안전)
./post-verify.sh
# 5. 롤백 문서화
echo "비활성화하려면: sudo pfctl -d"
이 패턴을 사용할 때
다음과 같은 작업:
- 원격: 문제 발생 시 물리적 접근 불가
- 되돌릴 수 없음: 또는 접근 없이는 되돌리기 어려움
- 네트워크 영향: 방화벽, 라우팅 테이블, 인터페이스 설정
- 인증 영향: SSH 키, PAM 설정, 사용자 권한
예시:
- 방화벽 규칙 변경
- SSH 설정 변경
- 네트워크 인터페이스 수정
- 헤드리스 머신의 DNS 서버 변경
- 자동화된 배포 스크립트
핵심 정리
- 설정과 활성화를 절대 결합하지 않는다 - 파일 작성과 활성화를 별도 단계로
- 탈출구를 먼저 검증한다 - 연결 방법이 변경 후에도 유지되는지 확인
- 적용 전 설정 문법 테스트 - 대부분의 도구에 dry-run 모드가 있다
- 필요 전에 롤백을 문서화한다 - 위기 상황에서는 조사할 시간이 없다
- 검증을 자동화한다 - 스크립트가 피곤한 인간이 놓치는 것을 잡아낸다
사전 검증에 쓰는 몇 분이 복구에 쓰는 몇 시간을 절약할 수 있다. 더 중요하게, 금요일 밤 11시에 원격 서버에서 잠겼다는 것을 깨닫는 스트레스를 절약한다.
이 패턴은 Tailscale을 통해 SSH로 원격 Mac Mini에서 pf 방화벽 규칙을 설정하면서 나타났다. 하나의 잘못된 규칙이 물리적 접근을 요구했을 것이다. 사전 검증이 그것을 방지했다.
