Infra/Cloud

[Ansible] 시스템 구축 및 환경 설정 자동화(스터디 3주차)

IMyoungho 2024. 1. 31. 12:00

3주차는 지금까지 배운 Ansible의 anisble-galaxy, playbook, role, module 등을 이용해 직접 환경구축 및 테스트를 진행했다.

따라서 이번 포스팅에서는 별도로 개념이 추가된 것이 아니므로 활용에 관련된 도전과제만 작성해보았다.

 


 

# 도전과제1

* ansible-vault 사용시, AWS SecretManager를 활용해보기

 

- 우선 ansible-vault  create를 통해 암호화할 파일(user_secrert.yml)을 생성한다.

- 나의 경우 파일 암호화에 쓰일 패스워드를 'Password123'으로 했다.

# user_secret.yml
---

user_info:
  - userid: "ansible"
    userpw: "ansiblePw1"
  - userid: "stack"
    userpw: "stackPw1"

=> 해당 파일이 ansible-vault에 의해 암호화 된 것을 확인할 수 있었다.

 

 

 

- Playbook 생성

---

- hosts: all

  # vault로 사용자 계정 관련 변수가 정의된 파일을 임포트하여 사용
  vars_files:
    - user_secret.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 }}"

=> 위에서 암호화한 파일의 user id,pw 정보로 계정을 생성하는 Playbook이다.

 

 

 

- ansible-vault encrypt 파일 사용 시, playbook 실행방법

ansible-playbook create-user.yaml --ask-vault-pass

=> 해당 방법은 파일암호화에 사용된 패스워드를 입력하는 옵션인 '--ask-vault-pass'를 사용한 것이다. 하지만 이 방법은 파이프라인 구성이나 자동화 스트립트 등에 사용 시에는 제약이 따라온다. 이를 해결하는 방법은 '--vault-password-file' 옵션을 통해 파일 암호화에 사용된 패스워드를 파일에 작성하여 사용하는 것이다. 

 

 

AWS Secret Manager

- 하지만  '--vault-password-file' 을 사용하는 방법 역시, 해당 복호화 키 파일의 유출 가능성이 존재하므로 안전한 저장소에서 관리하는 것이 더욱 좋다. 그래서 사용할 수 있는 방법중 하나가 바로 AWS Secret Manager이다.

 

 

- aws secretmanager를 통한 secret 생성

cat  << EOF > secret.json
{
    "password": "Password123"
}
EOF
aws secretsmanager create-secret --name  secret-file --secret-string file://secret.json --region ap-northeast-2

=> secret.json에 암호화에 사용될 Key-value 값을 작성한 뒤 해당파일을 인자로 create-secret을 진행하였다.

 

 

 

- 존재하는 Secret name 확인

aws secretsmanager list-secrets --region ap-northeast-2 | jq -r .SecretList[].Name

=> aws-cli나 GUI를 통해 내가 저장한 Secret value를 확인할 수 있었다. 이제 해당 secret을 암호화키로 사용해보자.

 

 

 

- aws secretmanager value 사용

aws secretsmanager get-secret-value --secret-id secret-file --region ap-northeast-2 | jq -r '.SecretString | fromjson | .password'
cat > get-secret.sh << EOF
#!/bin/bash
aws secretsmanager get-secret-value --secret-id secret-file --region ap-northeast-2 | jq -r '.SecretString | fromjson | .password'
EOF

chmod +x get-secrets.sh
ansible-playbook  create-user.yaml --vault-password-file ./get-secret.sh

=> shellscript를 파일로 작성해서 --vault-password-file 인자로 넣어주는 방법 외에 다른 여러 방법으로 시도해보았지만 내가 못하는건지 안되는 것 같다(아시는분 댓글 부탁드립니다)

 

 

 

- 계정 생성 확인

for i in {1..3}; do ssh ubuntu@tnode$i tail -n 2 /etc/passwd; echo;done

=> 정상적으로 생성된 것을 확인할 수 있었다.

 

 


 

# 도전과제2

* Lookups 플러그인을 활용한 playbook를 직접 작성

 

Lookups — Ansible Documentation

