infra
Platform

모듈 맵

[Network] 방화벽 정책 설계와 접근 제어 리스트(ACL) 구성 실무

0 / 35 완료

펼치기
0 / 35 완료0%

네트워크 트러블슈팅 · 21 / 35

[Network] 방화벽 정책 설계와 접근 제어 리스트(ACL) 구성 실무

Stateful Inspection과 ACL 규칙을 활용해 서버를 안전하게 보호하는 방화벽 정책을 설계하고 적용한다

🚨INCIDENT ALERT
HIGH

보안 점검에서 "일단 포트를 다 열어두자"는 임시 조치가 그대로 운영에 남아 있었습니다. 장애 때는 빠른 해결처럼 보였지만, 나중에는 접근 경로를 설명할 수 없는 위험이 됩니다.

방화벽 정책은 명령어보다 기준이 먼저입니다. 무엇을 누구에게 왜 열었는지 ACL로 표현할 수 있어야 합니다.

방화벽 정책 수립과 ACL

네트워크 보안의 첫 번째 방어선인 방화벽은 단순한 포트 차단을 넘어, 세션 상태 추적과 세밀한 접근 제어 목록(ACL)을 통해 서버를 보호한다. 이 챕터에서는 Stateful Inspection 원리부터 firewalld를 이용한 실전 정책 수립까지 단계적으로 학습한다.

💼
실무 맥락
현업 패턴

신규 서비스 배포 전 보안팀에서 "방화벽 정책 신청서"를 요구하는 경우가 많다. 개발자는 어떤 포트를, 어떤 출발지 IP 범위에서, 어떤 프로토콜로 허용해야 하는지 명확히 알아야 한다. 잘못된 정책은 서비스 장애 또는 보안 사고로 이어진다. 클라우드 환경에서는 Security Group이 동일한 역할을 하므로, 방화벽 개념을 이해하면 AWS/GCP/Azure 보안 설정도 자연스럽게 이해된다.

방화벽의 두 가지 방향: Inbound와 Outbound

모든 방화벽 규칙은 트래픽의 방향을 기준으로 분류된다.

이번 챕터에서 배울 것
  • 1Inbound/Outbound 트래픽 방향과 기본 차단 정책을 설명할 수 있다
  • 2Stateful Inspection과 conntrack으로 세션 상태를 추적할 수 있다
  • 3firewalld Zone으로 신뢰 수준을 분리할 수 있다
  • 4Rich Rule로 출발지 IP·포트·프로토콜 ACL을 작성할 수 있다
  • 5최소 권한 원칙(Default Deny)에 따라 방화벽 정책을 설계할 수 있다
  • 6방화벽 규칙 변경 시 기존 세션 끊김 부작용을 관리할 수 있다
실습 환경 준비
firewalld 설치 및 활성화
sudo dnf install -y firewalld && sudo systemctl enable --now firewalld
현재 Zone 및 규칙 확인
sudo firewall-cmd --get-active-zones && sudo firewall-cmd --list-all
conntrack 패키지 설치 확인
sudo dnf install -y conntrack-tools
실습 전 설정 백업 권장

sudo firewall-cmd --runtime-to-permanent 으로 변경 전 현재 상태를 저장해 두면 롤백이 용이합니다

💡개념

Inbound와 Outbound 방향 이해

보안 감사 결과 서버 방화벽이 "모두 허용" 상태였습니다. 포트를 하나씩 막으며 최소 허용 정책으로 바꾸려는데 서비스가 하나씩 죽기 시작합니다. 어떤 방향의 어떤 포트가 왜 필요한지 정리가 안 된 채로 규칙을 수정하면 이런 혼란이 반복됩니다. 인바운드와 아웃바운드를 구분하고 방향별 필요 포트를 이해하는 것이 방화벽 정책 설계의 출발점입니다.

Inbound와 Outbound 방향 이해 — 인바운드는 외부에서 서버로 들어오는 트래픽(웹 80/443·SSH 22 허용), 아웃바운드는 서버에서 외부로 나가는 트래픽(DNS 53·패키지 업데이트·API 호출). "모두 허용"을 최소 허용으로 바꿀 때 방향별 필요 포트를 정리하지 않으면 서비스가 하나씩 죽음확대

방화벽 규칙을 설정할 때 가장 먼저 정해야 하는 것은 "어느 방향의 트래픽을 제어하는가"입니다. 서버는 외부 요청을 받기도 하고(Inbound), 외부로 직접 통신을 시작하기도 합니다(Outbound). 이 두 방향에 다른 기본 정책이 적용됩니다.

Inbound(인바운드): 외부에서 서버로 들어오는 트래픽

  • 예시: 클라이언트가 웹 서버 80포트에 접속하는 요청
  • 기본 정책: 대부분의 서버에서 기본 차단(Default Deny) 후 필요한 포트만 허용

