[LINUX] Create multiple users with serial numbers at once with Ansible Playbook

Introduction

When creating multiple users with Ansible Playbook, it is normal to set the user name, UID, group name, etc. in the list variable in advance and create them all at once with the user module + loop.

However, if you create too many users, it is tedious to prepare the list variable.

I wish I had a playbook that could quickly create users with serial numbers, but I finally made a decent one, so I will leave it as a memorial.

Assumed case

Create a large number of serial number users, for example for developers.

environment

VirtualBox (+ vagrant) CentOS 7.7 ansible 2.9.6

Playbook

Again, to make the article easier to understand, I'll list it all in one Playbook ʻusercreate.yml`. (It's not that I don't know best practices. Just in case.)

First, prepare various variables at the beginning. In this example, we will create users with serial numbers from 01 to 20. See comments for a detailed explanation.

usercreate.yml


---
- name: Create many user
  hosts: localhost
  vars:
    #Create a character string by connecting 1 to 20 with commas. The end ends with a comma, but I'll do something about it later.
    user_num_data: "{% for n in range(20) %}{{n+1}},{% endfor %}"
    #Divide the variable created above with a comma and register it in the list variable. The last element is empty, but we'll do something about it later.
    user_num: "{{ user_num_data.split(',') }}"
    #The initial password for the user to create
    initialpw: zaq12wsx
    # UID/GID prefix. I will use the 5000 series.
    pre_id: 50
    #Username prefix.
    pre_name: devuser
    #It is a common group that registers all the users to be created.
    common_group: devgroup

Next is the task definition. First, create a common group. Create with 0, GID = 5000, which is not used by the user.

usercreate.yml


  tasks:
    - name: Common group is created
      group:
        name: '{{ common_group }}'
        gid: '{{ pre_id }}00'
        state: present