Lookups Lookup plugins retrieve data from outside sources such as files, databases, key/value stores, APIs, and other services. Like all templating, lookups execute and are evaluated on the Ansible control machine. Ansible makes the data returned by a look

docs.ansible.com

=> lookup 플러그인은 playbook 내에서 외부 소스(file, db, key/value stores, APIs 등)에 접근하여 그 내용을 playbook내로 가져와서 사용할 수 있게 해주는 역할을 한다(Jinja2 템플릿 언어에 대한 Ansible 전용 확장 기능)

 

 

 

-  랜덤패스워드(문자,숫자,특수문자 3가지조합 + 10자리)를 가진 계정을 생성하는 playbook

---
- hosts: all
  tasks:
    - name: Generate and encrypt password
      set_fact:
        encrypted_password: "{{ lookup('ansible.builtin.password', '/home/ubuntu/my-ansible/pw.txt', chars=['ascii_letters', 'digits', 'punctuation'], length=10) | password_hash('sha512') }}"

    - name: Create user with encrypted password
      ansible.builtin.user:
        name: tmp_user
        comment: temp user
        shell: /bin/bash
        state: present # 삭제시 absent 사용
        password: "{{ encrypted_password }}"
      register: user_creation_result

    - name: Show generated password
      debug:
        var: user_creation_result.ansible_facts.user_password

=> playbook 내에 작성한 것과 같이 10자리의 랜덤패스워드가로 tmp_user가 생성되었고 해당 패스워드는 pw.txt 파일에서 확인할 수 있었다.

 


 

# 도전과제 3

* Ubuntu 와 CentOS에 apache http를 설치하는 playbook을 작성(롤/템플릿 사용은 편한대로)

=> centos에도 제대로 동작되는지 확인하기 위해 tnode4를 centos를 생성해주고 /etc/hosts와 inventory 파일에 내용을 추가해주었다. 해당 AMI의 경우 AWS marketplace를 통해 생성했다(실습 후 marketplace 구독취소를 해주었다)

 

 

# Roles(apache.http) 생성 및 정보

ansible-galaxy init --init-path ./roles apache.http

 

 

- handlers/main.yml

---
# handlers file for apache.http

- name: Start httpd 
  ansible.builtin.service:
    name: httpd
    state: started

 

 

- tasks/main.yml

---
# tasks file for apache.http

- name: Import playbook
  ansible.builtin.include_tasks:
    file: "{{ ansible_facts.distribution }}.yml"

- name: Copy index file when Ubuntu
  ansible.builtin.template:
    src: modify.html
    dest: /var/www/html/index.html
  when: ansible_facts.distribution == "Ubuntu"

- name: Copy index file when CentOS
  ansible.builtin.template:
    src: modify.html
    dest: /var/www/html/index.html
  when: ansible_facts.distribution == "CentOS"

 

 

- tasks/CentOS.yml

---

- name: Install the latest version of Apache in CentOS
  ansible.builtin.yum:
    name: httpd
    state: present
  notify: Start httpd  
  #when: ansible_facts.distribution == "CentOS"

 

 

 

- tasks/Ubuntu.yml

---

- name: Install the latest version of Apache in Ubuntu
  ansible.builtin.apt:
    name: apache2
    state: present
  #when: ansible_facts.distribution == "Ubuntu"

 

 

- templetes/modify.html

<h1> This is Apache server!! </h1>

 

 

- playbook.yml

---

- hosts: tnode
  roles:
    - role: apache.http

=> playbook 실행결과 ubuntu, centos에 따라 상이하게 apt, yum으로 apache, httpd package가 설치되었다(해당되지 않는 경우 skip됨을 알 수 있음). 상이하게 적용한 점은 ubuntu의 경우 자동으로 apache service가 실행되었으나 centos의 경우 service를 직접 실행해주어야했으므로 handler를 통해 serivce를 start 시켜주었다.

 

 

- 서비스 정상 실행 확인

for i in {1..4}; do ssh tnode$i 'hostname;curl -s 127.0.0.1';echo; done

=> 모든 관리노드에서 설정한 templates/modify.html 내용으로 service가 실행중임을 확인할 수 있었다.

 

 


 