Outbound(아웃바운드): 서버에서 외부로 나가는 트래픽

  • 예시: 서버가 패키지 업데이트를 위해 외부 리포지토리에 접속
  • 기본 정책: 보안 수준에 따라 허용하거나, 폐쇄망에서는 차단

방향성이 중요한 이유:

  • 웹 서버는 인바운드 80/443만 허용해도 동작하지만, DB 서버는 인바운드를 애플리케이션 서버 IP로만 제한해야 한다
  • 아웃바운드 제한은 악성코드의 C2(Command & Control) 서버 통신을 차단하는 데 효과적이다

트래픽 방향을 도식으로 보면 규칙이 어느 지점에서 검사되는지 명확해집니다.

방화벽 방향과 Stateful 추적 — Inbound/Outbound를 검사하되 conntrack이 연결을 NEW→ESTABLISHED로 추적해 응답을 자동 허용확대

Stateful Inspection과 conntrack

현대 방화벽의 핵심은 단순한 패킷 필터링이 아닌 세션 상태 추적이다.

💡개념

Stateful Inspection과 conntrack 테이블

방화벽 규칙에 인바운드 TCP 80을 허용했는데 HTTP 응답이 안 돌아옵니다. 요청은 들어오는데 응답 패킷이 차단된 겁니다. Stateless 방화벽은 패킷 하나하나를 독립적으로 판단하기 때문에, 내가 먼저 요청한 응답이라도 별도 허용 규칙이 없으면 막습니다. Stateful Inspection이 어떻게 세션 상태를 추적해서 이 문제를 해결하는지 알아야, 왜 현대 방화벽이 응답 트래픽을 따로 허용하지 않아도 동작하는지 납득이 됩니다.

Stateless 패킷 필터링의 문제점:

  • 각 패킷을 독립적으로 검사하므로 응답 패킷도 별도로 허용해야 한다
  • HTTP 요청에 대한 응답(TCP ACK, 데이터 패킷)을 모두 허용 규칙으로 나열해야 한다

Stateful Inspection과 conntrack 테이블 — Stateless 방화벽은 패킷마다 독립 판단해 응답용 아웃바운드 규칙을 따로 열어야 하지만, Stateful 방화벽은 conntrack 테이블로 연결 세션을 추적해 ESTABLISHED/RELATED 응답을 자동 허용. 인바운드 규칙 하나로 충분하며 AWS 보안그룹도 stateful확대

Stateful Inspection: Linux 커널의 conntrack(Connection Tracking) 모듈이 세션 테이블을 관리한다.

패킷conntrack 상태 변화
클라이언트 → 서버:80 (SYN)NEW 상태로 기록
서버 → 클라이언트 (SYN-ACK)ESTABLISHED 상태
클라이언트 → 서버 (ACK, 데이터)ESTABLISHED (자동 허용)

conntrack 상태값 — conntrack이 추적하는 연결 상태 유형과 의미입니다:

상태설명
NEW새 연결 시도 (첫 번째 패킷)
ESTABLISHED양방향 통신이 확인된 연결
RELATEDFTP 데이터 채널처럼 기존 연결에서 파생된 연결
INVALID어떤 상태에도 속하지 않는 비정상 패킷

실습: conntrack 테이블 확인 — 현재 커널이 추적 중인 연결 목록을 조회합니다:

로컬 터미널
# 실습 디렉토리 준비
mkdir -p /tmp/networking/part4/exam_21 && cd /tmp/networking/part4/exam_21

# conntrack 테이블 조회
conntrack -L

# 특정 포트 필터링
conntrack -L | grep dport=80

# 실시간 이벤트 모니터링
conntrack -E
🔍실행 후 확인할 것
  • Chain 기본 정책 — DROP vs ACCEPTiptables -L -v 출력에서 Chain INPUT (policy DROP) 처럼 기본 정책을 먼저 확인 — DROP이면 명시적 ACCEPT 없는 패킷은 모두 차단, ACCEPT면 명시적 DROP 없는 패킷은 모두 통과
  • pkts/bytes 카운터로 룰 적중 여부 확인-v 옵션의 pkts 컬럼이 계속 0이면 해당 룰에 도달하는 트래픽이 없는 것 — 룰 순서가 잘못됐거나 출발지 IP·포트 조건이 실제 패킷과 불일치함을 의미
  • REJECT vs DROP 응답 차이REJECT는 클라이언트에게 즉시 거부 메시지를 보내 연결 시도가 빠르게 종료됨 — DROP은 응답이 없어 클라이언트가 타임아웃까지 대기, 외부 공격자에게 포트 존재를 숨길 때 DROP 사용

장점: 인바운드 허용 규칙만 작성해도, 해당 세션의 응답 패킷은 자동으로 허용된다.

