티스토리 뷰

CloudNet@의 가시다님 Ansible 1기 스터디에 참여하게 되어 배운 내용과 책의 내용을 함께 정리합니다.

📚 앤서블로 시작하는 인프라 자동화

 

앤서블로 시작하는 인프라 자동화 | 장현정 - 교보문고

앤서블로 시작하는 인프라 자동화 | 효율적인 IT 자동화를 위한 도구, 앤서블 설계부터 응용까지 단계별로 배우는 인프라 관리클라우드 컴퓨팅을 논할 때 IaC(Infrastructure as Code)를 빼놓을 수 없는

product.kyobobook.co.kr

1. 보안 설정 자동화

1.1. 패스워드 변경 주기 설정

사전 분석

  • 패스워드 변경 주기를 설정할 대상 호스트는 인벤토리를 통해 설정합니다.
  • 패스워드 변경 주기를 설정할 사용자 계정 정보와 최대 변경일은 변수를 통해 별도의 파일로 정의합니다.
  • 패스워드 변경 주기 설정은 ansible.builtin.user 모듈을 이용합니다.

플레이북 설계

  • 사용자 계정과 최대 변경일을 변수로 설정하기 위해 vars_maxdays.yml 파일을 생성합니다.
  • 메인 플레이북 set_chage_password.yml 파일에는 변경 주기를 설정할 태스트가 포함됩니다.

패스워드 변경 주기 설정 플레이북 설계

플레이북 개발 및 실행

1. 프로젝트 디렉토리를 생성하고 ansible.cfg, inventory 파일을 작성합니다.

~/my-ansible/chapter_11.1

#
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

 

 

2. 사전형 변수 파일을 작성합니다.

~/my-ansible/chapter_11.1/vars_maxdays.yml

---

Userinfo:
  - username: ansible
    maxdays: 90
  - username: stack
    maxdays: 90

 

3. 메인 플레이북을 작성합니다. (패스워드 변경 주기는 user 모듈의 password_expire_max 파라미터로 설정합니다.)

~/my-ansible/chapter_11.1/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 }}"

 

4. 리눅스에서 명령어의 용도가 궁금할때는 man <COMMAND>를 입력해 확인할 수 있습니다. 

  • chage는 사용자의 패스워드 만기 정보를 변경 및 설정하는 명령어입니다. (root 권한을 가진 사용자만 사용 가능)

 

5. 플레이북을 실행합니다.

 

5. 실행한 결과를 확인해보면 각 노드의 ansible 계정마다 잘 적용된 것을 확인할 수 있습니다.

 

1.2. 패스워드 생성 법칙 적용

사전 분석

  • 패스워드 생성 법칙 적용을 위해서는 pwquality.conf 라는 pam 설정 파일을 이용해야 하며, 리눅스 서버에 libpam-pwquality 패키지가 있어야 합니다.
  • 패스워드 변경 주기는 /etc/securiy/pwquality.conf 파일로 설정합니다.
  • /etc/securiy/pwquality.conf 파일을 설정하기 전에 원본 파일을 백업받습니다.
  • pwquality.conf 파일은 사용자가 커스텀으로 설정하는 파라미터들로 구성되어 있으며, Jinja2 템플릿 방식으로 구현합니다.
  • 파라미터들은 별도의 변수 설정 파일에서 정의한 파라미터 값으로 사용하고, 파라미터 정의 여부를 체크하여 pwquality.conf 파일의 내용을 구성합니다.

플레이북 설계

  • 변수 vars_pw_rule.yml 에 정의합니다.
    • 최소 패스워드 길이 설정 minlen
    • 최소 숫자 개수 설정 dcredit
    • 최소 대문자 개수 설정 ucredit
    • 최소 소문자 개수 설정 lcredit
    • 최소 특수문자 개수 설정 ocredit
    • root 계정에서도 해당 패스워드 룰을 설정할 수 있는 enforce_for_root
  • Jinja2 템플릿 파일 pwqulity.conf.j2 아래 내용 포함
    • minlen, dcredit, ucredit, lcredit, orcedit, enforce_for_root
    • minclass : 최소 문자클래스 개수
    • maxrepeat : 최대 연속 동일 문자 수
    • maxclassrepeat : 동일 글래스의 최대 연속 문자 수

