Ansible user Module: สร้าง Delete User บนระบบ

Ansible user module ใช้จัดการ Linux account ครอบคลุมตั้งแต่การสร้าง, ลบ, แก้ไข home directory, ตั้งรหัสผ่าน, กำหนด group, ไปจนถึง SSH authorized keys โดยไม่ต้องใช้ command รัน useradd หรือ usermod ตรง ๆ ซึ่งมักไม่ idempotent

บทความนี้อธิบายการใช้ user module ครอบคลุม parameters หลัก, การสร้างและลบ account, การกำหนด group และ shell, การตั้งรหัสผ่าน, การจัดการ SSH key ด้วย authorized_key module และ pattern สำหรับ deploy บัญชีข้ามหลายเซิร์ฟเวอร์

user Module พื้นฐาน

user module ต้องการ parameter name เป็นอย่างน้อย และใช้ state ควบคุมว่าจะสร้าง (present) หรือลบ (absent) บัญชี

---
- name: Basic user module usage
  hosts: all
  become: true
  tasks:
    - name: Create user account
      user:
        name: deploy
        state: present

    - name: Create user with full options
      user:
        name: appuser
        state: present
        comment: "Application Service User"
        shell: /bin/bash
        home: /opt/appuser
        create_home: true

    - name: Remove user account
      user:
        name: olduser
        state: absent
        remove: true    # ลบ home directory และ mail spool ด้วย

module ตรวจสอบว่าบัญชีมีอยู่แล้วหรือไม่ก่อนดำเนินการ ถ้ามีอยู่แล้วและ state เป็น present จะไม่ทำอะไร — ทำให้ Playbook เป็น idempotent โดยอัตโนมัติ

Group — กำหนด Primary และ Supplementary Groups

ใช้ group สำหรับ primary group และ groups สำหรับ supplementary groups ส่วน append ควบคุมว่าจะเพิ่มหรือแทนที่ groups ที่มีอยู่

---
- name: User group management
  hosts: all
  become: true
  tasks:
    - name: Create account with specific primary group
      user:
        name: webmaster
        group: www-data        # primary group
        state: present

    - name: Add account to supplementary groups
      user:
        name: deploy
        groups: sudo,docker    # supplementary groups
        append: true           # เพิ่มเข้าไป ไม่แทนที่ groups เดิม
        state: present

    - name: Set exact groups (replace existing)
      user:
        name: svcuser
        groups: appgroup,loggroup
        append: false          # แทนที่ groups ทั้งหมด
        state: present

    - name: Add account to docker group
      user:
        name: "{{ ansible_user }}"
        groups: docker
        append: true
        state: present

ข้อสำคัญ: append: true เป็น idempotent — ถ้าบัญชีอยู่ใน group นั้นแล้วจะไม่ทำอะไร แต่ append: false จะ replace groups ทุกครั้งที่รัน ระวังการใช้

UID, Shell, และ Home Directory

กำหนด UID ตายตัวเพื่อให้ consistent ข้ามหลาย server โดยเฉพาะ NFS หรือ shared filesystem ที่ต้องการ UID ตรงกัน

---
- name: UID, shell and home management
  hosts: all
  become: true
  tasks:
    # กำหนด UID ตายตัว (สำคัญมากสำหรับ NFS/shared storage)
    - name: Create account with fixed UID
      user:
        name: appuser
        uid: 1500
        group: appgroup
        shell: /bin/bash
        home: /opt/appuser
        create_home: true
        state: present

    # system account ไม่มี login shell และไม่ต้อง home
    - name: Create system account (no login)
      user:
        name: mysql
        uid: 106
        system: true           # UID < 1000, ไม่มี home, ไม่มี password
        shell: /bin/false
        create_home: false
        state: present

    # เปลี่ยน shell ของบัญชีที่มีอยู่แล้ว
    - name: Change shell
      user:
        name: deploy
        shell: /bin/zsh
        state: present

    # ปิด login โดยตั้ง shell เป็น nologin
    - name: Disable login for service account
      user:
        name: svcaccount
        shell: /sbin/nologin
        state: present

ตั้งรหัสผ่าน

รหัสผ่านใน user module ต้องเป็น hashed password เท่านั้น ห้ามใส่ plain text โดยตรง ใช้ ansible.builtin.password_hash filter สำหรับ hash และเก็บ password ต้นฉบับใน Ansible Vault