Stateful 추적 판단 — 누락 시 증상과 conntrack 한계
ESTABLISHED,RELATED 허용 룰을 빠뜨림나가는 요청은 되는데 '응답'이 막혀 통신 불가 — 아웃바운드는 되지만 결과를 못 받는 전형 증상. 거의 항상 INPUT 1번 룰로 -m state ESTABLISHED,RELATED ACCEPT
conntrack 테이블이 가득 참nf_conntrack: table full, dropping packet 로그 + 신규 연결 무작위 실패. nf_conntrack_max 확인(기본 수만~수십만). 고연결 서버는 상향 또는 메모리 점검 — '간헐 연결 실패+이 로그=conntrack 포화'
현재 추적 연결 수 확인conntrack -C 또는 /proc/sys/net/netfilter/nf_conntrack_count. nf_conntrack_max의 80%↑ 지속이면 증설 신호. 모니터링 대상 1순위
UDP·ICMP도 stateful이 되나된다(유사 상태 추적) — 단 UDP는 진짜 세션이 없어 타임아웃 기반. DNS·VoIP 등 단명 UDP가 많으면 conntrack 항목이 빠르게 쌓였다 빠진다
stateless로 운영하면응답 포트 범위를 직접 다 열어야 해 규칙이 폭증·구멍 위험. 현대 방화벽은 stateful이 기본 — 'stateless는 특수 목적(초고성능 L4)에서만'
비대칭 라우팅 환경요청과 응답이 다른 경로로 흐르면 conntrack이 세션을 못 따라가 INVALID로 드롭. 멀티홈·LB 뒤에서 발생 — 라우팅 대칭화 또는 정책 조정

ACL: 출발지/목적지/포트/프로토콜 기반 제어

ACL(Access Control List)은 네트워크 접근을 세밀하게 제어하는 규칙 목록이다.

💡개념

ACL이 패킷을 허용·거부하는 순서 — 5-tuple 추출부터 암묵적 거부까지

ACL에 규칙을 다 넣었는데 특정 트래픽만 막히거나, 반대로 막았어야 할 게 뚫립니다. ACL은 패킷의 5-tuple을 뽑아 규칙을 위에서부터 대조하고, 첫 매칭에서 판정을 끝낸 뒤, 아무 데도 안 걸리면 암묵적으로 거부합니다. 이 순서를 알면 "왜 이 규칙이 안 먹지"가 대부분 순서·범위 문제임이 보입니다.

TEXT
[패킷 도착]  예: 10.0.1.9 → 10.0.1.20 : 5432 / TCP
   │
   ① 5-tuple 추출: 출발지 IP·포트, 목적지 IP·포트, 프로토콜
   │     stateless ACL은 이 다섯 값만 보고 판단
   │
   ② ACL 규칙을 위에서부터 1번씩 대조
   │     각 규칙의 조건(소스·목적지·포트·프로토콜)과 5-tuple 비교
   │
   ③ 첫 매칭 규칙의 액션 적용 → 즉시 종료
   │     ALLOW면 통과, DENY면 차단 (뒤 규칙은 보지 않음)
   │
   ④ 어떤 규칙에도 안 맞으면 → 맨 끝의 암묵적 거부(implicit deny)
   ▼
[③에서 ALLOW된 경우만] 목적지 서비스로

각 단계에서 무슨 일이 일어나고, 어긋나면 어떤 증상인가:

단계하는 일여기서 어긋나면
① 5-tuple 추출소스·목적 IP와 포트, 프로토콜을 읽어 판단 재료로 삼음stateless ACL은 이게 전부라 응답 패킷도 따로 열어야 함 / stateful(conntrack)은 세션을 기억해 ESTABLISHED 응답을 자동 허용
② 순차 대조규칙을 위에서 아래로 하나씩 검사넓은 허용(ANY ALLOW·0-65535)이 위에 있으면 아래의 세밀한 DENY가 무력화(too broad·최소 권한 위반)
③ 첫 매칭 적용맞는 첫 규칙의 액션을 실행하고 종료DENY를 ALLOW보다 아래 두면 차단 의도가 안 먹음 / 위치가 곧 우선순위라 순서만 바꿔도 결과가 뒤집힘
④ 암묵적 거부아무 규칙에도 안 맞은 패킷을 기본 차단필요한 포트 규칙을 빠뜨리면 implicit deny에 걸려 조용히 막힘(규칙이 "없어서" 막힌 것) — 안전판이자 흔한 누락 원인

즉 ACL 진단은 **"이 패킷의 5-tuple에 어느 규칙이 먼저 맞았나"**를 순서대로 짚는 일입니다. 특정 서버만 막히면 그 출발지 IP가 허용 규칙 조건에 실제로 드는지, 더 위에 넓은 DENY나 순서 역전이 없는지 확인합니다. 나가는 요청은 되는데 응답만 막히면 stateful 허용(ESTABLISHED,RELATED)이 빠졌는지, 아무 규칙에도 안 걸려 막히면 implicit deny 누락을 의심합니다.

