본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 10. · 11 Views
방화벽 정책 IaC 완벽 가이드
방화벽 정책을 코드로 관리하는 Infrastructure as Code 방법론을 배웁니다. iptables와 nftables의 차이부터 Ansible을 활용한 자동 배포, Git 기반 변경 이력 관리, 그리고 안전한 롤백 전략까지 실무에서 바로 적용할 수 있는 내용을 다룹니다.
목차
- iptables vs nftables 비교와 선택
- 방화벽 규칙 설계 원칙
- Ansible firewall role 작성
- rule-comment로 변경 이력 기록
- Git push → 자동 배포 파이프라인
- 방화벽 정책 롤백 전략
1. iptables vs nftables 비교와 선택
3년 차 인프라 엔지니어 김서버 씨는 회사의 보안 정책을 강화하라는 미션을 받았습니다. "방화벽 규칙을 체계적으로 관리해야 하는데, iptables를 계속 써야 할까요?
아니면 nftables로 전환해야 할까요?" 선배 박인프라 씨에게 물었습니다.
iptables는 리눅스의 전통적인 방화벽 관리 도구이고, nftables는 그 후속 버전입니다. nftables는 더 단순한 문법과 나은 성능을 제공하며, 하나의 도구로 IPv4와 IPv6를 모두 관리할 수 있습니다.
현대적인 인프라에서는 nftables로의 전환이 권장됩니다.
다음 코드를 살펴봅시다.
# iptables 방식 (구식)
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -j DROP
# nftables 방식 (현대적)
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
tcp dport { 22, 80 } accept
}
}
김서버 씨는 월요일 아침, 회의실에서 보안팀장님의 지시를 받았습니다. "우리 서버들의 방화벽 정책이 제각각이에요.
이번 분기에 표준화해 주세요." 30대가 넘는 서버의 방화벽 규칙을 일일이 확인하는 것만으로도 며칠이 걸릴 것 같았습니다. 점심시간에 선배 박인프라 씨가 다가왔습니다.
"서버야, 고민이 많아 보이네. 혹시 방화벽 정책 표준화 건?" 김서버 씨는 고개를 끄덕이며 물었습니다.
"네, 그런데 iptables를 계속 써야 할지, nftables로 바꿔야 할지 모르겠어요." iptables의 시대 iptables는 2001년부터 리눅스의 표준 방화벽 도구였습니다. 마치 오래된 스위스 아미 나이프처럼, 할 수 있는 일은 많지만 사용법이 복잡했습니다.
여러 개의 명령어 도구가 필요했습니다. IPv4에는 iptables, IPv6에는 ip6tables, ARP에는 arptables, 브리지에는 ebtables를 각각 따로 써야 했습니다.
규칙을 추가할 때마다 명령어를 하나씩 실행해야 했습니다. 100개의 규칙이 있다면?
100번의 명령어를 실행해야 했습니다. 그리고 규칙의 순서가 매우 중요했습니다.
잘못된 위치에 규칙을 추가하면 전체 정책이 엉망이 되기도 했습니다. nftables의 등장 2014년, 리눅스 커널 3.13 버전에 nftables가 도입되었습니다.
이것은 iptables의 모든 단점을 개선한 차세대 방화벽 도구였습니다. 가장 큰 차이는 문법입니다.
iptables는 각 규칙을 별도의 명령어로 실행해야 했지만, nftables는 테이블 형식으로 규칙을 한 번에 정의할 수 있습니다. 마치 설정 파일을 작성하듯이 말이죠.
성능도 크게 향상되었습니다. iptables는 규칙이 많아질수록 선형적으로 느려졌습니다.
하지만 nftables는 내부적으로 해시 테이블과 트라이 구조를 사용해서 수천 개의 규칙도 빠르게 처리합니다. 실무에서의 선택 박인프라 씨가 말했습니다.
"요즘은 대부분 nftables로 넘어가는 추세야. 특히 우리처럼 클라우드 환경에서는 더더욱 그렇지." 실제로 Debian 10, Ubuntu 20.04 이후 버전부터는 nftables가 기본값입니다.
Red Hat Enterprise Linux 8도 마찬가지입니다. iptables 명령어를 실행해도 내부적으로는 nftables를 사용하는 호환 모드로 동작합니다.
김서버 씨는 위의 코드를 비교해 보았습니다. iptables는 세 줄의 명령어가 필요했지만, nftables는 하나의 테이블 정의로 끝났습니다.
그것도 더 읽기 쉬운 형태로 말이죠. 마이그레이션 고려사항 "그런데 기존 iptables 규칙은 어떻게 하죠?" 김서버 씨가 물었습니다.
"걱정 마. iptables-translate라는 도구가 있어.
기존 규칙을 자동으로 변환해 줘." 박인프라 씨가 답했습니다. 실제로 기존 인프라를 한 번에 바꾸는 것은 위험합니다.
먼저 개발 환경에서 충분히 테스트하고, 스테이징 환경을 거쳐, 마지막으로 프로덕션에 적용하는 단계적 접근이 필요합니다. 결론 김서버 씨는 결심했습니다.
새로운 서버는 nftables로 구축하고, 기존 서버는 점진적으로 마이그레이션하기로 했습니다. 더 나은 도구를 선택하는 것, 그것이 인프라 엔지니어의 중요한 판단이었습니다.
실전 팁
💡 - Debian/Ubuntu에서는 apt install nftables로 바로 사용 가능합니다
- 기존 iptables 규칙은
iptables-save | iptables-restore-translate로 변환할 수 있습니다 - nftables 설정 파일은
/etc/nftables.conf에 저장됩니다
2. 방화벽 규칙 설계 원칙
김서버 씨는 첫 방화벽 규칙을 작성하고 선배에게 검토를 요청했습니다. 박인프라 씨가 코드를 보더니 고개를 저었습니다.
"이렇게 하면 보안 사고가 날 수 있어요. 방화벽 규칙에는 반드시 지켜야 할 원칙들이 있거든요."
방화벽 규칙은 화이트리스트 방식으로 설계해야 하며, 최소 권한 원칙을 따라야 합니다. 기본 정책은 모두 거부하고, 필요한 것만 명시적으로 허용하는 방식입니다.
규칙의 순서도 중요하며, 구체적인 규칙이 일반적인 규칙보다 앞에 와야 합니다.
다음 코드를 살펴봅시다.
table inet filter {
# 기본 정책: 모두 차단 (Deny by Default)
chain input {
type filter hook input priority 0; policy drop;
# 1. 루프백 인터페이스 허용 (필수)
iif lo accept
# 2. 기존 연결 및 관련 트래픽 허용
ct state established,related accept
# 3. 특정 IP에서만 SSH 허용 (구체적 규칙)
ip saddr 203.0.113.0/24 tcp dport 22 accept
# 4. 웹 서비스 허용 (일반적 규칙)
tcp dport { 80, 443 } accept
# 5. ICMP 핑 허용 (제한적)
icmp type echo-request limit rate 5/second accept
}
}
김서버 씨가 작성한 첫 번째 방화벽 규칙은 이랬습니다. 일단 모든 포트를 열어두고, 위험한 포트만 막는 방식이었습니다.
언뜻 생각하면 합리적으로 보였습니다. "필요한 건 다 쓸 수 있고, 위험한 것만 막으면 되잖아요?" 박인프라 씨는 고개를 저었습니다.
"그건 블랙리스트 방식이야. 보안에서 가장 위험한 접근법이지." 화이트리스트 vs 블랙리스트 보안의 기본 철학은 명확합니다.
마치 야간 경비가 신분증을 확인하듯이, 허가된 사람만 들여보내야 합니다. 블랙리스트 방식은 "이 사람들만 빼고 다 들어와"라고 하는 것과 같습니다.
문제가 뭘까요? 새로운 위협은 매일 생겨납니다.
어제까지 몰랐던 취약점이 오늘 발견됩니다. 블랙리스트는 이미 알려진 위협만 막을 수 있습니다.
하지만 화이트리스트는 다릅니다. 명시적으로 허용한 것만 통과시키니까, 알려지지 않은 위협도 자동으로 차단됩니다.
최소 권한 원칙 "그래서 우리는 최소 권한 원칙을 따라야 해." 박인프라 씨가 설명을 이어갔습니다. 이 원칙은 간단합니다.
꼭 필요한 것만 허용하는 것입니다. 웹 서버라면 80번과 443번 포트만 열면 됩니다.
SSH는? 관리자 IP에서만 접속할 수 있게 제한합니다.
위의 코드를 보면 이 원칙이 명확히 드러납니다. 첫 번째 줄의 policy drop이 핵심입니다.
기본적으로 모든 것을 차단합니다. 그리고 아래로 내려가면서 필요한 것들을 하나씩 허용합니다.
규칙의 순서가 중요한 이유 방화벽은 위에서 아래로 규칙을 검사합니다. 마치 체크리스트를 따라 내려가듯이 말이죠.
일치하는 첫 번째 규칙이 적용되고, 나머지는 무시됩니다. 그래서 순서가 매우 중요합니다.
예를 들어 "모든 IP에서 SSH 허용"이라는 규칙이 "특정 IP에서만 SSH 허용"보다 위에 있다면? 특정 IP 규칙은 절대 실행되지 않습니다.
필수 규칙들 코드의 첫 번째 규칙 iif lo accept는 루프백 인터페이스를 허용합니다. 이게 왜 필요할까요?
서버의 많은 프로세스들이 자기 자신과 통신합니다. 데이터베이스에 연결하고, 로컬 캐시를 확인하고, 내부 API를 호출합니다.
루프백을 막으면 서버가 제대로 작동하지 않습니다. 두 번째 규칙 ct state established,related accept는 이미 수립된 연결을 허용합니다.
외부로 나가는 요청에 대한 응답을 받을 수 있게 해줍니다. 이것도 필수입니다.
실전 시나리오 회사의 웹 서버를 생각해 봅시다. 어떤 트래픽이 필요할까요?
고객들은 80번과 443번 포트로 접속합니다. 관리자는 SSH로 서버에 접속해야 합니다.
하지만 SSH는 전 세계에 열려있으면 안 됩니다. 회사 사무실 IP와 VPN IP에서만 허용합니다.
ICMP 핑은 어떻게 할까요? 완전히 막으면 네트워크 진단이 어렵습니다.
하지만 무제한으로 허용하면 핑 플러드 공격에 취약합니다. 그래서 limit rate 5/second로 초당 5개로 제한합니다.
흔한 실수 초보 엔지니어들이 자주 하는 실수가 있습니다. 일시적으로 테스트하려고 방화벽을 완전히 끄는 것입니다.
"잠깐만 테스트하고 다시 켤게요." 하지만 까먹고 그대로 둡니다. 그리고 보안 사고가 발생합니다.
또 다른 실수는 너무 느슨한 규칙입니다. "일단 되게 하고 나중에 조이자"는 생각.
하지만 그 "나중"은 절대 오지 않습니다. 처음부터 엄격하게 시작하는 것이 정답입니다.
검증 방법 규칙을 적용한 후에는 반드시 테스트해야 합니다. 허용되어야 할 트래픽이 실제로 통과하는지, 차단되어야 할 트래픽이 제대로 막히는지 확인합니다.
nft list ruleset 명령어로 현재 적용된 규칙을 확인할 수 있습니다. tcpdump나 nft monitor로 실시간 트래픽을 모니터링할 수도 있습니다.
정리 김서버 씨는 규칙을 다시 작성했습니다. 이번에는 기본 정책을 drop으로 설정하고, 필요한 것만 하나씩 허용했습니다.
박인프라 씨가 만족스럽게 고개를 끄덕였습니다. "이제 제대로 된 방화벽이네요." 보안은 편의성과의 싸움입니다.
하지만 원칙을 지키면 둘 다 얻을 수 있습니다.
실전 팁
💡 - 방화벽 규칙을 변경하기 전에 항상 백업을 만들어 두세요
- 원격 서버의 방화벽을 수정할 때는
at명령으로 자동 롤백을 예약하세요 (예:at now + 5 minutes후 원복 스크립트) - 새 규칙 적용 후 반드시 별도 SSH 세션을 유지한 상태에서 테스트하세요
3. Ansible firewall role 작성
김서버 씨는 30대의 서버에 같은 방화벽 규칙을 적용해야 했습니다. 서버마다 일일이 접속해서 설정할 생각을 하니 막막했습니다.
"한 달은 걸리겠는데요?" 박인프라 씨가 웃으며 말했습니다. "Ansible을 쓰면 10분이면 돼요."
Ansible은 서버 설정을 자동화하는 도구입니다. 방화벽 규칙을 코드로 작성하면, 수십 대의 서버에 동시에 적용할 수 있습니다.
Role 구조를 사용하면 재사용 가능한 모듈로 관리할 수 있으며, 변수를 활용해 서버 유형별로 다른 정책을 적용할 수 있습니다.
다음 코드를 살펴봅시다.
# roles/firewall/tasks/main.yml
---
- name: nftables 패키지 설치
apt:
name: nftables
state: present
- name: 방화벽 규칙 템플릿 배포
template:
src: nftables.conf.j2
dest: /etc/nftables.conf
owner: root
group: root
mode: '0644'
notify: restart nftables
- name: nftables 서비스 활성화
systemd:
name: nftables
enabled: yes
state: started
# roles/firewall/templates/nftables.conf.j2
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
iif lo accept
ct state established,related accept
{% for port in allowed_tcp_ports %}
tcp dport {{ port }} accept
{% endfor %}
{% if allow_ssh_from %}
ip saddr { {{ allow_ssh_from | join(', ') }} } tcp dport 22 accept
{% endif %}
}
}
월요일 아침, 김서버 씨는 엑셀 파일을 펼쳐 놓고 서버 목록을 확인했습니다. 웹 서버 15대, API 서버 10대, 데이터베이스 서버 5대.
총 30대의 서버에 새로운 방화벽 정책을 적용해야 했습니다. "하나씩 접속해서 설정하면 하루에 5대 정도 가능할 것 같은데..." 계산기를 두드려 봤습니다.
일주일은 족히 걸릴 것 같았습니다. 게다가 사람이 하는 일이라 실수할 가능성도 높았습니다.
수작업의 한계 과거에는 이런 작업을 셸 스크립트로 처리했습니다. for 루프를 돌면서 각 서버에 ssh로 접속하고, 명령어를 실행하는 방식이었죠.
하지만 문제가 많았습니다. 중간에 한 대라도 실패하면?
어디서부터 다시 시작해야 할까요? 이미 적용된 서버는 어떻게 건너뛸까요?
네트워크가 불안정하면 어떻게 될까요? 하나하나가 골칫거리였습니다.
Ansible의 등장 박인프라 씨가 Ansible을 소개했습니다. "이건 멱등성이 보장돼.
같은 작업을 여러 번 실행해도 결과가 같아." 멱등성이라는 어려운 말이 나왔지만, 개념은 간단했습니다. 마치 전등 스위치를 여러 번 눌러도 결국 켜진 상태가 되는 것처럼, Ansible도 원하는 상태를 정의하면 현재 상태에 관계없이 그 상태로 만들어 줍니다.
Role 구조의 이해 Ansible의 Role은 관련된 작업들을 하나로 묶은 것입니다. 마치 요리 레시피처럼, 재료(변수), 조리 과정(tasks), 도구(templates)를 모두 포함합니다.
위의 코드를 보면 구조가 명확합니다. tasks/main.yml에는 해야 할 일들이 순서대로 나열되어 있습니다.
첫째, nftables 설치. 둘째, 설정 파일 배포.
셋째, 서비스 시작. 템플릿의 강력함 templates/nftables.conf.j2 파일이 핵심입니다.
.j2는 Jinja2 템플릿 엔진을 의미합니다. 이것을 사용하면 변수를 활용한 동적인 설정 파일을 만들 수 있습니다.
예를 들어 웹 서버는 80번과 443번 포트가 필요하지만, API 서버는 8080번이 필요할 수 있습니다. 템플릿의 {% for port in allowed_tcp_ports %} 부분이 이를 처리합니다.
변수 정의 서버 그룹별로 다른 변수를 정의할 수 있습니다. group_vars/webservers.yml 파일을 만들어 봅시다.
yaml allowed_tcp_ports: - 80 - 443 allow_ssh_from: - 203.0.113.0/24 - 198.51.100.0/24 API 서버는 다른 설정을 가질 수 있습니다. group_vars/apiservers.yml에서 8080번 포트를 추가하면 됩니다.
실행 과정 김서버 씨는 playbook을 작성했습니다. yaml # site.yml - hosts: all become: yes roles: - firewall 그리고 명령어 하나로 실행했습니다.
bash ansible-playbook -i inventory site.yml 화면에 각 서버의 작업 진행 상태가 실시간으로 표시되었습니다. 초록색은 성공, 노란색은 변경됨, 빨간색은 실패.
30대의 서버 설정이 불과 5분 만에 완료되었습니다. 핸들러의 역할 코드에서 notify: restart nftables 부분을 주목해 봅시다.
이것은 핸들러를 호출합니다. 설정 파일이 변경되었을 때만 서비스를 재시작합니다.
만약 설정이 이미 최신 상태라면? 재시작하지 않습니다.
불필요한 서비스 중단을 방지합니다. 이것이 바로 멱등성의 예시입니다.
테스트 전략 처음부터 30대에 적용하는 건 위험합니다. 김서버 씨는 단계적 접근을 했습니다.
먼저 개발 서버 1대에서 테스트했습니다. 문제없이 작동하는 것을 확인했습니다.
다음은 스테이징 환경 3대. 마지막으로 프로덕션 환경에 롤아웃했습니다.
Ansible의 --limit 옵션을 사용하면 특정 서버만 선택할 수 있습니다. bash ansible-playbook -i inventory site.yml --limit webserver01 버전 관리 Role을 Git 저장소에 저장하면 변경 이력이 자동으로 관리됩니다.
누가, 언제, 무엇을, 왜 변경했는지 모두 기록됩니다. 문제가 생기면 이전 버전으로 되돌릴 수 있습니다.
정리 김서버 씨는 놀라웠습니다. 일주일이 걸릴 줄 알았던 작업이 오전 중에 끝났습니다.
게다가 다음에 새로운 서버가 추가되면? 같은 명령어 한 줄이면 됩니다.
Infrastructure as Code의 진정한 가치를 경험한 순간이었습니다.
실전 팁
💡 - Ansible Galaxy에서 검증된 방화벽 role을 찾아볼 수 있습니다 (ansible-galaxy install)
--check옵션으로 실제 적용 전 드라이런을 수행하세요--diff옵션으로 정확히 무엇이 변경될지 미리 확인할 수 있습니다
4. rule-comment로 변경 이력 기록
3개월 후, 김서버 씨는 이상한 방화벽 규칙 하나를 발견했습니다. "왜 이 IP 대역을 허용했지?
누가 추가한 거지?" 하지만 아무도 기억하지 못했습니다. 박인프라 씨가 한숨을 쉬며 말했습니다.
"그래서 모든 규칙에 주석을 달아야 한다니까요."
방화벽 규칙에 comment를 추가하면 변경 이유와 작성자, 날짜를 기록할 수 있습니다. nftables는 각 규칙마다 주석을 달 수 있으며, 이를 통해 나중에 규칙의 목적을 파악할 수 있습니다.
티켓 번호나 요청자 정보를 함께 기록하면 추적이 더욱 쉬워집니다.
다음 코드를 살펴봅시다.
# roles/firewall/templates/nftables.conf.j2
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# 기본 규칙
iif lo accept comment "Loopback required for local services"
ct state established,related accept comment "Allow return traffic"
# SSH 접근 제어
{% for rule in ssh_rules %}
ip saddr {{ rule.ip }} tcp dport 22 accept comment "{{ rule.comment }} | Added: {{ rule.date }} | Ticket: {{ rule.ticket }}"
{% endfor %}
# 웹 서비스
tcp dport 80 accept comment "HTTP | Added: 2025-01-15 | Requested by: ops-team"
tcp dport 443 accept comment "HTTPS | Added: 2025-01-15 | Requested by: ops-team"
}
}
# group_vars/webservers.yml
ssh_rules:
- ip: "203.0.113.0/24"
comment: "Office network SSH access"
date: "2025-01-20"
ticket: "SEC-1234"
- ip: "198.51.100.50"
comment: "Emergency access for on-call engineer"
date: "2025-02-10"
ticket: "OPS-5678"
어느 날 보안팀에서 연락이 왔습니다. "198.51.100.50에서 SSH 접속이 왜 허용되어 있나요?" 김서버 씨는 방화벽 규칙을 확인했습니다.
분명히 있는 규칙이었지만, 누가, 왜 추가했는지 알 수 없었습니다. Git 커밋 로그를 뒤져봤습니다.
6개월 전에 추가되었고, 커밋 메시지는 "방화벽 규칙 업데이트"였습니다. 전혀 도움이 되지 않았습니다.
당시 작업한 동료에게 물어봤지만, 그도 기억하지 못했습니다. 문서화의 중요성 박인프라 씨가 설명했습니다.
"코드만으로는 부족해. 왜 그렇게 했는지가 중요하거든." 방화벽 규칙 하나하나는 비즈니스 요구사항을 반영합니다.
새로운 파트너사와 계약했다면 그들의 IP를 허용해야 합니다. 긴급 장애 대응을 위해 임시로 포트를 열 수도 있습니다.
하지만 시간이 지나면 맥락이 사라집니다. nftables의 comment 기능 nftables는 각 규칙에 주석을 달 수 있습니다.
comment "설명" 형식으로 추가하면 됩니다. 이 주석은 규칙의 일부로 저장되어 nft list ruleset 명령으로 확인할 수 있습니다.
위의 코드를 보면 체계적인 주석 형식을 볼 수 있습니다. 파이프 기호로 구분된 세 가지 정보: 설명, 추가 날짜, 티켓 번호.
이렇게 표준화하면 나중에 파싱하기도 쉽습니다. 변수를 활용한 관리 group_vars/webservers.yml에 규칙 정보를 구조화된 형태로 저장했습니다.
각 규칙은 IP 주소, 설명, 날짜, 티켓 번호를 포함합니다. 새로운 규칙을 추가할 때는 이 파일만 수정하면 됩니다.
템플릿이 자동으로 적절한 형식의 주석을 생성해 줍니다. 실수로 주석을 빼먹을 일이 없습니다.
티켓 시스템 연동 많은 회사가 Jira나 ServiceNow 같은 티켓 시스템을 사용합니다. 모든 인프라 변경은 티켓을 통해 승인받습니다.
티켓 번호를 주석에 포함하면 전체 맥락을 추적할 수 있습니다. "SEC-1234가 뭐였지?" 티켓 시스템에서 검색하면 승인 과정, 요청자, 비즈니스 정당성을 모두 확인할 수 있습니다.
감사 대응이나 컴플라이언스 검토 시 매우 유용합니다. 임시 규칙 관리 긴급 상황에서는 임시로 규칙을 추가하는 경우가 있습니다.
"일주일 후에 제거해야 하는데..." 하고 생각하지만, 바쁜 일상에 묻혀 잊어버립니다. 주석에 만료 날짜를 추가하는 것도 좋은 방법입니다.
yaml - ip: "192.0.2.100" comment: "Temporary access for vendor | EXPIRES: 2025-03-01" date: "2025-02-15" ticket: "TEMP-9999" 정기적으로 만료된 규칙을 찾아 제거하는 스크립트를 만들 수 있습니다. 실전 시나리오 3개월 후, 보안 감사가 시작되었습니다.
감사관이 물었습니다. "왜 이 IP에서 SSH 접속이 가능한가요?" 김서버 씨는 침착하게 규칙을 확인했습니다.
주석에는 이렇게 적혀 있었습니다. "Office network SSH access | Added: 2025-01-20 | Ticket: SEC-1234" 티켓을 열어보니 CISO의 승인이 있었습니다.
사무실 IP 대역에서의 SSH 접속은 정책적으로 허용된 것이었습니다. 모든 것이 명확했습니다.
변경 이력 조회 Git 저장소에 모든 것이 기록되어 있으므로, 특정 규칙의 역사를 추적할 수 있습니다. bash git log -p -- group_vars/webservers.yml 누가, 언제, 어떤 규칙을 추가하거나 제거했는지 한눈에 보입니다.
문제가 생긴 시점을 찾아 원인을 파악할 수 있습니다. 자동화된 검증 CI/CD 파이프라인에 검증 단계를 추가할 수 있습니다.
모든 규칙이 주석을 가지고 있는지, 티켓 번호 형식이 올바른지 자동으로 확인합니다. python # validate_firewall_rules.py for rule in ssh_rules: assert 'comment' in rule, "Comment is required" assert 'ticket' in rule, "Ticket number is required" assert rule['ticket'].startswith('SEC-') or rule['ticket'].startswith('OPS-') 정리 이제 김서버 씨는 자신 있게 말할 수 있습니다.
"우리 방화벽 규칙은 모두 문서화되어 있고, 추적 가능합니다." 6개월 후에 다시 봐도, 1년 후에 다른 담당자가 봐도 이해할 수 있습니다. 코드는 거짓말하지 않지만, 맥락은 시간이 지나면 사라집니다.
주석이 그 맥락을 보존합니다.
실전 팁
💡 - 주석 형식을 팀 내에서 표준화하세요 (예: "설명 | 날짜 | 담당자 | 티켓")
- 정기적으로 임시 규칙을 검토하는 캘린더 일정을 만드세요
- 주석이 없는 규칙을 찾는 스크립트를 CI/CD에 추가하세요
5. Git push → 자동 배포 파이프라인
김서버 씨는 매번 수동으로 Ansible을 실행하는 것이 번거로웠습니다. "규칙을 하나 수정할 때마다 노트북을 열고, VPN 연결하고, 명령어를 실행해야 해요." 박인프라 씨가 말했습니다.
"그럴 필요 없어. Git에 push만 하면 자동으로 배포되게 만들어 봐요."
GitOps 방식을 사용하면 Git 저장소가 진실의 유일한 원천이 됩니다. 코드를 push하면 CI/CD 파이프라인이 자동으로 검증하고 배포합니다.
GitHub Actions, GitLab CI, Jenkins 같은 도구를 활용하여 안전하고 일관성 있는 배포를 자동화할 수 있습니다.
다음 코드를 살펴봅시다.
# .github/workflows/deploy-firewall.yml
name: Deploy Firewall Rules
on:
push:
branches: [main]
paths:
- 'roles/firewall/**'
- 'group_vars/**'
pull_request:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Ansible Lint 검증
run: |
pip install ansible-lint
ansible-lint roles/firewall/
- name: 규칙 주석 검증
run: python scripts/validate_comments.py
- name: Dry-run 테스트
run: |
ansible-playbook site.yml --check --diff
env:
ANSIBLE_HOST_KEY_CHECKING: false
deploy-staging:
needs: validate
if: github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: 스테이징 배포
run: |
ansible-playbook site.yml --limit staging
- name: 배포 검증
run: |
ansible all -m shell -a "nft list ruleset" --limit staging
deploy-production:
needs: deploy-staging
if: github.event_name == 'push'
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v3
- name: 프로덕션 배포
run: |
ansible-playbook site.yml --limit production
금요일 오후 5시, 김서버 씨는 긴급 요청을 받았습니다. "새로운 파트너사 IP를 방화벽에 추가해 주세요.
월요일부터 서비스해야 합니다." 주말 내내 이 생각에 마음이 편치 않았습니다. 월요일 아침 일찍 출근해서 변경 작업을 했습니다.
노트북을 켜고, VPN에 연결하고, Ansible 명령어를 실행했습니다. 그런데 VPN이 불안정했습니다.
중간에 연결이 끊기면서 일부 서버에만 적용되었습니다. 다시 실행했지만, 어떤 서버가 업데이트되었는지 확신할 수 없었습니다.
GitOps의 철학 박인프라 씨가 새로운 방식을 제안했습니다. "Git 저장소를 진실의 원천으로 만드세요.
저장소의 코드가 실제 인프라 상태를 정의하는 겁니다." 이 개념은 간단하지만 강력했습니다. 마치 건축 도면이 건물의 청사진인 것처럼, Git 저장소가 인프라의 청사진이 되는 것입니다.
도면이 바뀌면 건물도 자동으로 변경됩니다. CI/CD 파이프라인 설계 위의 코드는 GitHub Actions 워크플로우입니다.
세 단계로 구성되어 있습니다: 검증, 스테이징 배포, 프로덕션 배포. 첫 번째 validate 단계는 코드 품질을 확인합니다.
Ansible Lint로 문법을 검사하고, 커스텀 스크립트로 비즈니스 규칙을 검증합니다. --check 옵션으로 드라이런을 실행해서 실제로 무엇이 바뀔지 미리 확인합니다.
두 번째 deploy-staging 단계는 스테이징 환경에 먼저 배포합니다. 프로덕션에 적용하기 전에 안전성을 검증하는 것입니다.
마치 비행기가 이륙 전에 활주로에서 테스트하는 것과 같습니다. 마지막 deploy-production 단계는 실제 프로덕션 환경에 배포합니다.
environment: production을 지정하면 GitHub에서 수동 승인을 요구하도록 설정할 수 있습니다. 트리거 조건 on.push.paths 설정을 주목해 봅시다.
방화벽 관련 파일이 변경되었을 때만 워크플로우가 실행됩니다. README.md를 수정한다고 해서 방화벽을 재배포할 필요는 없으니까요.
Pull Request가 생성되면 검증만 실행됩니다. 실제 배포는 main 브랜치에 머지된 후에만 일어납니다.
이렇게 하면 코드 리뷰 과정에서 문제를 미리 발견할 수 있습니다. 실제 작업 흐름 이제 김서버 씨의 작업 방식이 바뀌었습니다.
규칙 추가 vim group_vars/webservers.yml # 3. 커밋 및 푸시 git add group_vars/webservers.yml git commit -m "Add partner company IP access (Ticket: OPS-1234)" git push origin add-partner-ip # 4.
Pull Request 생성 (웹 UI에서) # 5. CI 검증 통과 확인 # 6.
동료 코드 리뷰 # 7. main에 머지 # 8.
자동 배포 완료! ``` 노트북을 열고 VPN에 연결할 필요가 없습니다.
스마트폰에서도 GitHub 앱으로 Pull Request를 만들 수 있습니다. 나머지는 파이프라인이 알아서 처리합니다.
**안전 장치** 자동화가 편리하지만, 위험하지 않을까요? 그래서 여러 안전 장치가 있습니다.
먼저 `--check` 모드로 드라이런을 실행합니다. 실제로 변경하지 않고 무엇이 바뀔지만 확인합니다.
문제가 있으면 여기서 걸립니다. 스테이징 환경에 먼저 배포합니다.
여기서 문제가 발견되면 프로덕션 배포는 자동으로 취소됩니다. 프로덕션 배포 전에는 수동 승인을 요구할 수 있습니다.
GitHub의 Environment Protection Rules를 설정하면 특정 사람의 승인 없이는 배포가 진행되지 않습니다. **배포 알림** Slack이나 이메일로 배포 알림을 받을 수 있습니다.
성공했는지, 실패했는지, 어떤 변경이 적용되었는지 실시간으로 확인합니다. ```yaml - name: Slack 알림 uses: slackapi/slack-github-action@v1 with: payload: | { "text": "방화벽 규칙이 프로덕션에 배포되었습니다." } ``` **롤백 전략** 문제가 생기면 어떻게 할까요?
Git의 장점은 모든 변경 이력이 보존된다는 것입니다. ```bash git revert HEAD git push origin main ``` 이전 커밋을 되돌리는 새 커밋을 만들어 push하면, 파이프라인이 자동으로 이전 상태로 배포합니다.
빠르고 안전한 롤백입니다. **감사 추적** 누가, 언제, 무엇을, 왜 변경했는지 모두 Git 로그에 남습니다.
커밋 메시지, Pull Request 토론, 승인자 정보까지 전부 기록됩니다. 컴플라이언스 요구사항을 자동으로 충족합니다.
**정리** 김서버 씨는 이제 금요일 오후에 긴급 요청을 받아도 걱정하지 않습니다. 스마트폰으로 코드를 수정하고 Pull Request를 만듭니다.
집에서 노트북을 열어 리뷰를 확인하고 머지합니다. 파이프라인이 자동으로 검증하고 배포합니다.
주말을 편하게 보낼 수 있게 되었습니다. 자동화가 주는 진정한 선물입니다.
**실전 팁**
💡 - GitHub의 Environment Protection Rules로 프로덕션 배포에 수동 승인을 추가하세요
- Slack이나 Microsoft Teams로 배포 알림을 받도록 설정하세요
- 배포 실패 시 자동으로 롤백하는 로직을 추가할 수 있습니다
---
## 6. 방화벽 정책 롤백 전략
어느 날 새벽 3시, 김서버 씨의 전화기가 울렸습니다. "사이트가 안 돼요!" 방금 배포한 방화벽 규칙에 문제가 있었습니다.
고객들이 접속할 수 없었습니다. "빨리 원래대로 돌려야 하는데..." 당황한 김서버 씨에게 박인프라 씨가 말했습니다.
"침착하게 롤백 절차를 따라 해요."
**롤백**은 문제가 생긴 변경을 이전 상태로 되돌리는 것입니다. Git 기반 배포에서는 커밋을 되돌리면 자동으로 롤백됩니다.
수동 롤백을 위해서는 이전 버전의 설정을 백업해 두거나, **트랜잭션 방식**으로 원자적으로 적용해야 합니다. 롤백 가능한 시간 제한을 두는 것도 중요합니다.
다음 코드를 살펴봅시다.
```python
# scripts/safe-deploy.sh
#!/bin/bash
# 안전한 방화벽 배포 스크립트
# 1. 현재 규칙 백업
echo "Backing up current firewall rules..."
nft list ruleset > /var/backups/nftables/rules-$(date +%Y%m%d-%H%M%S).conf
BACKUP_FILE="/var/backups/nftables/rules-$(date +%Y%m%d-%H%M%S).conf"
# 2. 새 규칙 적용
echo "Applying new firewall rules..."
nft -f /etc/nftables.conf
# 3. 5분 후 자동 롤백 예약
echo "Scheduling automatic rollback in 5 minutes..."
at now + 5 minutes <<EOF
if [ -f /tmp/firewall-confirmed ]; then
echo "Deployment confirmed, rollback cancelled"
rm /tmp/firewall-confirmed
else
echo "No confirmation received, rolling back..."
nft flush ruleset
nft -f $BACKUP_FILE
systemctl restart nftables
echo "Rollback completed at $(date)" | mail -s "Firewall Auto-Rollback" ops@company.com
fi
EOF
echo "New rules applied. You have 5 minutes to confirm."
echo "Run: touch /tmp/firewall-confirmed"
echo "To rollback manually: nft flush ruleset && nft -f $BACKUP_FILE"
# playbooks/rollback.yml
---
- name: 방화벽 규칙 롤백
hosts: "{{ target_hosts }}"
become: yes
vars_prompt:
- name: rollback_version
prompt: "롤백할 커밋 해시 또는 태그를 입력하세요"
private: no
tasks:
- name: Git 저장소에서 이전 버전 체크아웃
git:
repo: "{{ firewall_repo }}"
dest: /tmp/firewall-rollback
version: "{{ rollback_version }}"
delegate_to: localhost
- name: 이전 버전 규칙 적용
template:
src: /tmp/firewall-rollback/roles/firewall/templates/nftables.conf.j2
dest: /etc/nftables.conf
notify: restart nftables
새벽 3시 15분, 김서버 씨는 땀을 흘리며 노트북 앞에 앉았습니다. 모니터링 대시보드는 빨간색으로 가득했습니다.
웹사이트 접속률이 0퍼센트. 고객 문의 전화가 쏟아지고 있었습니다.
20분 전에 배포한 방화벽 규칙에 문제가 있었습니다. 실수로 80번 포트를 막아버렸습니다.
심장이 빠르게 뛰었습니다. "어떻게 하지?" 롤백의 중요성 박인프라 씨의 목소리가 전화기 너머로 들렸습니다.
"당황하지 마. 우리는 롤백 계획이 있어.
Git 커밋 하나만 되돌리면 돼." 모든 변경에는 실수의 가능성이 있습니다. 아무리 철저히 테스트해도 프로덕션 환경에서 예상치 못한 문제가 생길 수 있습니다.
그래서 롤백 전략은 배포만큼이나 중요합니다. 자동 백업 시스템 위의 safe-deploy.sh 스크립트는 영리한 안전 장치입니다.
새 규칙을 적용하기 전에 현재 규칙을 백업합니다. 날짜와 시간이 포함된 파일명으로 저장되어 나중에 쉽게 찾을 수 있습니다.
더 중요한 것은 자동 롤백 타이머입니다. 마치 폭탄 해체 영화에서 본 것처럼, 5분의 카운트다운이 시작됩니다.
이 시간 안에 확인하지 않으면 자동으로 이전 상태로 되돌아갑니다. 이것은 원격 서버에서 특히 중요합니다.
방화벽 규칙 실수로 SSH 접속이 끊기면? 서버에 접근할 방법이 없어집니다.
하지만 자동 롤백이 있다면 5분만 기다리면 됩니다. 확인 프로세스 새 규칙이 제대로 작동하는 것을 확인했다면, 확인 파일을 생성합니다.
bash touch /tmp/firewall-confirmed 이렇게 하면 at 작업이 롤백을 취소합니다. 간단하지만 효과적인 메커니즘입니다.
Git 기반 롤백 김서버 씨는 빠르게 Git 로그를 확인했습니다. bash git log --oneline -5 abc1234 Add new firewall rule (문제의 커밋) def5678 Update SSL certificate ghi9012 Add monitoring alerts 문제의 커밋을 되돌렸습니다.
bash git revert abc1234 git push origin main CI/CD 파이프라인이 자동으로 실행되었습니다. 이전 규칙이 모든 서버에 배포되었습니다.
3분 만에 사이트가 정상화되었습니다. Ansible 롤백 플레이북 rollback.yml 플레이북은 더 세밀한 제어를 제공합니다.
특정 서버 그룹만 롤백하거나, 특정 버전으로 되돌릴 수 있습니다. bash ansible-playbook rollback.yml \ -e "target_hosts=webservers" \ -e "rollback_version=v1.2.3" 대화형 프롬프트가 나타나서 어떤 버전으로 롤백할지 확인합니다.
실수로 잘못된 버전을 선택하는 것을 방지합니다. 버전 태깅 전략 안정적인 버전에는 Git 태그를 붙입니다.
bash git tag -a v1.2.3 -m "Stable firewall rules - 2025-01-20" git push origin v1.2.3 문제가 생기면 마지막으로 안정적이었던 태그로 빠르게 롤백할 수 있습니다. 커밋 해시를 기억할 필요가 없습니다.
단계적 배포로 위험 최소화 한 번에 모든 서버에 배포하지 않습니다. 카나리 배포 방식을 사용합니다.
첫 번째는 카나리 서버 1대. 여기서 30분간 모니터링합니다.
문제가 없으면 10퍼센트의 서버에 배포합니다. 다시 모니터링.
최종적으로 전체에 배포합니다. 문제가 생기면?
카나리 서버 1대만 영향을 받습니다. 99퍼센트의 고객은 정상적으로 서비스를 이용합니다.
모니터링과 알람 롤백이 필요한 상황을 빠르게 감지해야 합니다. Prometheus, Grafana, CloudWatch 같은 모니터링 도구를 활용합니다.
핵심 메트릭을 추적합니다: HTTP 응답률, 응답 시간, 에러율. 배포 직후 이 지표들이 급변하면 자동으로 알람이 발송됩니다.
롤백 훈련 분기에 한 번씩 롤백 훈련을 합니다. 실제 상황이 아닐 때 연습해야 진짜 상황에서 당황하지 않습니다.
스테이징 환경에서 일부러 문제를 만들고, 롤백 절차를 실행합니다. 시간을 재고, 문서를 개선하고, 자동화를 강화합니다.
문서화 롤백 절차를 위키에 명확히 문서화했습니다. 새벽 3시에 반쯤 잠든 상태에서도 따라 할 수 있을 정도로 단순하게 작성합니다.
1단계: Git 커밋 되돌리기 2단계: CI/CD 파이프라인 확인 3단계: 서비스 정상화 확인 4단계: 사후 분석 문서 작성 사후 분석 롤백이 끝났다고 끝이 아닙니다. 왜 문제가 생겼는지 분석합니다.
포스트모템 문서를 작성합니다. 무엇이 잘못되었나?
왜 테스트에서 잡지 못했나? 어떻게 재발을 방지할 수 있나?
비난하지 않고, 시스템을 개선하는 데 집중합니다. 정리 새벽 3시 30분, 사이트는 정상화되었습니다.
김서버 씨는 깊게 숨을 내쉬었습니다. 15분의 긴장된 시간이었지만, 롤백 계획 덕분에 큰 사고를 막았습니다.
다음 날 팀 회의에서 이 사건을 공유했습니다. 테스트 프로세스를 개선했고, 자동 검증 규칙을 추가했습니다.
실수는 학습의 기회였습니다. 완벽한 시스템은 없습니다.
하지만 빠르게 복구할 수 있는 시스템은 만들 수 있습니다.
실전 팁
💡 - 프로덕션 변경 전에는 항상 롤백 계획을 먼저 세우세요
- 자동 롤백 타이머는 SSH 접속이 끊길 수 있는 원격 서버에서 필수입니다
- 안정적인 버전에는 Git 태그를 붙여서 빠른 롤백을 가능하게 하세요
- 롤백 훈련을 정기적으로 수행하여 팀의 대응 능력을 높이세요
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Helm 마이크로서비스 패키징 완벽 가이드
Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.
보안 아키텍처 구성 완벽 가이드
프로젝트의 보안을 처음부터 설계하는 방법을 배웁니다. AWS 환경에서 VPC부터 WAF, 암호화, 접근 제어까지 실무에서 바로 적용할 수 있는 보안 아키텍처를 단계별로 구성해봅니다.
AWS Organizations 완벽 가이드
여러 AWS 계정을 체계적으로 관리하고 통합 결제와 보안 정책을 적용하는 방법을 실무 스토리로 쉽게 배워봅니다. 초보 개발자도 바로 이해할 수 있는 친절한 설명과 실전 예제를 제공합니다.
AWS KMS 암호화 완벽 가이드
AWS KMS(Key Management Service)를 활용한 클라우드 데이터 암호화 방법을 초급 개발자를 위해 쉽게 설명합니다. CMK 생성부터 S3, EBS 암호화, 봉투 암호화까지 실무에 필요한 모든 내용을 담았습니다.
AWS Secrets Manager 완벽 가이드
AWS에서 데이터베이스 비밀번호, API 키 등 민감한 정보를 안전하게 관리하는 Secrets Manager의 핵심 개념과 실무 활용법을 배워봅니다. 초급 개발자도 쉽게 따라할 수 있도록 실전 예제와 함께 설명합니다.