서비스는 정상적으로 8080에서 리스닝 중인데 외부 접속은 타임아웃입니다. 클라우드 보안그룹을 열어도 OS 안의 firewalld가 마지막 관문에서 패킷을 막고 있었습니다.
호스트 방화벽은 서버 안쪽의 마지막 문입니다. 열기 전에 무엇을 열고 있는지 정확히 확인해야 합니다.
OS 호스트 방화벽 포트 열기 (firewalld / ufw)
애플리케이션을 배포했는데 외부에서 접속이 안 될 때,
OS 방화벽이 포트를 차단하고 있는 경우가 매우 흔합니다.
이 챕터에서는 CentOS의 firewalld와 Ubuntu의 ufw로
원하는 포트를 안전하게 열고 확인하는 방법을 익힙니다.
1. 방화벽 레이어 이해
- 1네트워크 방화벽과 OS 호스트 방화벽 레이어의 차이를 설명할 수 있다
- 2firewalld 존(zone) 개념을 이해하고 CentOS에서 포트를 관리할 수 있다
- 3ufw 기본 명령어로 Ubuntu 포트 허용 규칙을 관리할 수 있다
- 4--permanent 옵션 누락 시 재부팅 후 규칙이 소실되는 문제를 해결할 수 있다
- 5포트를 열어도 접속이 안 될 때 SELinux, 바인딩 주소를 단계별로 추가 점검할 수 있다
firewall-cmd --list-allufw status verbosess -tulnp | grep 8080sestatus네트워크 방화벽 vs OS 호스트 방화벽 레이어
포트 8080을 열었는데도 외부에서 접속이 안 됩니다. AWS 보안 그룹에서 열었고, ss -tlnp로 확인하니 프로세스도 LISTEN 중입니다. 그런데 실제로는 firewalld가 OS 레벨에서 막고 있었습니다. 방화벽이 네트워크 방화벽과 OS 호스트 방화벽 두 레이어로 나뉜다는 것을 모르면 한 곳만 확인하고 "설정 다 맞는데 왜 안 되지"를 반복하게 됩니다.
확대
방화벽은 어느 레이어에서 동작하느냐에 따라 역할이 다릅니다.
방화벽 레이어 구조
[인터넷]
↓
[네트워크 방화벽 / UTM] ← 여러 서버를 동시 보호
↓ (라우터, 방화벽 어플라이언스)
[스위치/라우터]
↓
[OS 호스트 방화벽] ← 해당 서버 자체만 보호
↓ (firewalld / ufw / iptables)
[애플리케이션]
| 구분 | 네트워크 방화벽 | OS 호스트 방화벽 |
|---|---|---|
| 위치 | 네트워크 인프라 장비 | 서버 OS 내부 |
| 관리 주체 | 네트워크/보안팀 | 시스템 관리자 |
| 적용 범위 | 여러 서버/구간 | 단일 서버 |
| 도구 | Cisco ASA, pf, AWS SG | firewalld, ufw, iptables |
심층 방어(Defense in Depth)
두 레이어를 함께 사용하면, 한쪽이 뚫려도 나머지 레이어에서 막을 수 있습니다. 특히 내부망에서 서버 간 이동 공격(Lateral Movement)을 OS 방화벽으로 막는 것이 중요합니다.
firewalld, ufw, iptables의 관계
- iptables — Linux 커널 방화벽 프레임워크 (실제 규칙 처리)
- firewalld — CentOS/RHEL의 iptables 프론트엔드
- ufw — Ubuntu의 iptables 프론트엔드
firewalld와 ufw는 iptables를 사용하기 쉽게 감싸주는 관리 도구입니다. 직접 iptables를 작성하는 것보다 실수가 적습니다.
firewall-cmd 한 줄이 실제 차단·허용이 되기까지 — 선언부터 패킷 평가까지
firewall-cmd --add-port=8080/tcp --permanent을 쳤는데 아직 접속이 안 되거나, 반대로 목록엔 없는데 열려 있는 경우가 있습니다. 이는 명령 한 줄이 곧바로 패킷을 막는 게 아니라 선언 → 백엔드 변환 → 활성 반영 → 패킷 평가라는 단계를 거치기 때문입니다. 이 파이프라인을 알면 "열었는데 막힘"이 어느 단계에서 어긋났는지 짚을 수 있습니다.
[관리자] firewall-cmd --add-port=8080/tcp --permanent (또는 ufw allow 8080/tcp)
│
① 규칙 선언: 어느 zone에 무엇을(포트·서비스·rich rule) 허용/거부할지 기술
│ --permanent → 디스크 설정 파일에 기록 (이 시점엔 아직 미적용)
│
② 백엔드 변환: firewalld/ufw가 이 선언을 실제 커널 규칙으로 번역
│ RHEL9+ = nftables, 구형·ufw = iptables 규칙으로 생성
│
③ 활성 반영: firewall-cmd --reload / ufw는 자동으로 런타임에 로드
│ 이 단계를 건너뛰면 파일엔 있어도 커널엔 없음
│
④ 패킷 평가: 트래픽이 오면 그 패킷이 속한 zone의 규칙과 대조 → 허용/거부
▼
[허용된 경우만] 서비스(8080)에 도달
각 단계에서 무슨 일이 일어나고, 막히면(열었는데 막힘) 어떤 증상인가:
| 단계 | 하는 일 | 여기서 막히면 |
|---|---|---|
| ① 규칙 선언 | firewall-cmd·ufw로 zone·포트·서비스를 허용/거부로 선언 | --permanent만 하고 런타임 반영을 안 하면 지금은 적용 안 됨 / --permanent 없이 하면 재부팅·재시작 때 사라짐 |
| ② 백엔드 변환 | 선언을 nftables·iptables 규칙으로 번역해 커널에 넣을 형태로 만듦 | 한 호스트에서 firewalld와 ufw를 동시에 쓰면 두 규칙 집합이 충돌·중복 / Docker가 넣는 FORWARD 규칙은 이 경로 밖이라 firewalld 목록에 안 보여도 열림 |
| ③ 활성 반영 | --reload(firewalld)로 저장된 설정을 런타임 커널에 로드 | --reload를 안 하면 설정 파일엔 있는데 실제론 안 열림·안 막힘 / --list-all(런타임)과 --permanent --list-all이 다르면 미반영 신호 |
| ④ 패킷 평가 | 도착 패킷의 인터페이스·출발지로 zone을 정하고 그 zone 규칙과 대조 | 인터페이스가 예상과 다른 zone에 묶여 있으면(zone 불일치) 열어둔 규칙이 그 패킷엔 적용 안 됨 / 출발지 기반 zone이 인터페이스 zone을 이김 |
즉 **"방화벽에서 열었는데 막힌다"의 대부분은 ③(리로드 안 함) 아니면 ④(zone 불일치)**입니다. firewall-cmd --get-active-zones로 인터페이스가 어느 zone인지 확인하고, firewall-cmd --list-all(런타임)과 firewall-cmd --permanent --list-all을 대조해 반영 여부를 봅니다. ufw는 ufw status verbose로 active·규칙을 확인하고, 실제 커널 규칙은 iptables -L이나 nft list ruleset로 백엔드까지 내려가 대조합니다.
2. CentOS — firewalld 사용법
firewalld 존(zone)과 포트 관리
CentOS/RHEL 서버에서 포트를 열었는데 적용이 안 됩니다. --permanent 옵션을 빠뜨렸거나, 잘못된 zone에 규칙을 추가한 경우입니다. firewalld의 zone 개념을 이해하지 못하면 포트를 열어도 왜 적용이 안 되는지, 재부팅 후 왜 원상 복구가 되는지 이유를 알 수 없습니다.
확대
firewalld는 존(zone) 개념으로 네트워크 인터페이스를 분류하고 각 존에 다른 정책을 적용합니다.
주요 존과 기본 정책
| 존 | 설명 | 기본 정책 |
|---|---|---|
public | 외부 공개 네트워크 | 선택적 허용 |
trusted | 완전히 신뢰하는 네트워크 | 모든 연결 허용 |
internal | 내부 네트워크 | 선택적 허용 |
drop | 가장 엄격 | 모든 연결 차단 |
block | 엄격 | 들어오는 연결 거부 |
주요 명령어
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# 실습 디렉토리 준비
mkdir -p /tmp/networking/part4/exam_22 && cd /tmp/networking/part4/exam_22
# 서비스 상태 확인
systemctl status firewalld
# 서비스 시작/활성화
systemctl start firewalld
systemctl enable firewalld
# 현재 활성 존과 규칙 전체 확인
firewall-cmd --list-all
# 특정 존의 규칙 확인
firewall-cmd --zone=public --list-all
# 현재 적용된 포트 목록만 확인
firewall-cmd --list-ports
# 포트 추가 (영구 적용)
firewall-cmd --zone=public --add-port=8080/tcp --permanent
firewall-cmd --reload
# 포트 제거 (영구)
firewall-cmd --zone=public --remove-port=8080/tcp --permanent
firewall-cmd --reload
# 런타임(즉시)과 영구 동시에 추가
firewall-cmd --zone=public --add-port=8080/tcp
firewall-cmd --zone=public --add-port=8080/tcp --permanent
- ufw Status: active / inactive—ufw status verbose 첫 줄에서 Status: active인지 먼저 확인 — inactive면 방화벽이 비활성화 상태로 룰 자체가 적용되지 않음, ufw enable로 활성화 필요
- 허용 포트 목록에서 대상 포트 존재 여부—ufw status numbered 출력에서 대상 포트(예: 22, 80, 443)가 ALLOW IN으로 나오는지 확인 — 없으면 해당 포트로의 외부 접근이 전부 차단됨
- firewall-cmd zones와 services 조합—firewall-cmd --list-all 출력에서 services: 줄에 http, https, ssh가 있는지 확인 — zone이 public이어도 services에 없으면 차단, 포트 직접 허용과 서비스 허용은 별개로 동작
3. Ubuntu — ufw 사용법
ufw 기본 명령어와 규칙 관리
Ubuntu 서버에 포트를 열어야 합니다. iptables 명령은 너무 복잡하고, firewalld는 Ubuntu에서 기본이 아닙니다. Ubuntu에서는 ufw가 표준입니다. ufw allow 80처럼 직관적인 명령어로 방화벽 규칙을 관리할 수 있는데, 기본 사용법을 모르면 매번 검색해야 합니다.
확대
ufw(Uncomplicated Firewall)는 Ubuntu에서 사용하는
사용하기 쉬운 방화벽 관리 도구입니다.
주요 명령어
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# ufw 상태 확인
ufw status
# 상세 상태 확인 (규칙 포함)
ufw status verbose
# ufw 활성화/비활성화
ufw enable
ufw disable
# 번호와 함께 규칙 목록 확인 (삭제 시 유용)
ufw status numbered
# 포트 허용
ufw allow 8080/tcp
ufw allow 8080/udp
ufw allow 8080 # TCP+UDP 모두 허용
# 포트 거부
ufw deny 8080/tcp
# 특정 IP에서만 특정 포트 허용
ufw allow from 192.168.1.100 to any port 3306
# 특정 IP 대역에서 허용
ufw allow from 192.168.1.0/24 to any port 3306
# 규칙 삭제 (번호로)
ufw status numbered
ufw delete 3 # 3번 규칙 삭제
# 규칙 삭제 (규칙 내용으로)
ufw delete allow 8080/tcp
# ufw 규칙 전체 초기화
ufw reset
서비스 이름으로 허용
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# 서비스 이름으로 허용 (사전 정의된 서비스)
ufw allow ssh
ufw allow http
ufw allow https
# 사용 가능한 서비스 목록
ls /etc/ufw/applications.d/
ufw app list
4. 실습: 웹 애플리케이션 포트 열기
8080 포트에서 실행되는 웹 애플리케이션에 외부 접속을 허용합니다.
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# 현재 방화벽 상태 확인
firewall-cmd --list-all
# public (active)
# target: default
# ...
# ports: 22/tcp
# ...
# 8080 포트 추가 (영구 + 즉시 적용)
firewall-cmd --zone=public --add-port=8080/tcp --permanent
firewall-cmd --reload
# 추가 확인
firewall-cmd --list-ports
# 22/tcp 8080/tcp
# 또는 전체 확인
firewall-cmd --list-all
# public (active)
# ...
# ports: 22/tcp 8080/tcp ← 추가됨
# 외부에서 연결 테스트
curl -v --connect-timeout 5 http://서버IP:8080
여러 포트 한번에 추가
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# 3000-3010 범위 포트 열기
firewall-cmd --zone=public --add-port=3000-3010/tcp --permanent
# 여러 포트 동시에
firewall-cmd --zone=public --add-port=8080/tcp --add-port=8443/tcp --permanent
firewall-cmd --reload
Ubuntu 서버에서 ufw로 동일한 작업을 수행합니다.
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# ufw 상태 확인
ufw status verbose
# Status: active (또는 inactive)
# ufw가 비활성화라면 활성화
# 먼저 실제 SSH 포트를 확인합니다(22가 아닐 수 있음).
sudo ss -tlnp | grep sshd
SSH_PORT=22 # /etc/ssh/sshd_config의 Port 값으로 교체
ufw allow "${SSH_PORT}/tcp" # 실제 관리 포트를 먼저 허용
ufw enable # 활성화
# 8080 포트 허용
ufw allow 8080/tcp
# 상태 확인
ufw status verbose
# Status: active
#
# To Action From
# -- ------ ----
# 22/tcp ALLOW IN Anywhere
# 8080/tcp ALLOW IN Anywhere ← 추가됨
# 외부에서 연결 테스트
curl -v --connect-timeout 5 http://서버IP:8080
주의: ufw enable 전 SSH 허용 필수
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# 원격 서버에서 작업할 때 이 순서를 반드시 지키세요!
ufw allow "${SSH_PORT}/tcp" # ← 실제 SSH 포트 먼저!
ufw enable # ← 그 다음!
# 순서 바꾸면 SSH 세션이 끊기고 서버 접근 불가
--permanent 없이 추가한 규칙이 재부팅 후 사라지는 것을 확인합니다.
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# [잘못된 예] --permanent 없이 포트 추가
firewall-cmd --zone=public --add-port=9090/tcp
# success
# 현재는 적용됨
firewall-cmd --list-ports
# 22/tcp 8080/tcp 9090/tcp
# 재부팅 시뮬레이션 — firewalld 재시작
systemctl restart firewalld
# 재시작 후 확인
firewall-cmd --list-ports
# 22/tcp 8080/tcp ← 9090이 사라짐!
# [올바른 방법] --permanent와 --reload
firewall-cmd --zone=public --add-port=9090/tcp --permanent
firewall-cmd --reload
# 다시 확인
firewall-cmd --list-ports
# 22/tcp 8080/tcp 9090/tcp
# 재시작해도 유지 확인
systemctl restart firewalld
firewall-cmd --list-ports
# 22/tcp 8080/tcp 9090/tcp ← 유지됨!
런타임 vs 영구 설정 차이
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# 런타임 설정만 확인 (현재 실행 중)
firewall-cmd --list-ports
# 영구(permanent) 저장된 설정 확인
firewall-cmd --permanent --list-ports
# 두 결과가 다르면 --reload로 동기화
방화벽에서 포트를 열었음에도 접속이 안 되는 경우 추가로 확인해야 할 항목들을 점검합니다.
# [점검 1] 프로세스가 해당 포트에서 리스닝하는지 확인
ss -tulnp | grep 8080
# 출력이 없으면 → 애플리케이션이 8080에서 실행되지 않는 것
# [점검 2] SELinux 포트 정책 (CentOS/RHEL)
# SELinux가 활성화된 경우 별도 포트 허용 필요
sestatus
# SELinux status: enabled
# Current mode: enforcing ← 활성화 상태
# SELinux에서 허용된 http 포트 확인
semanage port -l | grep http_port
# http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8080, 8443
# 8080이 없다면 추가
semanage port -a -t http_port_t -p tcp 8080
# [점검 3] 상위 네트워크 방화벽 확인
# 클라우드라면 Security Group/NACL 확인
# 온프레미스라면 네트워크팀에 상위 방화벽 규칙 요청
# [점검 4] 애플리케이션 바인딩 주소 확인
ss -tulnp | grep 8080
# 127.0.0.1:8080 → 루프백 바인딩 → 외부 접속 불가
# [점검 5] 실제 패킷이 오고 있는지 tcpdump로 확인
tcpdump -i eth0 port 8080 -n
# 패킷이 도달하는지 확인
5. 장애 사례 분석
증상
배포 후 테스트에서는 잘 됐는데,
다음 날 서버 재부팅(정기 패치) 후 갑자기 서비스 전면 장애 발생
원인 확인
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# 현재 포트 확인
firewall-cmd --list-ports
# 22/tcp ← 8080이 없음!
# 영구 설정 확인
firewall-cmd --permanent --list-ports
# 22/tcp ← 여기도 없음 → --permanent 없이 추가했던 것
# 언제 추가했는지 로그 확인
journalctl -u firewalld --since "2024-01-01" | grep 8080
즉각 조치 (서비스 복구)
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# 즉시 포트 열기 (서비스 복구 우선)
firewall-cmd --zone=public --add-port=8080/tcp
# 서비스 접속 확인 후 영구 적용
firewall-cmd --zone=public --add-port=8080/tcp --permanent
firewall-cmd --reload
# 최종 확인
firewall-cmd --permanent --list-ports
# 22/tcp 8080/tcp ← 이제 영구 저장됨
재발 방지
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# 방화벽 변경 작업 후 반드시 실행하는 검증 스크립트
verify_firewall() {
local port=$1
echo "런타임 설정:"
firewall-cmd --list-ports | grep -o "${port}/tcp" && echo "OK" || echo "MISSING"
echo "영구 설정:"
firewall-cmd --permanent --list-ports | grep -o "${port}/tcp" && echo "OK" || echo "MISSING"
}
verify_firewall 8080
교훈: 방화벽 포트 추가 후 항상 --permanent --list-ports로
영구 설정까지 저장됐는지 확인하는 습관을 들이세요.
증상
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
ufw enable
# Firewall is active and enabled on system startup
# (갑자기 SSH 세션 연결 끊김)
원인 분석
ufw enable 실행 시 기본 정책이 DENY(모든 인바운드 차단) 이기 때문에,
먼저 SSH 포트를 허용하지 않은 상태에서 ufw enable을 실행하면
현재 SSH 세션을 포함한 모든 인바운드가 차단됩니다.
ufw 기본 정책:
INPUT: DENY ← SSH 포트 미허용 상태로 활성화 → 세션 차단!
OUTPUT: ALLOW
FORWARD: DENY
복구 방법 (콘솔/VNC 접근 필요)
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# 물리 콘솔 또는 클라우드 콘솔(AWS EC2 Session Manager 등)로 접속 후
# ufw 즉시 비활성화
ufw disable
# 올바른 순서로 재설정
ufw allow 22/tcp # SSH 먼저 허용
ufw allow 80/tcp # HTTP
ufw allow 443/tcp # HTTPS
ufw enable # 그 다음 활성화
# 확인
ufw status verbose
예방 방법
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# ufw enable 전 체크리스트:
echo "1. SSH 포트 허용 여부 확인:"
ufw show added | grep "22\|ssh"
# 확인 후 없으면 추가
ufw allow ssh
ufw status numbered # 규칙 확인
ufw enable # 최종 활성화
교훈: ufw는 enable 전에 반드시 SSH 포트를 허용해야 합니다. 원격 서버에서 작업할 때 이 순서를 지키지 않으면 접속이 끊깁니다.
심화 — 호스트 방화벽을 우회하는 트래픽
심화: firewalld/ufw의 사각지대 — FORWARD 경로와 Docker
firewall-cmd --list-ports에 22만 있는데도 컨테이너 포트가 외부에 뚫려 있다면, 방화벽이 고장 난 게 아니라 그 트래픽이 방화벽이 검사하는 경로로 오지 않은 것입니다. firewalld·ufw가 실제로 무엇을 보는지 알아야 이 사각지대를 이해할 수 있습니다.
- firewalld/ufw는 주로 INPUT 체인을 다룹니다: 이 도구들이 '포트를 연다/막는다'고 할 때 대상은 대개 호스트 자신에게 들어오는 트래픽(netfilter의 INPUT 체인)입니다. 반면 호스트를 거쳐 다른 목적지로 전달되는 트래픽은 FORWARD 체인을 타며, 여기에는 INPUT 규칙이 적용되지 않습니다.
- Docker는 iptables를 직접 건드립니다: 컨테이너를
-p 8080:80으로 띄우면 Docker가 nat 테이블 PREROUTING에 DNAT 규칙을, filter 테이블 FORWARD(DOCKER 체인)에 허용 규칙을 스스로 삽입합니다. published 포트로 온 패킷은 DNAT되어 FORWARD로 컨테이너에 전달되므로 firewalld/ufw의 포트 목록과 무관하게 열립니다. 'ufw가 Docker를 못 막는다'는 유명한 함정이 바로 이것입니다. - 백엔드가 섞이면 추론이 어렵습니다: RHEL 8+에서 firewalld 백엔드는 nftables지만 Docker는 iptables(-nft) 규칙을 넣습니다. 같은 커널 위에 두 규칙 집합이 공존하면 어느 규칙이 먼저 평가되는지 눈으로 따라가기 어렵습니다.
- conntrack 때문에 '지금 막아도' 기존 연결은 살아 있습니다: netfilter는 상태 추적(conntrack)을 하므로 이미 ESTABLISHED된 연결은 새로 넣은 차단 규칙과 무관하게 유지될 수 있습니다. 규칙을 바꾼 뒤 기존 세션이 안 끊긴다고 '규칙이 안 먹었다'고 오해하기 쉽습니다 — 새 연결부터 정책이 적용됩니다.
그래서 'firewall-cmd --list-ports에 없으니 닫혀 있다'는 컨테이너·포워딩 앞에서는 거짓일 수 있습니다. 컨테이너 포트를 실제로 통제하려면 DOCKER-USER 체인에 규칙을 넣거나, published 포트를 127.0.0.1:8080:80처럼 루프백에만 바인딩해야 합니다.
상황: 보안 점검에서 firewall-cmd --list-ports 결과가 22/tcp뿐이라 '8080은 닫혀 있다'고 보고했는데, 외부에서 http://서버IP:8080 접속이 멀쩡히 됩니다. ufw를 쓰는 다른 서버도 ufw status에는 8080이 없는데 뚫려 있습니다.
원인: -p 8080:80은 Docker가 직접 iptables의 nat PREROUTING(DNAT)과 filter FORWARD(DOCKER 체인)에 규칙을 삽입한 것입니다. 이 트래픽은 호스트의 INPUT 체인을 타지 않고 FORWARD로 컨테이너에 전달되므로, INPUT을 검사하는 firewalld/ufw의 포트 목록과 무관하게 열립니다. 방화벽이 뚫린 게 아니라, 방화벽이 보는 경로 밖으로 트래픽이 흐른 것입니다.
진단: iptables -t nat -L DOCKER -n으로 DNAT 규칙을, iptables -L FORWARD -n과 iptables -L DOCKER-USER -n으로 포워딩 허용 규칙을 확인합니다. ss -tlnp | grep 8080에는 docker-proxy가 0.0.0.0:8080으로 리스닝합니다. firewalld 포트 목록은 비어 있는데 실제 접속은 열려 있다면 컨테이너 우회를 의심합니다.
해결: 외부 노출이 필요 없으면 published 포트를 -p 127.0.0.1:8080:80처럼 루프백에만 바인딩합니다. 외부 노출은 필요하되 출발지를 제한하려면 firewalld/ufw의 INPUT 규칙이 아니라 DOCKER-USER 체인에 규칙을 넣어야 합니다(이 체인은 Docker 자신의 허용 규칙보다 먼저 평가됨). ufw라면 /etc/ufw/after.rules에 DOCKER-USER 필터를 추가하는 방식이 표준입니다. '호스트 방화벽에 안 보이니 안전하다'는 가정을 컨테이너 앞에서 버리는 것이 핵심입니다.
6. 실무 현장 관점
신규 서비스 배포 시 방화벽 작업 체크리스트
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
#!/bin/bash
# 신규 서비스 방화벽 설정 표준 절차
SERVICE_PORT=$1
SERVICE_NAME=$2
OS=$(grep -oP '(?<=^ID=).+' /etc/os-release | tr -d '"')
echo "=== 방화벽 설정: ${SERVICE_NAME}:${SERVICE_PORT} ==="
if [[ "$OS" == "centos" || "$OS" == "rhel" || "$OS" == "rocky" ]]; then
# CentOS/RHEL/Rocky
firewall-cmd --zone=public --add-port=${SERVICE_PORT}/tcp --permanent
firewall-cmd --reload
echo "[확인] $(firewall-cmd --permanent --list-ports | grep ${SERVICE_PORT})"
elif [[ "$OS" == "ubuntu" || "$OS" == "debian" ]]; then
# Ubuntu/Debian
ufw allow ${SERVICE_PORT}/tcp
echo "[확인]"
ufw status | grep ${SERVICE_PORT}
fi
# 서비스 리스닝 확인
echo "[프로세스 확인]"
ss -tulnp | grep ${SERVICE_PORT}
사용 예시
bash firewall-setup.sh 8080 "MyApp"
bash firewall-setup.sh 3306 "MySQL"
실무 환경별 고려사항
-
클라우드 환경 (AWS/GCP/Azure)
- OS 방화벽 외에 Security Group / 방화벽 규칙도 함께 설정 필요
- OS 방화벽을 비활성화하고 Security Group만 사용하는 팀도 있음
- 그러나 심층 방어를 위해 OS 방화벽도 유지하는 것을 권장
-
Kubernetes 환경
- NodePort 서비스라면 노드의 OS 방화벽에서 해당 포트 허용 필요
- CNI 플러그인(Calico 등)이 iptables 규칙을 자동 생성하므로 충돌 주의
-
방화벽 변경 이력 관리
- 어떤 포트를, 왜, 언제 열었는지 변경 이력을 관리해야 함
- 불필요한 포트가 누적되지 않도록 주기적으로 감사(Audit)
인프라 담당자 vs 개발자 역할 분리
개발자: "8080 포트를 열어주세요" → 티켓 요청
인프라: 목적, 출발지 IP, 기간 확인 후 허용
→ 변경 관리 시스템에 기록
→ 불필요해지면 제거
7. 핵심 명령어 요약
CentOS — firewalld
| 목적 | 명령어 |
|---|---|
| 포트 추가 (영구) | firewall-cmd --zone=public --add-port=8080/tcp --permanent && firewall-cmd --reload |
| 포트 제거 (영구) | firewall-cmd --zone=public --remove-port=8080/tcp --permanent && firewall-cmd --reload |
| 포트 목록 확인 | firewall-cmd --list-ports |
| 영구 설정 확인 | firewall-cmd --permanent --list-ports |
| 전체 규칙 확인 | firewall-cmd --list-all |
Ubuntu — ufw
| 목적 | 명령어 |
|---|---|
| 포트 허용 | ufw allow 8080/tcp |
| 특정 IP에서만 허용 | ufw allow from 192.168.1.100 to any port 3306 |
| 포트 거부 | ufw deny 8080/tcp |
| 상태 확인 | ufw status verbose |
| 번호로 규칙 삭제 | ufw delete 규칙번호 |
정리
- OS 방화벽은 네트워크 방화벽과 독립적으로 동작하는 별도 레이어
- CentOS:
firewall-cmd --add-port=포트/tcp --permanent && firewall-cmd --reload - Ubuntu:
ufw allow 포트/tcp(enable 전 SSH 허용 필수) --permanent누락 시 재부팅 후 규칙이 사라지는 실수 주의- 포트 열어도 안 되면: 프로세스 리스닝 여부 → SELinux → 상위 방화벽 순서로 점검
- 방화벽 설정 후
--permanent --list-ports로 영구 저장 여부 반드시 확인
관련 모듈로 더 깊이:
- 운영 서버 접속 장애 진단: iptables INPUT 체인 완전 분석 — firewalld/ufw가 내부적으로 다루는 iptables 체인을 직접 읽는 법
- telnet과 nc(netcat) 명령어로 L4 포트 통신 상태 점검 — 포트를 연 뒤 실제로 열렸는지 외부에서 확인하는 법
- 방화벽 정책 설계와 접근 제어 리스트(ACL) 구성 실무 — OS 방화벽 위에 있는 네트워크 ACL 정책 레이어와의 관계
다음 모듈에서는 iptables 규칙 체인 구조와 ACCEPT/DROP/REJECT 동작을 직접 작성하고 적용하는 방법을 다룹니다.