로컬 터미널
mkdir -p /tmp/networking/part4/firewall && cd /tmp/networking/part4/firewall
cat > policy.txt << 'EOF'
# 방화벽 정책 정의서
# 형식: 방향 소스 목적지 포트 프로토콜 액션

# 인바운드 허용
INBOUND  ANY      THIS_HOST  22   TCP  ALLOW   # SSH
INBOUND  ANY      THIS_HOST  80   TCP  ALLOW   # HTTP
INBOUND  ANY      THIS_HOST  443  TCP  ALLOW   # HTTPS
INBOUND  10.0.0.0/8  THIS_HOST  ANY  ANY  ALLOW  # 내부망

# 아웃바운드 허용
OUTBOUND THIS_HOST  ANY  80   TCP  ALLOW   # HTTP
OUTBOUND THIS_HOST  ANY  443  TCP  ALLOW   # HTTPS
OUTBOUND THIS_HOST  ANY  53   UDP  ALLOW   # DNS

# 기본 거부
DEFAULT  DROP
EOF
firewalld 설치 및 기본 상태 확인
위험 명령어

이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.

로컬 터미널
# firewalld 설치 (CentOS/RHEL/Rocky)
sudo dnf install -y firewalld

# firewalld 시작 및 자동 시작 설정
sudo systemctl start firewalld
sudo systemctl enable firewalld

# 현재 방화벽 상태 전체 확인
sudo firewall-cmd --state
sudo firewall-cmd --list-all

# 활성화된 Zone 확인
sudo firewall-cmd --get-active-zones

# 모든 Zone 목록 확인
sudo firewall-cmd --get-zones

예상 출력:

running

public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services: cockpit dhcpv6-client ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
서비스 기반 ACL 규칙 추가

firewalld는 사전 정의된 서비스 이름으로 포트를 쉽게 관리할 수 있다.

위험 명령어

이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.

로컬 터미널
# HTTP(80) 허용
sudo firewall-cmd --zone=public --add-service=http --permanent

# HTTPS(443) 허용
sudo firewall-cmd --zone=public --add-service=https --permanent

# SSH(22) 허용 확인 (기본 포함됨)
sudo firewall-cmd --zone=public --list-services

# 사용자 정의 포트 허용 (예: 8080/TCP)
sudo firewall-cmd --zone=public --add-port=8080/tcp --permanent

# 포트 범위 허용 (예: 8000-8100/TCP)
sudo firewall-cmd --zone=public --add-port=8000-8100/tcp --permanent

# 설정 적용 (--permanent 옵션 후 반드시 필요)
sudo firewall-cmd --reload

# 적용 확인
sudo firewall-cmd --zone=public --list-all

주의: --permanent 없이 추가하면 재부팅 시 사라진다. --permanent로 추가하면 --reload가 필요하다.

Rich Rule로 세밀한 ACL 작성

Rich Rule을 사용하면 출발지 IP, 포트, 프로토콜을 조합한 정밀한 규칙을 만들 수 있다.

위험 명령어

이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.

로컬 터미널
# 특정 IP에서 SSH만 허용 (관리자 IP만 SSH 접속 허용)
sudo firewall-cmd --zone=public --add-rich-rule='
  rule family="ipv4"
  source address="203.0.113.10/32"
  service name="ssh"
  accept' --permanent

# 내부 네트워크(192.168.1.0/24)에서 MySQL(3306) 허용
sudo firewall-cmd --zone=public --add-rich-rule='
  rule family="ipv4"
  source address="192.168.1.0/24"
  port port="3306" protocol="tcp"
  accept' --permanent

# 특정 IP 차단 (블랙리스트)
sudo firewall-cmd --zone=public --add-rich-rule='
  rule family="ipv4"
  source address="10.0.0.5/32"
  reject' --permanent

# 연결 시도를 로그로 기록하면서 차단
sudo firewall-cmd --zone=public --add-rich-rule='
  rule family="ipv4"
  source address="10.0.0.0/8"
  port port="3306" protocol="tcp"
  log prefix="DB_ACCESS_ATTEMPT " level="warning"
  reject' --permanent

sudo firewall-cmd --reload

# Rich Rule 목록 확인
sudo firewall-cmd --zone=public --list-rich-rules

firewalld Zone 관리

💡개념

firewalld Zone 개념과 활용

서버에 인터페이스가 두 개 있습니다. 하나는 내부 관리망, 다른 하나는 외부 공개망에 연결됩니다. 두 인터페이스에 같은 방화벽 규칙을 적용하면 관리망에서나 외부에서나 동일하게 취급되어 보안 구분이 사라집니다. Zone은 인터페이스나 출발지 IP에 따라 신뢰 수준을 다르게 적용하는 개념으로, 이것을 이해해야 "내부망은 관대하게, 외부망은 엄격하게"라는 정책을 firewalld에서 제대로 구현할 수 있습니다.

