Red Hat Certified Engineer (RHCE) #17 RHCSA 자동화 4: firewall, SELinux, SSH 키
#16 RHCSA 자동화 3: 스토리지(LVM), 파일시스템(NFS)에서 스토리지를 플레이북으로 잡았다면, 이번에는 RHCSA 자동화의 마지막 영역인 보안 구성을 다룹니다. firewalld로 포트를 영구 허용하고, SELinux boolean과 파일 컨텍스트를 조정하며, 사용자 계정에 SSH 공개키를 배포하는 작업을 모두 Ansible로 자동화하겠습니다.
이 세 가지는 RHCSA에서 손으로 익혔던 작업입니다. RHCSA #12 firewalld와 SSH 키 인증에서 firewall-cmd --permanent와 ssh-copy-id를 다뤘고, RHCSA #13 SELinux 깊이에서 setsebool -P와 semanage fcontext, restorecon을 익혔습니다. RHCE는 같은 결과를 멱등성 있는 플레이북으로 만들어 내는 일입니다.
모듈이 속한 collection부터 #
보안 작업에 쓰는 모듈은 대부분 ansible.posix와 community.general collection에 들어 있습니다. core에 기본 포함되지 않을 수 있으므로, 시험 환경에서 설치 여부를 먼저 확인하겠습니다.
| 작업 | 모듈 | collection |
|---|---|---|
| firewalld 규칙 | firewalld | ansible.posix |
| SELinux boolean | seboolean | ansible.posix |
| SELinux 모드 | selinux | ansible.posix |
| 파일 컨텍스트 | sefcontext | community.general |
| SSH 공개키 배포 | authorized_key | ansible.builtin |
ansible-doc -l | grep firewalld로 모듈이 보이는지 확인하고, 보이지 않으면 ansible-galaxy collection install ansible.posix로 설치합니다. 모듈의 전체 옵션은 인터넷 없는 환경에서 ansible-doc ansible.posix.firewalld로 찾는 습관을 들이겠습니다.
firewalld 자동화 #
RHCSA에서 firewall-cmd --add-service=http --permanent와 --reload로 했던 작업을 ansible.posix.firewalld 모듈로 옮깁니다. 이 모듈의 핵심은 영구 적용과 즉시 적용을 별도 옵션으로 제어한다는 점입니다.
| 옵션 | 의미 |
|---|---|
service 또는 port | 허용 대상. 서비스 이름 또는 포트/프로토콜 |
state | enabled로 허용, disabled로 차단 |
permanent: true | 영구 규칙(reboot 후에도 유지). --permanent에 해당 |
immediate: true | 런타임에도 즉시 반영. --reload 없이 바로 적용 |
zone | 적용할 zone. 생략 시 기본 zone |
--permanent만 적용하면 재부팅 전까지 런타임에 반영되지 않으므로, 시험에서는 permanent: true와 immediate: true를 함께 거는 것이 안전합니다. 한쪽만 걸면 “지금은 열렸는데 재부팅하면 닫힌다” 또는 “재부팅 후에는 열리는데 지금은 닫혀 있다” 같은 부분 감점이 납니다.
---
- name: Configure firewalld
hosts: webservers
become: true
tasks:
- name: Ensure firewalld is running
ansible.builtin.service:
name: firewalld
state: started
enabled: true
- name: Allow http service permanently and immediately
ansible.posix.firewalld:
service: http
state: enabled
permanent: true
immediate: true
- name: Allow https service
ansible.posix.firewalld:
service: https
state: enabled
permanent: true
immediate: true
- name: Allow custom tcp port 8080
ansible.posix.firewalld:
port: 8080/tcp
state: enabled
permanent: true
immediate: trueservice는 /usr/lib/firewalld/services에 정의된 이름을 사용하고, 정의가 없는 포트는 port: 8080/tcp 형식으로 직접 엽니다. 여러 서비스를 한 번에 처리하려면 loop로 묶어도 됩니다.
- name: Allow multiple services
ansible.posix.firewalld:
service: "{{ item }}"
state: enabled
permanent: true
immediate: true
loop:
- http
- https
- cockpitSELinux 자동화 #
SELinux 작업은 세 갈래로 나뉩니다. 모드 설정, boolean 토글, 파일 컨텍스트 지정입니다. 각각 다른 모듈을 쓰므로 구분해서 익히겠습니다.
1) 모드 설정: selinux 모듈 #
ansible.posix.selinux 모듈로 enforcing 또는 permissive 모드를 설정합니다. state: enforcing이 정책 적용 모드이고, policy: targeted가 표준 정책입니다.
- name: Ensure SELinux is enforcing
ansible.posix.selinux:
state: enforcing
policy: targeteddisabled에서 enabled로 바꾸는 경우처럼 재부팅이 필요한 변경이면, 이 모듈은 결과에 reboot_required를 알려 줍니다. 그 경우 ansible.builtin.reboot task로 재부팅을 이어 가는 패턴이 안전합니다.
2) boolean 토글: seboolean 모듈 #
setsebool -P httpd_can_network_connect on으로 했던 작업이 ansible.posix.seboolean 모듈입니다. persistent: true가 RHCSA의 -P에 해당하며, 이것을 빠뜨리면 재부팅 후 값이 초기화됩니다.
- name: Allow httpd to make network connections
ansible.posix.seboolean:
name: httpd_can_network_connect
state: true
persistent: true| 옵션 | 의미 |
|---|---|
name | boolean 이름. getsebool -a로 확인 |
state | true로 켜고 false로 끔 |
persistent: true | 재부팅 후에도 유지. setsebool -P에 해당 |
3) 파일 컨텍스트: sefcontext 모듈 #
비표준 경로(예: /web 아래 웹 콘텐츠)를 두면 SELinux 레이블이 맞지 않아 서비스가 접근하지 못합니다. RHCSA에서는 semanage fcontext로 정책에 규칙을 추가하고 restorecon으로 실제 파일에 레이블을 적용했습니다.
community.general.sefcontext 모듈은 정책 규칙만 추가합니다. 즉 semanage fcontext에 해당하는 일까지만 하고, 실제 파일 레이블 적용(restorecon)은 별도 task로 이어 줘야 합니다. 이 둘을 묶는 것이 정석입니다.
- name: Add fcontext rule for /web
community.general.sefcontext:
target: '/web(/.*)?'
setype: httpd_sys_content_t
state: present
- name: Apply the new context to existing files
ansible.builtin.command:
cmd: restorecon -Rv /websefcontext만 실행하면 정책에는 규칙이 들어가지만 이미 존재하는 파일의 레이블은 바뀌지 않습니다. 그래서 command로 restorecon을 한 번 돌려야 실제 파일에 반영됩니다. command는 매번 changed로 잡혀 멱등성이 살짝 어긋나지만, 시험에서는 restorecon이 빠지는 것이 훨씬 큰 감점이므로 함께 두는 편을 권합니다.
SSH 공개키 배포 #
RHCSA에서 ssh-copy-id로 했던 공개키 배포를 ansible.builtin.authorized_key 모듈로 자동화합니다. 특정 사용자의 ~/.ssh/authorized_keys에 공개키를 멱등성 있게 추가하는 모듈입니다.
- name: Deploy public key for deploy user
ansible.builtin.authorized_key:
user: deploy
state: present
key: "{{ lookup('file', 'files/deploy_id_ed25519.pub') }}"| 옵션 | 의미 |
|---|---|
user | 대상 사용자 계정 |
key | 등록할 공개키 문자열. lookup('file', ...)로 파일에서 읽음 |
state | present로 추가, absent로 제거 |
exclusive: true | 이 키만 남기고 기존 키를 모두 제거 |
key는 제어 노드에 둔 공개키 파일을 lookup('file', ...)으로 읽어 넣는 방식이 흔합니다. 여러 사용자에게 각자의 키를 배포하려면 변수 딕셔너리와 loop를 조합합니다.
- name: Deploy keys for multiple users
ansible.builtin.authorized_key:
user: "{{ item.name }}"
state: present
key: "{{ lookup('file', item.keyfile) }}"
loop:
- { name: alice, keyfile: files/alice.pub }
- { name: bob, keyfile: files/bob.pub }system role 대안 #
이번 영역도 손수 모듈을 거는 대신 #13 system roles에서 다룬 rhel-system-roles로 처리할 수 있습니다. 시험에서 system role을 쓰라고 명시하면 반드시 role을 쓰고, 그렇지 않으면 익숙한 쪽을 택하면 됩니다.
firewall system role #
redhat.rhel_system_roles.firewall role에 변수로 규칙을 선언합니다. role 내부가 영구 적용까지 처리하므로 옵션을 일일이 챙길 필요가 줄어듭니다.
- name: Configure firewall via system role
hosts: webservers
become: true
roles:
- redhat.rhel_system_roles.firewall
vars:
firewall:
- service: http
state: enabled
- service: https
state: enabled
- port: 8080/tcp
state: enabledselinux system role #
redhat.rhel_system_roles.selinux role로 모드와 boolean, 파일 컨텍스트를 한 번에 선언합니다. role이 컨텍스트 적용까지 함께 처리하므로 restorecon을 따로 부르지 않아도 됩니다.
- name: Configure SELinux via system role
hosts: webservers
become: true
roles:
- redhat.rhel_system_roles.selinux
vars:
selinux_state: enforcing
selinux_booleans:
- name: httpd_can_network_connect
state: true
persistent: true
selinux_fcontexts:
- target: '/web(/.*)?'
setype: httpd_sys_content_t
state: present
selinux_restore_dirs:
- /web통합 예제 #
세 영역을 하나의 플레이북으로 묶으면 시험의 보안 자동화 문제와 비슷한 형태가 됩니다. firewalld로 포트를 열고, SELinux boolean을 켜고, SSH 키를 배포하는 흐름입니다.
---
- name: Secure web hosts
hosts: webservers
become: true
tasks:
- name: Open http and https permanently
ansible.posix.firewalld:
service: "{{ item }}"
state: enabled
permanent: true
immediate: true
loop:
- http
- https
- name: Enforce SELinux
ansible.posix.selinux:
state: enforcing
policy: targeted
- name: Enable httpd network boolean
ansible.posix.seboolean:
name: httpd_can_network_connect
state: true
persistent: true
- name: Add fcontext for content dir
community.general.sefcontext:
target: '/web(/.*)?'
setype: httpd_sys_content_t
state: present
- name: Restore context on content dir
ansible.builtin.command:
cmd: restorecon -Rv /web
- name: Deploy admin public key
ansible.builtin.authorized_key:
user: deploy
state: present
key: "{{ lookup('file', 'files/deploy.pub') }}"시험 포인트 #
- firewalld는
permanent: true와immediate: true를 함께 거는 것이 안전합니다. 한쪽만 걸면 재부팅 전후 상태가 어긋나 부분 감점이 납니다. - seboolean은
persistent: true를 반드시 챙깁니다. RHCSA의setsebool -P에 해당하며, 빠지면 재부팅 후 초기화됩니다. - sefcontext는 규칙 추가만 합니다. 실제 파일 적용은
restorecon을 별도 task로 이어 줘야 레이블이 반영됩니다. - selinux 모듈은 재부팅이 필요한 변경(disabled에서 enabled)이면
reboot_required를 알려 줍니다. 필요하면reboottask로 이어 갑니다. - authorized_key의
key는lookup('file', ...)으로 제어 노드의 공개키를 읽어 넣습니다.exclusive: true는 기존 키를 지우므로 의도할 때만 씁니다. - 모듈이 보이지 않으면
ansible-galaxy collection install ansible.posix와community.general을 먼저 확인합니다.
정리 #
이번 글에서 잡은 것:
- firewalld.
ansible.posix.firewalld로 service와 port를permanent: true+immediate: true로 영구 허용 - SELinux 모드.
ansible.posix.selinux로 enforcing/targeted 설정. 필요 시 재부팅 - SELinux boolean.
ansible.posix.seboolean로 토글.persistent: true로 영구 적용 - SELinux 컨텍스트.
community.general.sefcontext로 규칙 추가 후restorecon으로 적용 - SSH 키.
ansible.builtin.authorized_key로 사용자별 공개키 배포 - system role 대안. firewall과 selinux role로 같은 작업을 변수 선언으로 처리
이것으로 #14부터 이어진 RHCSA 자동화 네 편이 끝났습니다. 사용자,패키지, 서비스,시간,로그, 스토리지, 보안까지 RHCSA의 손작업을 모두 플레이북으로 옮겼습니다. 시험 비중의 절반을 차지하는 영역이므로, 각 모듈의 영구 적용 옵션을 손에 익히는 것이 합격선을 넘는 지름길입니다.
다음: 시험 팁 #
자동화 영역을 모두 다뤘으니, 이제 4시간을 실제로 어떻게 운영할지 정리할 차례입니다.
#18 시험 팁과 시간 관리에서는 ansible-doc 활용법, 멱등성 검증 습관, 영구 적용 점검 체크리스트, 그리고 시간 배분 전략까지 시험장에서 바로 쓸 수 있는 실전 팁을 정리하겠습니다.