Next, create a group for each user to be created. Exclude the last empty element by setting the looping list variable to '{{user_num [: -1]}}'. Then, when using a serial number for a user name, etc., use ʻitem.zfill (2)` to align it to two digits.

usercreate.yml


    - name: Groups are created
      group:
        name: '{{ pre_name }}{{ item.zfill(2) }}'
        gid: '{{ pre_id }}{{ item.zfill(2) }}'
        state: present
      with_items:
        - '{{ user_num[:-1] }}'

Finally create a user.

usercreate.yml


    - name: Users are created
      user:
        name: '{{ pre_name }}{{ item.zfill(2) }}'
        group: '{{ pre_name }}{{ item.zfill(2) }}'
        groups: '{{ pre_name }}{{ item.zfill(2) }}, {{ common_group }}'
        uid: '{{ pre_id }}{{ item.zfill(2) }}'
        state: present
        password: "{{ initialpw | password_hash('sha512') }}"
        update_password: on_create
      with_items:
        - '{{ user_num[:-1] }}'
      register: usercreated

As a bonus, disable the password to prompt you to change the initial password. In the previous task, specify a condition with when to execute only when the user was created. Also, specify the label of loop_control to suppress the output when ansible-playbook is executed.

usercreate.yml


    - name: Passwords are expired
      shell: |
        passwd -e '{{ item.invocation.module_args.name }}'
      with_items:
        - '{{ usercreated.results }}'
      when:
        - item.changed
        - item.invocation.module_args.state == "present"

      loop_control:
        label: "{{ item.invocation.module_args.name }}"

Execution example

It is a normal execution result.

$ ansible-playbook -i inventories/test usercreate.yml 

PLAY [Create many user] ************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************
ok: [localhost]

TASK [Common group is created] *****************************************************************************************
changed: [localhost]

TASK [Groups are created] **********************************************************************************************
changed: [localhost] => (item=1)
changed: [localhost] => (item=2)
changed: [localhost] => (item=3)
changed: [localhost] => (item=4)
changed: [localhost] => (item=5)
changed: [localhost] => (item=6)
changed: [localhost] => (item=7)
changed: [localhost] => (item=8)
changed: [localhost] => (item=9)
changed: [localhost] => (item=10)
changed: [localhost] => (item=11)
changed: [localhost] => (item=12)
changed: [localhost] => (item=13)
changed: [localhost] => (item=14)
changed: [localhost] => (item=15)
changed: [localhost] => (item=16)
changed: [localhost] => (item=17)
changed: [localhost] => (item=18)
changed: [localhost] => (item=19)
changed: [localhost] => (item=20)

TASK [Users are created] ***********************************************************************************************
changed: [localhost] => (item=1)
changed: [localhost] => (item=2)
changed: [localhost] => (item=3)
changed: [localhost] => (item=4)
changed: [localhost] => (item=5)
changed: [localhost] => (item=6)
changed: [localhost] => (item=7)
changed: [localhost] => (item=8)
changed: [localhost] => (item=9)
changed: [localhost] => (item=10)
changed: [localhost] => (item=11)
changed: [localhost] => (item=12)
changed: [localhost] => (item=13)
changed: [localhost] => (item=14)
changed: [localhost] => (item=15)
changed: [localhost] => (item=16)
changed: [localhost] => (item=17)
changed: [localhost] => (item=18)
changed: [localhost] => (item=19)
changed: [localhost] => (item=20)

TASK [Passwords are expired] *******************************************************************************************
changed: [localhost] => (item=devuser01)
changed: [localhost] => (item=devuser02)
changed: [localhost] => (item=devuser03)
changed: [localhost] => (item=devuser04)
changed: [localhost] => (item=devuser05)
changed: [localhost] => (item=devuser06)
changed: [localhost] => (item=devuser07)
changed: [localhost] => (item=devuser08)
changed: [localhost] => (item=devuser09)
changed: [localhost] => (item=devuser10)
changed: [localhost] => (item=devuser11)
changed: [localhost] => (item=devuser12)
changed: [localhost] => (item=devuser13)
changed: [localhost] => (item=devuser14)
changed: [localhost] => (item=devuser15)
changed: [localhost] => (item=devuser16)
changed: [localhost] => (item=devuser17)
changed: [localhost] => (item=devuser18)
changed: [localhost] => (item=devuser19)
changed: [localhost] => (item=devuser20)

PLAY RECAP *************************************************************************************************************
localhost                  : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

If you look at / etc / passwd, it is beautifully created with serial numbers.

$ grep devuser /etc/passwd
devuser01:x:5001:5001::/home/devuser01:/bin/bash
devuser02:x:5002:5002::/home/devuser02:/bin/bash
devuser03:x:5003:5003::/home/devuser03:/bin/bash
devuser04:x:5004:5004::/home/devuser04:/bin/bash
devuser05:x:5005:5005::/home/devuser05:/bin/bash
devuser06:x:5006:5006::/home/devuser06:/bin/bash
devuser07:x:5007:5007::/home/devuser07:/bin/bash
devuser08:x:5008:5008::/home/devuser08:/bin/bash
devuser09:x:5009:5009::/home/devuser09:/bin/bash
devuser10:x:5010:5010::/home/devuser10:/bin/bash
devuser11:x:5011:5011::/home/devuser11:/bin/bash
devuser12:x:5012:5012::/home/devuser12:/bin/bash
devuser13:x:5013:5013::/home/devuser13:/bin/bash
devuser14:x:5014:5014::/home/devuser14:/bin/bash
devuser15:x:5015:5015::/home/devuser15:/bin/bash
devuser16:x:5016:5016::/home/devuser16:/bin/bash
devuser17:x:5017:5017::/home/devuser17:/bin/bash
devuser18:x:5018:5018::/home/devuser18:/bin/bash
devuser19:x:5019:5019::/home/devuser19:/bin/bash
devuser20:x:5020:5020::/home/devuser20:/bin/bash

The same applies to / etc / group.

$ grep dev /etc/group
devgroup:x:5000:devuser01,devuser02,devuser03,devuser04,devuser05,devuser06,devuser07,devuser08,devuser09,devuser10,devuser11,devuser12,devuser13,devuser14,devuser15,devuser16,devuser17,devuser18,devuser19,devuser20
devuser01:x:5001:devuser01
devuser02:x:5002:devuser02
devuser03:x:5003:devuser03
devuser04:x:5004:devuser04
devuser05:x:5005:devuser05
devuser06:x:5006:devuser06
devuser07:x:5007:devuser07
devuser08:x:5008:devuser08
devuser09:x:5009:devuser09
devuser10:x:5010:devuser10
devuser11:x:5011:devuser11
devuser12:x:5012:devuser12
devuser13:x:5013:devuser13
devuser14:x:5014:devuser14
devuser15:x:5015:devuser15
devuser16:x:5016:devuser16
devuser17:x:5017:devuser17
devuser18:x:5018:devuser18
devuser19:x:5019:devuser19
devuser20:x:5020:devuser20

The password is also expired.

$ sudo chage -l devuser01
Last password change					: password must be changed
Password expires					: password must be changed
Password inactive					: password must be changed
Account expires						: never
Minimum number of days between password change		: 0
Maximum number of days between password change		: 99999
Number of days of warning before password expires	: 7

If there are not enough users, you can re-execute the playbook by changing the following range (20) to range (40) etc., and the created users will not be affected and only the additional parts will be created. ..

user_num_data: "{% for n in range(20) %}{{n+1}},{% endfor %}"

With this, even if multiple teams with dozens of members are set up, don't miss it! is.

Recommended Posts

Create multiple users with serial numbers at once with Ansible Playbook
Create multiple users with serial numbers at once in Ansible Playbook: Part 2
Update multiple tables at once with pandas to_sql
Convert multiple proto files at once with python
Rsync multiple files at once
[Laravel] Aliase to create migration file of multiple tables at once
Replace all at once with sed
Create multiple line charts from a data frame at once using Matplotlib
Send newsletters all at once with Gmail
Get out of multiple loops at once