Zone은 네트워크 인터페이스나 출발지 IP에 따라 다른 신뢰 수준을 부여하는 개념이다.

firewalld Zone 개념과 활용 — firewalld는 인터페이스·출발지 IP를 신뢰 수준별 zone에 묶음: drop(수신 전면 차단)·block·public(기본, 공용망)·external(마스커레이딩)·dmz·work·home·internal·trusted(전면 허용). 같은 포트라도 어느 zone에 속하느냐로 허용 여부가 갈림확대

주요 Zone 비교 — Zone마다 신뢰 수준이 다르며, 인터페이스에 Zone을 할당해 정책을 적용합니다:

Zone신뢰 수준설명
trusted최고모든 트래픽 허용 (사내 관리망)
internal높음내부 네트워크용
home중간홈 네트워크
public낮음외부 인터페이스 기본값
dmz낮음DMZ 구간 서버
block없음모든 인바운드 차단 (ICMP 거부)
drop없음모든 인바운드 무시 (응답 없음)

Zone 활용 예시 - 3-tier 아키텍처 — 각 계층에 서로 다른 Zone을 적용해 트래픽 흐름을 제어합니다: 보안 존 기반 계층 분리 — 인터넷→public→internal→trusted로 신뢰 수준이 높아지고 각 경계에서 ACL로 접근 제한확대

로컬 터미널
# 인터페이스를 특정 Zone에 할당
sudo firewall-cmd --zone=internal --change-interface=eth1 --permanent

# 출발지 IP 대역을 Zone에 바인딩
sudo firewall-cmd --zone=trusted --add-source=10.0.0.0/8 --permanent

# Zone별 규칙 확인
sudo firewall-cmd --zone=internal --list-all
sudo firewall-cmd --zone=trusted --list-all
최소 권한 규칙 적용 실습

프로덕션 서버에 최소 권한 원칙을 적용한다.

위험 명령어

이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.

로컬 터미널
# 현재 public Zone의 불필요한 서비스 제거
# cockpit(웹 콘솔)과 dhcpv6-client 제거
sudo firewall-cmd --zone=public --remove-service=cockpit --permanent
sudo firewall-cmd --zone=public --remove-service=dhcpv6-client --permanent

# 필요한 서비스만 명시적 허용
# 1. 관리자 IP에서만 SSH 허용 (기본 SSH 서비스 제거 후 Rich Rule로 교체)
sudo firewall-cmd --zone=public --remove-service=ssh --permanent

sudo firewall-cmd --zone=public --add-rich-rule='
  rule family="ipv4"
  source address="YOUR_ADMIN_IP/32"
  service name="ssh"
  accept' --permanent

# 2. 웹 서비스 허용
sudo firewall-cmd --zone=public --add-service=http --permanent
sudo firewall-cmd --zone=public --add-service=https --permanent

# 3. 기본 정책 확인 (default는 REJECT)
sudo firewall-cmd --zone=public --get-target

# 적용
sudo firewall-cmd --reload

# 최종 확인
sudo firewall-cmd --zone=public --list-all

결과: SSH는 관리자 IP에서만, HTTP/HTTPS는 전체에서, 나머지는 모두 차단된 최소 권한 정책이 완성된다.

기존 세션 끊김 부작용

증상: firewall-cmd --reload를 실행하자마자 SSH 터미널이 응답 없음 상태가 되었다.

원인 분석 — reload 전후 conntrack 상태를 비교해 세션 초기화 여부를 확인합니다:

로컬 터미널
# 변경 전 conntrack 상태 확인
conntrack -L | grep dport=22
# 출력: tcp 6 86398 ESTABLISHED src=203.0.113.10 dst=10.0.1.5 sport=52431 dport=22 ...

# --reload는 규칙을 완전히 재로드하며, 일부 배포판에서 conntrack 테이블이 초기화됨
# 또는 새 규칙이 기존 ESTABLISHED 세션을 다시 검사

해결 방법:

방법 1: --reload 대신 --runtime-to-permanent 사용

로컬 터미널
# 임시 규칙을 먼저 적용 (reload 없이 즉시 반영)
sudo firewall-cmd --zone=public --add-service=ssh  # --permanent 없이

# 동작 확인 후 영구 저장
sudo firewall-cmd --runtime-to-permanent

방법 2: 새 SSH 세션 열어둔 채로 작업

로컬 터미널
# 작업 전 다른 터미널에서 SSH 접속을 열어둔다
# 규칙 변경 후 새 세션으로 접속 테스트 → 성공 확인 후 기존 세션 종료

방법 3: at 명령으로 자동 롤백 예약

위험 명령어

이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.

