[![logo](https://www.hongsnet.net/images/logo.gif)](https://www.hongsnet.net) # Ansible 활용 > OS 보안취약점 조치작업을 자동화 한다. # Table of Contents | NO | ITEM | Content | 비고 | | ------ | ------ | ------ | ------ | | 1 | /etc/securetty 점검 | [GO](./SECURETTY/) | | | 2 | sshd_config 설정 취약점 | [GO](./SSHD/) | | | 3 | common-password (PAM) 설정 취약점 | [GO](./PAM/COMMON/) | | | 4 | pam_tally2 (PAM) 설정 취약점 | [GO](./PAM/TALLY2) | | | 5 | 리눅스 계정파일 권한 취약점 | [GO](./PERMISSION/FILE) | | | 6 | SUID,SGID,STICKBIT 설정 취약점 | [GO](./PERMISSION/BITS) | | | 7 | cron Deny 설정 취약점 | [GO](./CRON/) | | | 8 | login.defs 설정 취약점 | [GO](./LOGIN/) | | | 9 | issue MOTD(Banner) 설정 취약점 | [GO](./MOTD/) | | | 10 | rsyslog 설정 취약점 | [GO](./LOGS/) | | | 11 | TMOUT (/etc/profile) 설정 취약점 | [GO](./PROFILE/) | | | 12 | World Writealbe 설정 취약점 | [GO](./PERMISSION/WWR) | | ## 전체 Playbook 위의 각 항목별 Playbook은 해당 보안취약점에 대한 조치 검증으로 살펴보았으며, 위의 항목을 모두 통합한 Playbook은 다음과 같다. 단, **World Write Able 조치는 12번에 명시된 Playbook을 별도로 수행**한다. ```python --- - name: OS Secure Fix hosts: ALL_HOSTS vars: time: "{{lookup('pipe','date \"+%Y%m%d\"')}}" tasks: - name: Disable root remote access - commenting pts replace: dest=/etc/securetty regexp="^pts" replace="#pts" - name: Disable root login over SSH Comment absent lineinfile: dest: /etc/ssh/sshd_config regexp: "^#PermitRootLogin" line: "" state: absent - name: Disable root login over SSH lineinfile: dest: /etc/ssh/sshd_config regexp: "^PermitRootLogin" line: "PermitRootLogin no" state: present notify: - reload sshd - name: /root/test Directory Create command: mkdir -p /root/test - name: /root/test/common-password_{{ time }} file copy check stat: path: /root/test/common-password_{{ time }} register: common_password_config_backup - name: /etc/pam.d/common-password_{{ time }} file backup command: cp -rf /etc/pam.d/common-password /root/test/common-password_{{ time }} when: common_password_config_backup.stat.exists == False - name: Copy the /etc/pam.d/common-password file in remote node copy: src: templates/common-password dest: /etc/pam.d/common-password owner: root group: root mode: 0644 register: common_password_config - name: Restrict Access to the su Command lineinfile: dest: /etc/pam.d/su regexp: '# auth required pam_wheel.so' line: 'auth required pam_wheel.so use_uid' state: present - name: Account Pam_tally2 Setting lineinfile: path: /etc/pam.d/common-auth insertbefore: BOF regexp: "pam_tally2.so" line: "auth required pam_tally2.so onerr=fail audit silent deny=5 unlock_time=900" when: ansible_distribution == "Debian" - name: Account Pam_tally2 Setting lineinfile: dest: '/etc/pam.d/system-auth' regexp: "pam_tally2.so" line: "auth required pam_tally2.so onerr=fail audit silent deny=5 unlock_time=900" state: present when: ansible_distribution == "CentOS" - name: /etc/passwd file check stat: path=/etc/passwd register: passwd_check - name: /etc/passwd permission set Execute... command: chmod 644 /etc/passwd when: passwd_check.stat.mode != 644 - name: /etc/passwd owner set Execute... command: chown root. /etc/shadow when: passwd_check.stat.pw_name != 'root' - name: /etc/passwd group set Execute... command: chown .root /etc/shadow when: passwd_check.stat.gr_name != 'root' - name: /etc/group file check stat: path=/etc/group register: group_check - name: /etc/group permission set Execute... command: chmod 644 /etc/group when: group_check.stat.mode != 644 - name: /etc/group owner set Execute... command: chown root. /etc/group when: group_check.stat.pw_name != 'root' - name: /etc/group group set Execute... command: chown .root /etc/group when: group_check.stat.gr_name != 'root' - name: /etc/shadow file check stat: path=/etc/shadow register: shadow_check - name: /etc/shadow permission set Execute... command: chmod 640 /etc/shadow when: shadow_check.stat.mode != 640 - name: /etc/shadow owner set Execute... command: chown root. /etc/shadow when: shadow_check.stat.pw_name != 'root' - name: /etc/shadow group set Execute... command: chown .shadow /etc/shadow when: shadow_check.stat.gr_name != 'shadow' - name: Remove SGID, SUID Permission Bit file: path: "{{ item }}" owner: root group: root mode: 00755 with_items: - /usr/bin/newgrp - /sbin/unix_chkpwd - /usr/bin/at - name: Copy the CRON cron.allow file in remote node copy: src: templates/cron.allow.j2 dest: /etc/cron.allow owner: root group: root mode: 0640 - name: Copy the CRON cron.deny file in remote node copy: src: templates/cron.deny.j2 dest: /etc/cron.deny owner: root group: root mode: 0640 - name: Modify Password Min Length lineinfile: dest=/etc/login.defs regexp="PASS_MIN_LEN" line="PASS_MIN_LEN 8" state=present - name: Modify Password Max Days lineinfile: dest=/etc/login.defs regexp="^PASS_MAX_DAYS[\s\x20]*[0-9]*" line="PASS_MAX_DAYS 90" state=present - name: Modify Password Min Days lineinfile: dest=/etc/login.defs regexp="^PASS_MIN_DAYS[\s\x20]*[0-9]*" line="PASS_MIN_DAYS 1" state=present - name: Copy the banner issue file in remote node copy: src: templates/issue.j2 dest: /etc/issue owner: root group: root mode: 0644 - name: Copy the banner motd file in remote node copy: src: templates/issue.j2 dest: /etc/motd owner: root group: root mode: 0644 - name: Copy the banner issue.net file in remote node copy: src: templates/issue.j2 dest: /etc/issue.net owner: root group: root mode: 0644 - name: /etc/ssh/sshd_config Banner Configure lineinfile: dest=/etc/ssh/sshd_config regexp="^#?Banner" line="Banner /etc/issue.net" state=present - name: /root/test Directory Create command: mkdir -p /root/test - name: /root/test/rsyslog_config_{{ time }} file copy check stat: path: /root/test/rsyslog.conf_{{ time }} register: rsyslog_config_backup - name: /etc/rsyslog.conf_{{ time }} file backup command: cp -rf /etc/rsyslog.conf /root/test/rsyslog.conf_{{ time }} when: rsyslog_config_backup.stat.exists == False - name: Copy the Rsyslog Configs file file in remote node copy: src: templates/rsyslog.conf.j2 dest: /etc/rsyslog.conf owner: root group: root mode: 0644 register: rsyslog_config - name: rsyslog Daemon Reloaded Service service: name: rsyslog state: restarted enabled: yes when: rsyslog_config.changed - name: Login TimeOut Setting 600 seconds lineinfile: dest=/etc/profile regexp="^TMOUT" line="TMOUT=600" state=present handlers: - name: reload sshd systemd: name: sshd state: reloaded ``` ## Playbook 실행 ```bash # ansible-playbook -i hosts linux_secure_fix.yml ```