---
- name: Password management
  hosts: all
  become: true
  vars:
    account_password: "{{ vault_account_password }}"   # เก็บใน Ansible Vault

  tasks:
    # ตั้งรหัสผ่านโดย hash ตอน runtime
    - name: Set password
      user:
        name: deploy
        password: "{{ account_password | password_hash('sha512') }}"
        state: present

    # ตั้งรหัสผ่านเฉพาะตอนสร้าง ไม่เปลี่ยนถ้ามีอยู่แล้ว
    - name: Set password only on creation
      user:
        name: newaccount
        password: "{{ 'InitialPass123!' | password_hash('sha512') }}"
        update_password: on_create   # ไม่เปลี่ยนถ้าบัญชีมีอยู่แล้ว
        state: present

    # ล็อค account (ใส่ ! นำหน้า hash)
    - name: Lock account
      user:
        name: suspendaccount
        password_lock: true
        state: present

    # บังคับ reset รหัสผ่านครั้งต่อไปที่ login
    - name: Force password change on next login
      user:
        name: newemployee
        password: "{{ 'TempPass!' | password_hash('sha512') }}"
        update_password: always
        state: present

ระวัง: ห้ามเขียน password plain text ใน Playbook โดยตรง — ใช้ ansible-vault encrypt ก่อนเสมอ และใช้ update_password: on_create เพื่อป้องกัน Ansible reset password ทุกครั้งที่รัน

authorized_key — จัดการ SSH Public Keys

authorized_key module ใช้ร่วมกับ user module เพื่อ deploy SSH public key ให้กับบัญชีต่าง ๆ ทำให้ login แบบ passwordless ได้อย่างปลอดภัยและ idempotent

---
- name: SSH key management
  hosts: all
  become: true
  tasks:
    # เพิ่ม SSH key จากไฟล์บน control node
    - name: Add SSH authorized key
      authorized_key:
        user: deploy
        state: present
        key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"

    # เพิ่ม key จาก variable
    - name: Add SSH key from variable
      authorized_key:
        user: deploy
        state: present
        key: "{{ deploy_ssh_public_key }}"

    # เพิ่มหลาย keys พร้อมกัน
    - name: Add multiple SSH keys
      authorized_key:
        user: deploy
        state: present
        key: "{{ item }}"
      loop: "{{ ssh_public_keys }}"

    # ลบ key ที่ไม่ต้องการออก
    - name: Remove SSH key
      authorized_key:
        user: oldaccount
        state: absent
        key: "{{ old_ssh_key }}"

Pattern: สร้าง Deploy Account ข้ามหลายเซิร์ฟเวอร์

ตัวอย่าง Playbook สร้างบัญชี deploy พร้อม SSH key, sudo access และ directory structure บน server ทุกตัวในคราวเดียว

---
- name: Create deploy account across all servers
  hosts: all
  become: true
  vars:
    deploy_name: deploy
    deploy_uid: 1500
    deploy_groups: "sudo,docker"
    deploy_ssh_key: "{{ lookup('file', '~/.ssh/deploy_rsa.pub') }}"

  tasks:
    - name: Create deploy group
      group:
        name: "{{ deploy_name }}"
        gid: "{{ deploy_uid }}"
        state: present

    - name: Create deploy account
      user:
        name: "{{ deploy_name }}"
        uid: "{{ deploy_uid }}"
        group: "{{ deploy_name }}"
        groups: "{{ deploy_groups }}"
        append: true
        shell: /bin/bash
        home: "/home/{{ deploy_name }}"
        create_home: true
        state: present

    - name: Add SSH key
      authorized_key:
        user: "{{ deploy_name }}"
        state: present
        key: "{{ deploy_ssh_key }}"

    - name: Allow passwordless sudo
      copy:
        content: "{{ deploy_name }} ALL=(ALL) NOPASSWD: ALL\n"
        dest: "/etc/sudoers.d/{{ deploy_name }}"
        owner: root
        group: root
        mode: '0440'
        validate: 'visudo -cf %s'

    - name: Create application directories
      file:
        path: "{{ item }}"
        state: directory
        owner: "{{ deploy_name }}"
        group: "{{ deploy_name }}"
        mode: '0755'
      loop:
        - /opt/apps
        - /var/log/apps

สรุป

user module เป็นวิธีที่ถูกต้องในการจัดการ Linux accounts ด้วย Ansible แทนการรัน useradd/usermod โดยตรง รองรับ state present/absent, การกำหนด UID, group, shell, home directory และ password ได้ในคำสั่งเดียว

Pattern ที่ควรจำ: ใช้ append: true เมื่อเพิ่ม supplementary groups เพื่อไม่ให้ลบ groups เดิม, ใช้ update_password: on_create เพื่อป้องกัน password reset ทุกรัน, เก็บ password ใน Ansible Vault เสมอ และใช้ authorized_key module ควบคู่กันสำหรับ SSH key management