로컬 터미널
# 5분 후 방화벽 규칙 초기화 예약 (실수 대비 안전망)
echo "firewall-cmd --reload" | sudo at now + 5 minutes

# 방화벽 규칙 적용
sudo firewall-cmd --zone=public --remove-service=ssh --permanent
sudo firewall-cmd --reload

# 접속 테스트 성공 시 at 작업 취소
sudo atq  # 작업 번호 확인
sudo atrm [작업번호]

예방: 프로덕션 방화벽 변경 시 항상 Maintenance Window를 잡고, 콘솔 접근(IPMI, iDRAC) 또는 Out-of-Band 채널을 확보한다.

증상: 웹 서버 80포트는 접속되는데, 애플리케이션에서 외부 API를 호출하면 타임아웃이 발생한다.

원인 분석 — 아웃바운드 규칙과 실시간 conntrack 세션을 순서대로 점검합니다:

로컬 터미널
# 아웃바운드 규칙 확인
sudo firewall-cmd --zone=public --list-all
# → outbound 제한이 보임

# 서버에서 외부 API 직접 테스트
curl -v https://api.example.com/v1/test
# → 연결 타임아웃

# 방화벽 로그 확인
sudo journalctl -u firewalld -f

# conntrack으로 아웃바운드 세션 추적
conntrack -L | grep dport=443

해결 — 아웃바운드 HTTPS를 rich-rule로 명시적으로 허용합니다:

위험 명령어

이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.

로컬 터미널
# 아웃바운드 HTTPS 허용 (기본적으로 아웃바운드는 허용이지만,
# 일부 강화된 정책에서는 차단될 수 있음)
sudo firewall-cmd --zone=public --add-rich-rule='
  rule family="ipv4"
  destination address="0.0.0.0/0"
  port port="443" protocol="tcp"
  accept' --permanent

# 또는 nftables 직접 확인
sudo nft list ruleset | grep -A5 "output"

sudo firewall-cmd --reload

교훈: 방화벽 정책은 인바운드뿐 아니라 아웃바운드도 고려해야 하며, 특히 서버가 외부 의존성(API, DNS, NTP)을 갖는 경우 아웃바운드 규칙을 명시적으로 관리해야 한다.

심화 — firewalld는 규칙을 어떤 순서로 고르는가

💡개념

심화: source zone 우선순위와 rich rule priority — 규칙을 다 넣었는데 의도와 다른 이유

규칙을 전부 맞게 넣은 것 같은데 의도와 달리 뚫리거나 막힌다면, 대개 firewalld가 '어느 zone을, 어떤 순서로' 적용하는지를 놓친 것입니다. firewalld는 iptables처럼 규칙을 위에서 아래로 나열해 읽지 않고, 먼저 zone을 고르고 그 안에서 판단합니다.

  • source-based zone이 interface zone을 이긴다: 패킷이 도착하면 firewalld는 먼저 '출발지 IP가 어떤 zone의 source로 바인딩돼 있는가'를 봅니다. 바인딩돼 있으면 그 패킷이 어느 인터페이스로 들어오든 인터페이스의 zone이 아니라 그 source zone을 적용합니다. 그래서 firewall-cmd --add-source=10.0.0.0/8을 trusted에 붙이면, 그 대역은 public 인터페이스로 들어와도 trusted(target ACCEPT)로 취급돼 열어둔 적 없는 포트까지 전부 열립니다. '편의상 대역을 trusted에' 넣는 것이 그 대역에 한해 방화벽을 끄는 것과 같습니다.
  • rich rule은 priority로 순서를 준다: 같은 zone 안에서 accept와 reject rich rule이 겹칠 때, priority를 지정하지 않으면 '먼저 특정 IP를 차단하고 그다음 대역을 허용' 같은 의도한 순서가 보장되지 않습니다. priority 값이 낮을수록(음수 포함) 먼저 평가되므로, 차단 규칙을 허용보다 앞세우려면 priority를 명시해야 합니다.
  • 마지막은 zone의 target: 어느 rich rule·service·port에도 안 걸린 나머지는 zone의 기본 target(default/ACCEPT/DROP/REJECT)이 결정합니다. trusted처럼 target이 ACCEPT인 zone은 '나머지 전부 허용'이 기본값입니다.

즉 firewalld에서 '왜 이 IP만 다르게 동작하지'라는 의문은 대개 어느 zone으로 분류됐는가에서 시작해야 풀립니다.

상황: public 인터페이스에는 http/https만 허용해 뒀는데, 모니터링 편의를 위해 사내 대역 10.0.0.0/8을 trusted zone의 source로 추가한 뒤부터, 그 대역에서는 5432(DB)·9090 등 연 적 없는 포트까지 다 접속됩니다. 인터페이스는 여전히 public인데도 그렇습니다.

