Skip to content

Ansible Level 04 Day 02: Create Users and Groups

This document outlines the solution for Ansible Level 04 Day 02. The objective was to onboard new team members by creating user accounts, assigning them to specific groups (admins and developers), setting custom home directories, and securely applying passwords using Ansible Vault.

Table of Contents

  1. Task Overview
  2. Step-by-Step Solution
  3. Deep Dive: Ansible Concepts Used

Task Overview

Objective: Create users and groups on App Server 2 (stapp02) based on a provided YAML list, applying specific constraints and secure passwords.

Requirements: 1. Target: App Server 2. 2. Groups to Create: developers and admins. 3. Data Source: ~/playbooks/data/users.yml (contains lists of users for each group). 4. Developers Group: * Home Directory: /var/www (exact path, not /var/www/user). * Password: Rc5C9EyvbU (Must be encrypted). 5. Admins Group: * Home Directory: Default (/home/{USER}). * Password: YchZHRcLkL (Must be encrypted). * Privileges: Must be added to the wheel group for sudo access. 6. Vault: Use ~/playbooks/secrets/vault.txt as the vault password file. Configure ansible.cfg to use this file automatically. 7. Playbook: ~/playbooks/add_users.yml. Must run with ansible-playbook -i inventory add_users.yml.


Step-by-Step Solution

1. Configure Ansible for Vault

Since the validation script will run the playbook without the --vault-password-file argument, we must configure Ansible to find the vault password automatically.

Command:

cd ~/playbooks
vi ansible.cfg

Content:

[defaults]
inventory = ./inventory
vault_password_file = ./secrets/vault.txt
(Ensure you preserve any other existing settings in the file if they were already there, just add/modify the vault_password_file line).

2. Encrypt the Passwords

Instead of writing plain text passwords in our playbook, we will create a dedicated secrets file, encrypt it with Ansible Vault, and load it into our playbook.

Create the secrets file:

vi secrets.yml

Initial Content (Plain Text):

dev_pass_plain: "Rc5C9EyvbU"
admin_pass_plain: "YchZHRcLkL"

Encrypt the file: Run the following command. Because we configured ansible.cfg in Step 1, Ansible will automatically use vault.txt to encrypt this file without prompting you for a password.

ansible-vault encrypt secrets.yml
(If you cat secrets.yml now, you will see it is fully encrypted with $ANSIBLE_VAULT headers).

3. Create the Playbook

Now we construct the playbook. We use vars_files to pull in the user lists from data/users.yml and the encrypted passwords from secrets.yml.

Note: The structure of data/users.yml typically defines two lists: developers: and admins:. We will loop over these.

Command:

vi add_users.yml

Content:

---
- name: Create Users and Groups for Nautilus Project
  hosts: stapp02
  become: yes
  vars_files:
    - data/users.yml
    - secrets.yml
  tasks:
    - name: Create developers group
      group:
        name: developers
        state: present

    - name: Create admins group
      group:
        name: admins
        state: present

    - name: Add users to developers group
      user:
        name: "{{ item }}"
        group: developers
        home: /var/www
        password: "{{ dev_pass_plain | password_hash('sha512') }}"
        state: present
      loop: "{{ developers }}"
      # Note: If your users.yml nests them under a parent key (e.g., users: developers:), 
      # adjust this loop to "{{ users.developers }}"

    - name: Add users to admins group
      user:
        name: "{{ item }}"
        group: admins
        groups: wheel
        append: yes
        password: "{{ admin_pass_plain | password_hash('sha512') }}"
        state: present
      loop: "{{ admins }}"
      # Note: Adjust to "{{ users.admins }}" if nested under a parent 'users' key.

4. Execute and Validate

Run the playbook. Thanks to our ansible.cfg, we don't need any extra arguments.

Execution Command:

ansible-playbook -i inventory add_users.yml

Expected Output: You should see tasks executing successfully, creating groups, and dynamically looping over the lists to create the users.


Deep Dive: Ansible Concepts Used

Ansible Vault & ansible.cfg

Storing plain text passwords in Git or playbooks is a massive security risk. Ansible Vault encrypts variables and files. By defining vault_password_file in ansible.cfg, you streamline automation. The CI/CD pipeline (or the validation script, in this case) just needs access to that file to decrypt on the fly, keeping the execution command perfectly clean.

Password Hashing in Ansible

The Ansible user module's password parameter does not accept plain text passwords. If you pass plain text, Linux will literally store that text in /etc/shadow, rendering the account un-loggable because the system expects a hash there. By applying the Jinja2 filter | password_hash('sha512'), Ansible takes our decrypted plain-text string from the vault, hashes it using the SHA-512 algorithm, and feeds the resulting secure hash to the Linux system.

Loading Variable Files (vars_files)

Instead of hardcoding lists of users inside the playbook, we imported an external data file (data/users.yml). This is excellent practice because it separates Data from Logic. If HR hires a new developer tomorrow, you only update users.yml—the playbook logic (add_users.yml) remains completely untouched.