패스워드 생성 법칙 플레이북 설계

플레이북 개발 및 실행

1. 프로젝트 디렉토리를 생성하고 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

 

 

2. 변수 값을 설정합니다.

~/my-ansible/chapter_11.2/vars_pw_rule.yml

---

minlen: 8
dcredit: -1
ucredit: -1
lcredit: -1
ocredit: -1
# default 값은 true지만 실습의 편의성을 위해 false로 적용
enforce_for_root: false

 

3. 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 %}

 

4. 메인 플레이북을 작성합니다. when 구문으로 데비안(우분투)의 경우 apt 패키지를 설치합니다. 이후 copy로 백업 후, template으로 템플릿 파일을 복사합니다.

~/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
        # default 값은 no지만 그럴 경우 로컬에서 파일 복사
        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'

 

5. 플레이북을 실행하기 전에 패스워드 생성 법칙이 설정되어 있는지 체크해보면 설정되어 있지 않은 것을 확인할 수 있습니다.

 

6. 플레이북을 실행합니다.

 

7. 패스워드 생성 법칙이 적용된 것은 파일의 생성 유무에 따라 확인할 수 있습니다.

 

8. 생성된 conf파일을 확인해보면 변수 파일에 지정해놓은 내용이 적용되어 있는 것을 확인할 수 있습니다.

 

9. 실제로 적용되어 있는지 노드에 접속해 확인해봅니다.

 

1.3. 디렉토리 및 파일 접근 권한 변경

상황

  • 리눅스 보안 중에 꼭 확인해야 하는 항목이 바로 Sticky bit 설정 파일World Writable 설정 파일입니다.
  • Sticky bit 설정 파일은 리눅스에서 파일 소유자그룹 소유자만 해당 파일을 읽고 쓰고 삭제할 수 있도록 권한을 부여한 것을 의미합니다.
  • 파일 소유자에게 권한을 부여하면 SUID, 파일 그룹에게 권한을 부여하면 SGID, 다른 사람에게 권한을 부여하면 Sticky bit 라고 합니다.
  • Sticky bit가 적용된 파일 목록 중 보안을 위해 이를 적용하면 안 되는 파일 목록들이 있습니다.
  • Sticky bit가 적용된 파일의 권한을 수정할 때는 적용되면 안 되는 파일인지 반드시 먼저 확인합니다. 보안 관련 가이드 문서 참고
  • Sticky bit가 설정된 디렉토리 내에서는 (/tmp와 /var/tmp의 기본 퍼미션은 777입니다.)
    1. 퍼미션이 777인 파일에 대해서 파일의 소유자만이 삭제를 할 수 있습니다. (수정이나 실행, 읽기는 모두 허용됩니다.)
    2. Sticky bit가 설정된 디렉토리 자체도 소유자만이 삭제할 수 있습니다.
    3. root 계정은 모두 할 수 있습니다.
  • World Writable 파일모든 사용자에게 파일을 읽고 쓸 수 있는 권한이 부여된 파일을 의미합니다.

사전 분석

  • Sticky bit 파일 검색 명령어: find / -xdev -perm -04000 -o -perm -02000 -o -perm -01000
  • World Writable 파일 검색 명령어: find / -xdev -type f -perm -2
  • ansible.builtin.shell 모듈을 이용하여 Sticky bit 파일과 World Writable 파일을 찾습니다.
  • 찾은 파일 목록은 ansible.builtin.file 모듈을 이용하여 파일의 접속 권한을 설정합니다.
  • Sticky bit 파일은 u-s, g-s, o-s 로 설정하고, World Writable 파일은 o-w 로 설정합니다.

플레이북 설계

접근 권한 변경 플레이북 설계

 

 

플레이북 개발 및 실행

1. 프로젝트 디렉토리를 생성하고 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

 

2. 태스크 파일을 작성합니다. 검색 시 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 }}"

 