원인: firewalld는 출발지 IP가 특정 zone에 바인딩돼 있으면, 그 패킷이 어느 인터페이스로 들어오든 인터페이스 zone(public)이 아니라 source zone(trusted)을 적용합니다. trusted는 target이 ACCEPT라 모든 포트를 허용합니다. 결국 '편의상 trusted에 대역 추가'가 그 대역에 한해 방화벽을 사실상 끈 셈입니다.

진단: firewall-cmd --get-active-zones로 그 대역이 어느 zone에 source로 붙었는지 확인합니다. firewall-cmd --zone=trusted --list-all에서 sources에 10.0.0.0/8이 있고 target이 ACCEPT인지 봅니다. 특정 IP가 어느 zone으로 처리되는지 헷갈릴 때는 인터페이스 zone이 아니라 소스 바인딩부터 확인합니다.

해결: 대역을 trusted가 아니라, 필요한 서비스만 허용하는 internal(또는 전용) zone에 붙이고 거기에 rich rule로 꼭 필요한 포트만 엽니다. 전면 신뢰가 정말 필요한 극소수 관리 호스트만 개별 IP로 trusted에 두고, 대역 단위로는 trusted를 쓰지 않습니다(CentOS/Ubuntu 서버 방화벽(firewalld / ufw) 포트 열기에서 zone별 정책 구성을 확인).

실전 방화벽 정책 설계

웹 애플리케이션 서버 보안 정책 완성

3-tier 웹 서비스의 애플리케이션 서버에 적합한 방화벽 정책을 완성한다.

위험 명령어

이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.

로컬 터미널
#!/bin/bash
# app-server-firewall.sh
# 애플리케이션 서버 방화벽 정책 설정 스크립트

# 변수 정의
ADMIN_IP="203.0.113.10"     # 관리자 IP
WEB_SERVER_IP="10.0.1.10"   # 웹 서버 (프론트엔드)
DB_SERVER_IP="10.0.1.20"    # DB 서버

# 1. 기본 불필요 서비스 제거
firewall-cmd --zone=public --remove-service=cockpit --permanent
firewall-cmd --zone=public --remove-service=dhcpv6-client --permanent
firewall-cmd --zone=public --remove-service=ssh --permanent

# 2. 관리자만 SSH 허용
firewall-cmd --zone=public --add-rich-rule="
  rule family=ipv4
  source address=${ADMIN_IP}/32
  service name=ssh
  accept" --permanent

# 3. 웹 서버에서 앱 포트(8080) 허용
firewall-cmd --zone=public --add-rich-rule="
  rule family=ipv4
  source address=${WEB_SERVER_IP}/32
  port port=8080 protocol=tcp
  accept" --permanent

# 4. 앱 서버 → DB 서버 아웃바운드 허용 (나머지 아웃바운드는 제한)
firewall-cmd --zone=public --add-rich-rule="
  rule family=ipv4
  destination address=${DB_SERVER_IP}/32
  port port=5432 protocol=tcp
  accept" --permanent

# 5. ICMP (ping) - 네트워크 진단용으로 내부에서만 허용
firewall-cmd --zone=public --add-rich-rule="
  rule family=ipv4
  source address=10.0.0.0/8
  icmp-type name=echo-request
  accept" --permanent

# 6. 그 외 모든 트래픽 차단 (기본 target: default = REJECT)
firewall-cmd --zone=public --set-target=default --permanent

firewall-cmd --reload

# 최종 정책 확인
echo "=== 최종 방화벽 정책 ==="
firewall-cmd --zone=public --list-all
로컬 터미널
# 스크립트 실행
chmod +x app-server-firewall.sh
sudo ./app-server-firewall.sh

# 정책 검증
# 1. 외부에서 SSH 시도 → 거부 확인
# 2. 관리자 IP에서 SSH 접속 → 성공 확인
# 3. 웹 서버에서 8080 포트 접속 → 성공 확인
# 4. 다른 IP에서 8080 포트 접속 → 거부 확인

방화벽 정책 감사와 모니터링

방화벽 로그 분석과 정책 감사
로컬 터미널
# 방화벽 드롭 패킷 로그 활성화
sudo firewall-cmd --zone=public --add-rich-rule='
  rule family="ipv4"
  source address="0.0.0.0/0"
  log prefix="FIREWALL_DROP " level="info" limit value="5/m"
  drop' --permanent

# 로그 실시간 모니터링
sudo journalctl -f | grep FIREWALL_DROP

# 또는 커널 로그에서 확인
sudo dmesg | grep FIREWALL_DROP

# nftables 규칙 전체 확인 (firewalld 백엔드)
sudo nft list ruleset

# 규칙 통계 (패킷/바이트 카운트)
sudo nft list ruleset | grep -E "packets|bytes"

# iptables 호환 모드로 현재 규칙 확인 (구버전 호환)
sudo iptables -L -n -v --line-numbers

정리