# 도전과제4

* Jinja2 템플릿을 활용한 예시 playbook를 구글링하여 실습 환경에 맞게 구성(내용 추가 및 수정 중)

ansible-galaxy role init --init-path ./roles myrole.nginx

 

 

- handlers/main.yml

---
# handlers file for myrole.nginx

- name: Reload daemon
  systemd:
    daemon_reload: yes
- name: Restart nginx
  service:
    name: nginx
    state: restarted

 

 

- template/nginx.conf.j2

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 1024;  
}

http {
    sendfile on;
    #tcp_nopush on;
    #tcp_nodelay on;
    keepalive_timeout 65;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    #gzip on;

    server {
        listen 80 default_server;
        listen [::]:80 default_server;
        
        root /var/www/html;
        index index.html index.htm;
        
        server_name _;
        
        location / {
            try_files $uri $uri/ =404;
        }
    }
}

 

 

- var/main.yml

---
# vars file for myrole.nginx
user: imyoungho

 

 

- tasks/main.yml

---
# tasks file for myrole.nginx

- name: apt update
  apt:
    update_cache: yes

- name: Add User for Nginx
  user:
    name: "{{ user }}"
    shell: /bin/bash
    home: /home/{{ user }}
    createhome: yes

- name: Install Nginx
  apt:
    name: nginx
    state: present

- name: Copy Nginx Configuration
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
  notify:
    - Reload daemon
    - Restart nginx

 

 

- playbook file(install_nginx.yml)

---
      
- hosts: tnode3
  vars_files:
    - vars/main.yml
  roles:
    - role: myrole.nginx
      become: yes

 

 


 

# 도전과제5

* file과 lineinfile 모듈을 활용하여 /tmp/test.txt 파일을 생성하고 hello 문자열을 추가하는 playbook 작성

 

 

- work.yml

---

- hosts: all
  vars_files: var.yml

  tasks: 
  - name: Create file
    ansible.builtin.file:
      path: "{{ item.filepath }}"
      owner: "{{ item.own }}"
      group: "{{ item.own }}"
      mode: "{{ item.permit }}"
      state: touch
    loop: "{{ fileinfo }}"

  - name: Write String in file
    ansible.builtin.lineinfile:
      path: "{{ item.filepath }}"
      line: "{{ item.string }}"
    loop: "{{ fileinfo }}"

 

 

- var.yml

fileinfo:
  - string: hello
    own: ubuntu
    filepath: /tmp/test.txt
    permit: 644
    
  - string: byebye
    own: ubuntu
    filepath: /tmp/test2.txt
    permit: 644

 

 

- 결과

for i in {1..3}; do ssh tnode1 ls /tmp/*.txt;echo; done
for i in {1..3}; do ssh tnode1 cat /tmp/*.txt;echo; done

 


# 도전과제6

* 앤서블 갤럭시에서 PostgreSQL 설치하는 롤을 검색하여, 해당 롤을 통해 tnode3에 설치

 

Ansible Galaxy

 

galaxy.ansible.com

 

* postgreSQL role install

- ansible.cfg file

[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

 

 

- inventory file

[db]
tnode3

[tnode]
tnode1
tnode2
tnode3

 

 

- ansible-galaxy를 통한 role install

 

Ansible Galaxy

 

galaxy.ansible.com

ansible-galaxy role install geerlingguy.postgresql

 

 

 

- playbook file (install_postgresql.yml)

- hosts: tnode3
  vars_files:
    - vars/main.yml
  roles:
    - role: geerlingguy.postgresql
      become: yes

 

 

- var/main.yml

postgresql_databases:
  - name: imyoungho_db
postgresql_users:
  - name: imyoungho
    password: qwe123

 

 

* playbook 실행

ansible-playbook install_postgresql.yml

 

 

- postgreSQL 접속

psql -U imyoungho -d imyoungho_db -h localhost -p 5432

=> tnode3에 위에서 설정한 var/main.yml 설정으로 postgresql이 구축되었으며 정상적으로 접속까지 가능한 것을 확인할 수 있었다.

반응형