3. 플레이북 실행 전에 파일들의 권한을 살펴보면 Sticky bit와 World Writable 설정이 되어있는 파일을 확인할 수 있습니다.

 

4. 플레이북을 실행합니다.

 

5. 파일을 다시 살펴보면 Sticky bit와 World Writable 설정이 빠진 것을 확인할 수 있습니다.

 

1.4. 사설 인증서 생성

 

How to create self-signed certificates — Ansible Documentation

© Copyright Ansible project contributors. Last updated on Feb 02, 2024.

docs.ansible.com

사전 분석

  • 사설 인증서에는 자체 서명된 인증 기관용 인증서와 해당 인증서를 이용해 만든 클라이언트 인증 키가 있습니다.
  • 인증서를 만들 때는 CSR(Certificate Signing Request) 이라는 인증 서명 요청을 합니다.
  • CSR을 통해 인증 기관용 인증서클라이언트 인증 키를 생성합니다.
  • 앤서블에서 개인 키를 만들 때는 community.crypto.openssl_privatekey 모듈을 사용합니다. - Link
  • CSR을 만들 때는 community.crypto.openssl_csr_pipe 모듈을 사용합니다. - Link
  • CSR을 이용하여 인증서를 생성할 때는 community.crypto.x509_certificate 모듈을 사용 - Link

플레이북 설계

사설 인증서 생성 플레이북 설계

  • tnode1사설 인증서를 생성하기 위해 inventory에 rootCA 호스트 그룹을 만들고 그룹 멤버로 tnode1 노드를 추가합니다.
  • 인증서 생성에 필요한 들은 vars_ssltls.yml 파일을 통해 외부 변수로 정의합니다.
  • 메인 플레이북인 make_certification.yml 에는 become을 false로 설정하여 root 계정이 아닌 ubuntu 계정으로 실행되도록 합니다.
  • pre_tasks 키워드를 사용하여 롤이 실행되기 전에 먼저 태스크가 실행되도록 하였으며, 인증서 생성을 위한 디렉토리를 생성하는 태스크를 추가합니다.
  • 인증서 생성은 rootCA 인증서와 serverKey로 나뉘며, 해당 인증서 생성은 각각 롤을 생성하여 처리하도록 설계합니다.
  • rootCA 롤과 serverKey 롤은 각각 ‘개인 키 생성CSR (인증 서명 요청) 생성 → CSR을 이용한 인증서 생성’ 태스크로 구성되며, serverKey 롤에서 CSR 인증서를 생성할 때는 이미 사전에 생성된 rootCA로부터 발급받아 생성하는 방식을 사용합니다.

플레이북 개발 및 실행

1. 프로젝트 디렉토리를 생성하고 ansible.cfg, inventory 파일을 작성합니다.

~/my-ansible/chapter_11.4

#
mkdir ~/my-ansible/chapter_11.4
cd ~/my-ansible/chapter_11.4

# ansible.cfg, inventory 파일 작성
cat <<EOT> ansible.cfg
[defaults]
inventory = ./inventory
remote_user = ubuntu
ask_pass = false
roles_path = ./roles