이 챕터에서 학습한 핵심 내용:

  1. 방향성: Inbound는 기본 차단, Outbound는 정책에 따라 관리
  2. Stateful Inspection: conntrack이 세션 상태를 추적해 응답 패킷을 자동 허용
  3. ACL 구성 요소: 출발지 IP + 목적지 포트 + 프로토콜 조합으로 세밀한 제어
  4. firewalld Zone: trusted/public 등 신뢰 수준별 Zone으로 인터페이스 관리
  5. 최소 권한: 기본 차단 후 필요한 것만 허용 (Default Deny)
  6. 부작용 관리: 규칙 변경 시 기존 세션 끊김 가능성을 고려한 안전한 작업 절차

명령어·단축키 빠른 참조

이 모듈에서 다룬 방화벽 정책·conntrack 명령을 실전 옵션과 함께 모았습니다. "예" 열의 조합을 그대로 써도 됩니다.

명령어/단축키용도자주 쓰는 예
firewall-cmd --list-all현재 zone 규칙 전체 확인sudo firewall-cmd --zone=public --list-all
firewall-cmd --get-active-zones인터페이스·source의 zone 바인딩source zone 우선순위 함정 진단 시
firewall-cmd --add-service / --add-port서비스·포트 허용--zone=public --add-port=8080/tcp --permanent
firewall-cmd --add-rich-rule출발지 IP+포트+프로토콜 ACLrule family=ipv4 source address=203.0.113.10/32 service name=ssh accept
firewall-cmd --add-source대역을 zone에 바인딩--zone=internal --add-source=10.0.0.0/8 (trusted 금지)
firewall-cmd --reload--permanent 규칙 적용세션 끊김 주의 — 대안은 아래
firewall-cmd --runtime-to-permanent런타임 규칙을 무중단 영구화reload 없이 즉시 반영 후 저장
firewall-cmd --list-rich-rules등록된 rich rule 확인--zone=public --list-rich-rules
conntrack -L추적 중인 세션 조회conntrack -L | grep dport=22
conntrack -C현재 추적 연결 수nf_conntrack_max의 80%↑면 증설 신호
nft list rulesetfirewalld 백엔드 규칙 전체sudo nft list ruleset | grep -A5 output
iptables -L -n -v체인 기본정책·룰 적중 카운터iptables -L -n -v --line-numbers (pkts 0=미적중)
... | at now + 5 minutes실수 대비 자동 롤백 예약echo "firewall-cmd --reload" | sudo at now + 5 minutes

관련 모듈로 더 깊이:

다음 챕터에서는 이 방화벽 앞단에서 트래픽을 분산하는 로드밸런서를 학습한다.

지식 확인

퀴즈 — 8문제

Q1

웹 서버에서 `curl https://api.internal:443`이 성공하는데 앱 서버에서 같은 주소로 연결하면 타임아웃이 납니다. 방화벽 정책에서 가장 먼저 확인할 사항은?

Q2

보안 점검에서 '`firewall-cmd --add-port=0-65535/tcp --permanent`가 적용된 서버'를 발견했습니다. 즉각 조치해야 하는 이유는?

Q3

운영 서버에서 방화벽 정책을 변경하다가 실수로 기존 DB 커넥션이 끊어졌습니다. 방화벽 규칙 변경 전에 해야 할 조치는?

Q4

실행 중인 서버에서 방화벽 규칙을 즉시 변경했을 때 발생할 수 있는 부작용은?

Q5

ACL 규칙에서 출발지 IP 192.168.1.0/24, 목적지 포트 443, 프로토콜 TCP를 허용할 때 올바른 firewall-cmd 명령은?

Q6

firewalld의 'Zone(존)' 개념이 방화벽 정책 관리에 주는 이점은?

Q7

[심화] firewalld에서 eth0은 public zone인데, 출발지 10.0.0.0/8을 trusted zone의 source로 추가했다. 10.0.0.5가 eth0로 접속하면 어느 zone 정책이 적용되는가?

Q8

[심화] public 인터페이스에 http/https만 열어둔 서버인데, 사내 대역 10.0.0.0/8에서는 연 적 없는 DB 포트(5432)까지 접속된다. 그 대역을 얼마 전 trusted zone의 source에 추가했다. 확인 순서로 가장 적절한 것은?

0 / 8 답변

🧪 실습으로 확인하기

NAT·포트포워딩 — 내부 서버 외부 노출 디버깅

고급

사설 IP 내부 서버를 외부에 노출하는 DNAT(포트포워딩)이 안 될 때, NAT 동작(SNAT/DNAT)을 이해하고, iptables nat 규칙·IP 포워딩 커널 설정·방화벽·복귀 경로(비대칭)를 순서대로 점검해 끊긴 고리를 찾는다. conntrack으로 변환을 추적하는 법도 다룬다.

45📋 3단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요