- 이 글은 CloudNet@ 팀 gasida님의 스터디 A101 1기 내용 및 실습으로 작성된 글입니다.
✅ 사전준비로 유저 생성 및 패스워드 설정
- 프로젝트 디렉터리 생성 및 플레이북 생성과 ansible.cfg, inventory를 생성한다.
# 디렉토리 생성
mkdir ~/my-ansible/chapter_09.1
cd ~/my-ansible/chapter_09.1
# ansible.cfg, inventory 파일 작성
cat <<EOT > ansible.cfg
[defaults]
inventory = ./inventory
remote_user = ubuntu
ask_pass = false
[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false
EOT
cat <<EOT> inventory
tnode1
tnode2
tnode3
EOT
- 사용자 계정 정보가 정의된 변수 파일을 생성
- ~/my-ansible/chapter_09.1/vars/users.yml
mkdir vars
cat <<EOT > vars/users.yml
user_info:
- userid: "ansible"
userpw: "ansiblePw1"
- userid: "stack"
userpw: "stackPw1"
EOT
- 사용자 계정을 생성하는 플레이북을 작성 : 모든 호스트에 동일하게 생성하며 vault로 작성된 변수 파일을 읽어 사용함
- ~/my-ansible/chapter_09.1/create_user.yml
---
- hosts: all
# vault로 사용자 계정 관련 변수가 정의된 파일을 임포트하여 사용
vars_files:
- vars/users.yml
tasks:
# loop 문을 사용하여 user_info의 userid와 userpw 사용
- name: Create user
ansible.builtin.user:
name: "{{ item.userid }}"
password: "{{ item.userpw | password_hash('sha512', 'mysecret') }}"
state: present
shell: /bin/bash
loop: "{{ user_info }}"
- 실행 및 확인
#
ansible-playbook create_user.yml
# 계정 생성 확인
ansible -m shell -a "tail -n 3 /etc/passwd" all
tnode2 | CHANGED | rc=0 >>
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
ansible:x:1001:1001::/home/ansible:/bin/bash
stack:x:1002:1002::/home/stack:/bin/bash
tnode1 | CHANGED | rc=0 >>
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
ansible:x:1001:1001::/home/ansible:/bin/bash
stack:x:1002:1002::/home/stack:/bin/bash
tnode3 | CHANGED | rc=0 >>
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
ansible:x:1001:1001::/home/ansible:/bin/bash
stack:x:1002:1002::/home/stack:/bin/bash
✅ 보안 설정 자동화
1. 패스워드 변경 주기 설정하기
- 패스워드 변경 주기를 설정할 대상 호스트는 인벤토리를 통해 설정한다.
- 패스워드 변경 주기를 설정할 사용자 계정 정보와 최대 변경일은 변수를 통해 별도의 파일로 정의한다.
- 패스워드 변경 주기 설정은 ansible.builtin.user 모듈을 이용한다.
- 플레이북 설계시 사용자 계정과 최대 변경일을 변수로 설정하기 위해 별도 변수파일을 생성하여 관리 (vars_maxdays.yml)
- 메인 플레이북 set_chage_password.yml 파일에는 변경 주기를 설정할 태스트가 포함
#
mkdir ~/my-ansible/chapter_11.1
cd ~/my-ansible/chapter_11.1
# ansible.cfg, inventory 파일 작성
cat <<EOT> ansible.cfg
[defaults]
inventory = ./inventory
remote_user = ubuntu
ask_pass = false
[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false
EOT
cat <<EOT> inventory
[tnode]
tnode1
tnode2
tnode3
EOT
- 플레이북 설계시 사용자 계정과 최대 변경일을 변수로 설정하기 위해 별도 변수파일을 생성하여 관리 (vars_maxdays.yml)
---
Userinfo:
- username: ansible
maxdays: 90
- username: stack
maxdays: 90
- 메인 플레이북 set_chage_password.yml 파일에는 변경 주기를 설정할 태스트가 포함
---
- hosts: tnode
vars_files: vars_maxdays.yml
tasks:
- name: Change Password Maxdays
ansible.builtin.user:
name: "{{ item.username }}"
password_expire_max: "{{ item.maxdays }}"
loop: "{{ Userinfo }}"
- change의 오타인줄 알았는데 아니였다..ㅎ
# 문법 체크
ansible-playbook --syntax-check set_chage_password.yml
# 시뮬레이션
ansible-playbook --check set_chage_password.yml
# 확인 : chage -l ansible
man chage
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i sudo chage -l ansible; echo; done
Password expires : never
...
Maximum number of days between password change : 99999
# 실행
ansible-playbook set_chage_password.yml
# 확인 : chage -l ansible
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i sudo chage -l ansible; echo; done
>> tnode1 <<
Last password change : Jan 10, 2024
Password expires : Apr 09, 2024
...
Maximum number of days between password change : 90
- 확인
ubuntu@server:~/my-ansible/chapter_11.1$ for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i sudo chage -l ansible; echo; done
>> tnode1 <<
Last password change : Feb 11, 2024
Password expires : May 11, 2024
Password inactive : never
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 90
Number of days of warning before password expires : 7
>> tnode2 <<
Last password change : Feb 11, 2024
Password expires : May 11, 2024
Password inactive : never
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 90
Number of days of warning before password expires : 7
>> tnode3 <<
Last password change : Feb 11, 2024
Password expires : May 11, 2024
Password inactive : never
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 90
Number of days of warning before password expires : 7
2. 패스워드 생성 법칙 적용하기
- 패스워드 생성 법칙 적용을 위해서는 pwquality.conf 라는 pam 설정 파일을 이용해야 하며, 리눅스 서버에 libpam-pwquality 패키지가 있어야 함.
- 패스워드 변경 주기는 /etc/securiy/pwquality.conf 파일로 설정한다.
- /etc/securiy/pwquality.conf 파일을 설정하기 전에 원본 파일을 백업받는다.
- pwquality.conf 파일은 사용자가 커스텀으로 설정하는 파라미터들로 구성되어 있으며, Jinja2 템플릿 방식으로 구현한다.
- 파라미터들은 별도의 변수 설정 파일에서 정의한 파라미터 값으로 사용하고, 파라미터 정의 여부를 체크하여 pwquality.conf 파일의 내용을 구성한다.
- 프로젝트 디렉터리 생성 및 ansible.cfg, inventory 파일 작성
- ~/my-ansible/chapter_11.2/..
#
mkdir ~/my-ansible/chapter_11.2
cd ~/my-ansible/chapter_11.2
# ansible.cfg, inventory 파일 작성
cat <<EOT> ansible.cfg
[defaults]
inventory = ./inventory
remote_user = ubuntu
ask_pass = false
[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false
EOT
cat <<EOT> inventory
[tnode]
tnode1
tnode2
tnode3
EOT
- 변수 값 설정
- ~/**my-ansible/**chapter_11.2/vars_pw_rule.yml
---
minlen: 8
dcredit: -1
ucredit: -1
lcredit: -1
ocredit: -1
enforce_for_root: false
✅ Jinja2 템플릿 파일 pwquality.conf.j2 작성
- {% ~ %} 사이에 제어문 구문 위치
- {% if **minlen** is **defined** %} 구문 : minlen 이라는 변수가 정의되면 아래 문장을 삽입하라’ 는 의미
- 아래 템플릿에는 {% if **변수** is **defined** %} ~ {% **endif** %} 구문을 사용하여 파라미터와 관련된 변수가 선언되면 해당 파라미터를 삽입
- ~/**my-ansible/**chapter_11.2/pwquality.conf.j2
# Created by ansible
{% if minlen is defined %}
# Minimum acceptable size for the new password
minlen = {{ minlen }}
{% endif %}
{% if dcredit is defined %}
# The maximum credit for having digits in the new password
dcredit = {{ dcredit }}
{% endif %}
{% if ucredit is defined %}
# The maximum credit for having uppercase characters in the new password
ucredit = {{ ucredit }}
{% endif %}
{% if lcredit is defined %}
# The maximum credit for having lowercase characters in the new password
lcredit = {{ lcredit }}
{% endif %}
{% if ocredit is defined %}
# The maximum credit for having other characters in the new password
ocredit = {{ ocredit }}
{% endif %}
{% if minclass is defined %}
# The minimum number of required classes of characters for the new password
minclass = {{ minclass }}
{% endif %}
{% if maxrepeat is defined %}
# The maximum number of allowed consecutive same characters in the new password
maxrepeat = {{ maxrepeat}}
{% endif %}
{% if maxclassrepeat is defined %}
# The maximum number of allowed consecutive characters of the same class in the new password
maxclassrepeat = {{ maxclassreapt }}
{% endif %}
{% if retry is defined %}
# Prompt user at most N times before returning with error
retry = {{ retry }}
{% endif %}
{% if enforce_for_root is defined %}
# Enforces pwquality checks on the root user password.
enforce_for_root
{% endif %}
- 메인 플레이북 작성
- ~/my-ansible/chapter_11.2/set_password_rule.yml
---
- hosts: tnode
vars_files: vars_pw_rule.yml
tasks:
- name: Install libpam-pwquality
ansible.builtin.apt:
name: libpam-pwquality
state: present
when: ansible_facts.os_family == "Debian"
- name: Backup pwquality.conf
ansible.builtin.copy:
src: /etc/security/pwquality.conf
dest: /etc/security/pwquality.conf.bak
remote_src: yes
- name: Copy pwquality.conf.j2 at /etc/security
ansible.builtin.template:
src: pwquality.conf.j2
dest: /etc/security/pwquality.conf
mode: '0644'
- 플레이북 실행 및 확인
# 문법 체크
ansible-playbook --syntax-check set_password_rule.yml
# 시뮬레이션
ansible-playbook --check set_password_rule.yml
# 실행 전 확인
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i sudo cat /etc/security/pwquality.conf; echo; done
ubuntu@server:~/my-ansible/chapter_11.2$ for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i sudo cat /etc/security/pwquality.conf; echo; done
>> tnode1 <<
cat: /etc/security/pwquality.conf: No such file or directory
>> tnode2 <<
cat: /etc/security/pwquality.conf: No such file or directory
>> tnode3 <<
cat: /etc/security/pwquality.conf: No such file or directory
- 파일이 없음을 확인
- 패스워드 변경 규칙에 맞게 노드에 접속하여 불충분 패스워드를 일부러 만들어 테스트함
# 실행
ansible-playbook set_password_rule.yml
# 확인
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i sudo ls -l /etc/security; echo; done
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i sudo cat /etc/security/pwquality.conf; echo; done
total 60
-rw-r--r-- 1 root root 4564 Mar 24 2022 access.conf
-rw-r--r-- 1 root root 1793 Jul 1 2020 capability.conf
-rw-r--r-- 1 root root 2234 Mar 24 2022 faillock.conf
-rw-r--r-- 1 root root 3635 Mar 24 2022 group.conf
-rw-r--r-- 1 root root 2161 Mar 24 2022 limits.conf
drwxr-xr-x 2 root root 4096 Mar 24 2022 limits.d
-rw-r--r-- 1 root root 1637 Mar 24 2022 namespace.conf
drwxr-xr-x 2 root root 4096 Mar 24 2022 namespace.d
-rwxr-xr-x 1 root root 1016 Mar 24 2022 namespace.init
-rw------- 1 root root 0 Feb 8 02:47 opasswd
-rw-r--r-- 1 root root 2971 Mar 24 2022 pam_env.conf
-rw-r--r-- 1 root root 487 Feb 11 17:54 pwquality.conf
-rw-r--r-- 1 root root 2674 Jan 14 2022 pwquality.conf.bak
-rw-r--r-- 1 root root 419 Mar 24 2022 sepermit.conf
-rw-r--r-- 1 root root 2179 Mar 24 2022 time.conf
# 확인 : ansible 계정에 패스워드를 조건이 불충분하도록 입력 시도
ssh tnode2
-----------------
sudo su - ansible
whoami
pwd
passwd ansible
Changing password for ansible.
Current password: ansiblePw1
New password: qwer
BAD PASSWORD: The password contains less than 1 digits
New password: qwer1234
BAD PASSWORD: The password contains less than 1 uppercase letters
New password: Qwer1234
BAD PASSWORD: The password contains less than 1 non-alphanumeric characters
passwd: Have exhausted maximum number of retries for service
passwd: password unchanged
3. 디렉터리 및 파일 접근 권한 변경
- 리눅스 보안 중에 꼭 확인해야 하는 항목이 바로 Sticky bit 설정 파일과 World Writable 설정 파일입니다.
- Sticky bit 설정 파일은 리눅스에서 파일 소유자나 그룹 소유자만 해당 파일을 읽고 쓰고 삭제할 수 있도록 권한을 부여한 것을 의미합니다.
- 파일 소유자에게 권한을 부여하면 SUID, 파일 그룹에게 권한을 부여하면 SGID, 다른 사람에게 권한을 부여하면 Sticky bit 라고 합니다.
- Sticky bit가 적용된 파일 목록 중 보안을 위해 이를 적용하면 안 되는 파일 목록들이 있습니다.
- Sticky bit가 적용된 파일의 권한을 수정할 때는 적용되면 안 되는 파일인지 반드시 먼저 확인합니다 → 보안 관련 가이드 문서 참고
- World Writable 파일은 모든 사용자에게 파일을 읽고 쓸 수 있는 권한이 부여된 파일을 의미합니다.
- 프로젝트 디렉터리 생성 및 ansible.cfg, inventory 파일 작성
- ~/my-ansible/chapter_11.3/..
#
mkdir ~/my-ansible/chapter_11.3
cd ~/my-ansible/chapter_11.3
# ansible.cfg, inventory 파일 작성
cat <<EOT> ansible.cfg
[defaults]
inventory = ./inventory
remote_user = ubuntu
ask_pass = false
[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false
EOT
cat <<EOT> inventory
[tnode]
tnode1
tnode2
tnode3
EOT
- 태스크 파일 작성 : 검색 시 grep 으로 필터링(-e 정규식 패턴, -v 매칭되지 않는 경우)
- ~/my-ansible/chapter_11.3/set_sticky_writable_files.yml
---
- hosts: tnode
tasks:
- name: Find Sticky bit files
ansible.builtin.shell: |
find / -xdev -perm -04000 -o -perm -02000 -o -perm 01000 \
| grep -e 'dump$' \
-e 'lp*-lpd$' \
-e 'newgrp$' \
-e 'restore$' \
-e 'at$' \
-e 'traceroute$' | xargs ls
register: sfile_list
- name: Find World Writable files
ansible.builtin.shell: |
find / -xdev -perm -2 -ls \
| grep -v 'l..........' | awk '{print $NF}'
register: wfile_list
- name: Print Sticky bit files
ansible.builtin.debug:
msg: "{{ sfile_list.stdout_lines }}"
- name: Print World Writable files
ansible.builtin.debug:
msg: "{{ wfile_list.stdout_lines }}"
- name: Set Sticky bit files
ansible.builtin.file:
path: "{{ item }}"
mode: "u-s,g-s,o-s"
loop: "{{ sfile_list.stdout_lines }}"
- name: Set World Writable files
ansible.builtin.file:
path: "{{ item }}"
mode: "o-w"
loop: "{{ wfile_list.stdout_lines }}"
- 플레이북 실행
# 문법 체크
ansible-playbook --syntax-check set_sticky_writable_files.yml
# 시뮬레이션
ansible-playbook --check set_sticky_writable_files.yml
# (예시) 확인
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i sudo ls -al /usr/bin/newgrp; echo; done # -rwsr-xr-x
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i sudo ls -al /var/crash; echo; done # drwxrwxrwt
# 실행
ansible-playbook set_sticky_writable_files.yml
# (예시) 변경 확인
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i sudo ls -al /usr/bin/newgrp; echo; done # -rwxr-xr-x
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i sudo ls -al /var/crash; echo; done # drwxrwxr-t
# 한번 더 실행
ansible-playbook set_sticky_writable_files.yml
- -rwsr-xr-x ---> -rwxr-xr-x
- drwxrwxrwt ---> # drwxrwxr-t
'DevOps > Ansible' 카테고리의 다른 글
[A101] 8. Ansible 모니터링 자동화 (0) | 2024.02.11 |
---|---|
[A101] 6. Ansible 시스템 구축 및 환경 설정 자동화 (0) | 2024.02.03 |
[A101] 5. Ansible Kubespray 분석 (0) | 2024.01.19 |
[A101] 4. Ansible 반복문, 조건문 (0) | 2024.01.18 |
[A101] 3. Ansible 기본사용(2) (0) | 2024.01.08 |