Red Hat Certified Engineer (RHCE) #17 RHCSA 자동화 4: firewall, SELinux, SSH 키

8 분 소요

#16 RHCSA 자동화 3: 스토리지(LVM), 파일시스템(NFS)에서 스토리지를 플레이북으로 잡았다면, 이번에는 RHCSA 자동화의 마지막 영역인 보안 구성을 다룹니다. firewalld로 포트를 영구 허용하고, SELinux boolean과 파일 컨텍스트를 조정하며, 사용자 계정에 SSH 공개키를 배포하는 작업을 모두 Ansible로 자동화하겠습니다.

이 세 가지는 RHCSA에서 손으로 익혔던 작업입니다. RHCSA #12 firewalld와 SSH 키 인증에서 firewall-cmd --permanentssh-copy-id를 다뤘고, RHCSA #13 SELinux 깊이에서 setsebool -Psemanage fcontext, restorecon을 익혔습니다. RHCE는 같은 결과를 멱등성 있는 플레이북으로 만들어 내는 일입니다.

모듈이 속한 collection부터 #

보안 작업에 쓰는 모듈은 대부분 ansible.posixcommunity.general collection에 들어 있습니다. core에 기본 포함되지 않을 수 있으므로, 시험 환경에서 설치 여부를 먼저 확인하겠습니다.

작업모듈collection
firewalld 규칙firewalldansible.posix
SELinux booleansebooleanansible.posix
SELinux 모드selinuxansible.posix
파일 컨텍스트sefcontextcommunity.general
SSH 공개키 배포authorized_keyansible.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허용 대상. 서비스 이름 또는 포트/프로토콜
stateenabled로 허용, disabled로 차단
permanent: true영구 규칙(reboot 후에도 유지). --permanent에 해당
immediate: true런타임에도 즉시 반영. --reload 없이 바로 적용
zone적용할 zone. 생략 시 기본 zone

--permanent만 적용하면 재부팅 전까지 런타임에 반영되지 않으므로, 시험에서는 permanent: trueimmediate: true를 함께 거는 것이 안전합니다. 한쪽만 걸면 “지금은 열렸는데 재부팅하면 닫힌다” 또는 “재부팅 후에는 열리는데 지금은 닫혀 있다” 같은 부분 감점이 납니다.

firewalld 구성 플레이북
---
- 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: true

service/usr/lib/firewalld/services에 정의된 이름을 사용하고, 정의가 없는 포트는 port: 8080/tcp 형식으로 직접 엽니다. 여러 서비스를 한 번에 처리하려면 loop로 묶어도 됩니다.

loop로 여러 서비스 허용
    - name: Allow multiple services
      ansible.posix.firewalld:
        service: "{{ item }}"
        state: enabled
        permanent: true
        immediate: true
      loop:
        - http
        - https
        - cockpit

SELinux 자동화 #

SELinux 작업은 세 갈래로 나뉩니다. 모드 설정, boolean 토글, 파일 컨텍스트 지정입니다. 각각 다른 모듈을 쓰므로 구분해서 익히겠습니다.

1) 모드 설정: selinux 모듈 #

ansible.posix.selinux 모듈로 enforcing 또는 permissive 모드를 설정합니다. state: enforcing이 정책 적용 모드이고, policy: targeted가 표준 정책입니다.

SELinux enforcing 설정
    - name: Ensure SELinux is enforcing
      ansible.posix.selinux:
        state: enforcing
        policy: targeted

disabled에서 enabled로 바꾸는 경우처럼 재부팅이 필요한 변경이면, 이 모듈은 결과에 reboot_required를 알려 줍니다. 그 경우 ansible.builtin.reboot task로 재부팅을 이어 가는 패턴이 안전합니다.

2) boolean 토글: seboolean 모듈 #

setsebool -P httpd_can_network_connect on으로 했던 작업이 ansible.posix.seboolean 모듈입니다. persistent: true가 RHCSA의 -P에 해당하며, 이것을 빠뜨리면 재부팅 후 값이 초기화됩니다.

SELinux boolean 토글
    - name: Allow httpd to make network connections
      ansible.posix.seboolean:
        name: httpd_can_network_connect
        state: true
        persistent: true
옵션의미
nameboolean 이름. getsebool -a로 확인
statetrue로 켜고 false로 끔
persistent: true재부팅 후에도 유지. setsebool -P에 해당

3) 파일 컨텍스트: sefcontext 모듈 #

비표준 경로(예: /web 아래 웹 콘텐츠)를 두면 SELinux 레이블이 맞지 않아 서비스가 접근하지 못합니다. RHCSA에서는 semanage fcontext로 정책에 규칙을 추가하고 restorecon으로 실제 파일에 레이블을 적용했습니다.

community.general.sefcontext 모듈은 정책 규칙만 추가합니다. 즉 semanage fcontext에 해당하는 일까지만 하고, 실제 파일 레이블 적용(restorecon)은 별도 task로 이어 줘야 합니다. 이 둘을 묶는 것이 정석입니다.

fcontext 규칙 추가와 restorecon
    - 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 /web

sefcontext만 실행하면 정책에는 규칙이 들어가지만 이미 존재하는 파일의 레이블은 바뀌지 않습니다. 그래서 commandrestorecon을 한 번 돌려야 실제 파일에 반영됩니다. 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', ...)로 파일에서 읽음
statepresent로 추가, 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 내부가 영구 적용까지 처리하므로 옵션을 일일이 챙길 필요가 줄어듭니다.

firewall 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: enabled

selinux system role #

redhat.rhel_system_roles.selinux role로 모드와 boolean, 파일 컨텍스트를 한 번에 선언합니다. role이 컨텍스트 적용까지 함께 처리하므로 restorecon을 따로 부르지 않아도 됩니다.

selinux role 플레이북
- 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: trueimmediate: true를 함께 거는 것이 안전합니다. 한쪽만 걸면 재부팅 전후 상태가 어긋나 부분 감점이 납니다.
  • seboolean은 persistent: true를 반드시 챙깁니다. RHCSA의 setsebool -P에 해당하며, 빠지면 재부팅 후 초기화됩니다.
  • sefcontext는 규칙 추가만 합니다. 실제 파일 적용은 restorecon을 별도 task로 이어 줘야 레이블이 반영됩니다.
  • selinux 모듈은 재부팅이 필요한 변경(disabled에서 enabled)이면 reboot_required를 알려 줍니다. 필요하면 reboot task로 이어 갑니다.
  • authorized_key의 keylookup('file', ...)으로 제어 노드의 공개키를 읽어 넣습니다. exclusive: true는 기존 키를 지우므로 의도할 때만 씁니다.
  • 모듈이 보이지 않으면 ansible-galaxy collection install ansible.posixcommunity.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 활용법, 멱등성 검증 습관, 영구 적용 점검 체크리스트, 그리고 시간 배분 전략까지 시험장에서 바로 쓸 수 있는 실전 팁을 정리하겠습니다.

X