[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false
EOT

cat <<EOT> inventory
[rootCA]
tnode1

[tnode]
tnode2
tnode3
EOT

 

2. myrole.rootCA와 myrole.serverKey 롤을 생성합니다.

ansible-galaxy role init --init-path ./roles myrole.rootCA
ansible-galaxy role init --init-path ./roles myrole.serverKey

 

3. 롤이 생성되었는지 확인합니다.

 

4. myrole.rootCA 에 태스크 파일을 작성합니다. (플레이북은 community.crypto 라는 컨텐츠 컬렉션을 사용) - Link

  • 개인 키를 만들 때는 community.crypto.openssl_privatekey 모듈을 사용합니다. - Link
  • CSR을 만들 때는 community.crypto.openssl_csr_pipe 모듈을 사용합니다. - Link
  • CSR을 이용하여 인증서를 생성할 때는 community.crypto.x509_certificate 모듈을 사용합니다. - Link
  • 여기서는 자체 서명 인증서를 생성하는 것이므로 providerselfsigned 로 설정합니다.

~/my-ansible/chapter_11.4/roles/myrole.rootCA/tasks/main.yml

---
# tasks file for myrole.rootCA

- name: Create new private key for rootCA
  community.crypto.openssl_privatekey:
    path: "{{ ca_privatekey_path }}"

- name: Create CSR for new certificate rootCA
  community.crypto.openssl_csr_pipe:
    privatekey_path: "{{ ca_privatekey_path }}"
    country_name: "{{ country_name }}"
    organization_name: "{{ orgarnization_name }}"
    common_name: "{{ ca_common_name }}"
  register: csr

- name: Create Self-signed new certificate rootCA
  community.crypto.x509_certificate:
    path: "{{ ca_certificate_path }}"
    privatekey_path: "{{ ca_privatekey_path }}"
    csr_content: "{{ csr.csr }}"
    selfsigned_not_after: "{{ certificate_days }}"
    provider: selfsigned
    state: present

 

5. myrole.serverKey에 태스크 파일을 작성합니다.

  • myrole.rootCA 태스크와 비슷하지만, rootCA로부터 발급받는 인증서를 생성할 때 provider가 사전에 생성된 CA 파일을 이용합니다.(ownca를 사용합니다.)
  • 사전에 생성된 rootCA의 개인 키와 인증서는 ownca로 시작되는 파라미터를 사용합니다.

~/my-ansible/chapter_11.4/roles/myrole.serverKey/tasks/main.yml

---
# tasks file for myrole.serverKey

- name: Create new private key for server key
  community.crypto.openssl_privatekey:
    path: "{{ server_privatekey_path }}"

- name: Create CSR for new server key
  community.crypto.openssl_csr_pipe:
    privatekey_path: "{{ server_privatekey_path }}"
    country_name: "{{ country_name }}"
    organization_name: "{{ orgarnization_name }}"
    common_name: "{{ server_common_name }}"
  register: csr

- name: Create Self-signed server key from rootCA
  community.crypto.x509_certificate:
    path: "{{ server_certificate_path }}"
    privatekey_path: "{{ server_privatekey_path }}"
    csr_content: "{{ csr.csr }}"
    ownca_path: "{{ ca_certificate_path }}"
    ownca_privatekey_path: "{{ ca_privatekey_path }}"
    ownca_not_after: "{{ certificate_days }}"
    provider: ownca
    state: present

 

6. 프로젝트 디렉토리에서 변수 파일을 생성합니다.

touch ~/my-ansible/chapter_11.4/vars_ssltls.yml

~/my-ansible/chapter_11.4/vars_ssltls.yml

---

country_name: KR
orgarnization_name: Cloudneta
ca_common_name: Ubuntu-CA
server_common_name: local
certificate_days: "+3650d"
ssl_tls_path: /home/ubuntu/tls
ca_privatekey_path: /home/ubuntu/tls/ca_priv.key
ca_certificate_path: /home/ubuntu/tls/ca_cert.crt
server_privatekey_path: /home/ubuntu/tls/server_priv.key
server_certificate_path: /home/ubuntu/tls/server_cert.crt

 

7. 플레이북을 작성합니다.

  • become를 false로 설정하여 root가 아닌 ubuntu 계정에서 실행합니다.
  • pre_tasks 섹션을 통해 롤이 실행되기 전에 인증서를 생성하고 보관할 디렉토리를 먼저 생성합니다.
touch ~/my-ansible/chapter_11.4/make_certification.yml

~/my-ansible/chapter_11.1/make_certification.yml

---

- hosts: rootCA
  become: false
  vars_files: vars_ssltls.yml

  pre_tasks:
    - name: Make ssl & tls directory
      ansible.builtin.file:
        path: "{{ ssl_tls_path }}"
        state: directory

  roles:
    - role: myrole.rootCA
    - role: myrole.serverKey

 

8. 플레이북을 실행합니다.

 

9. 플레이북의 대상이 rootCA 호스트 그룹이었으므로 tnode1에만 인증관련 파일이 생성된 것을 확인할 수 있습니다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함