Ansible has made automation simple and it has become the universal automation language. By now, the benefits are well-known in the IT community. Like all good technologies, however, there can be challenges to face or approaches to combine. Consider using comma-separated value (CSV) files and Ansible to create Linux user accounts.

In this article, the goal is to automate user creation using Ansible. A list of users can be passed via an external variable file using vars_files or directly into the playbook using a loop. The problem arises when the list of users to be created is only available in a format like CSV while the Ansible developer is more comfortable using a YAML list. I personally have experienced situations where a user list including passwords is provided in a CSV file with the requirement to create those users on multiple Linux machines using an automation tool such as Ansible.

[ You might also like: Automate virtual machine deployment with Ansible: Design ]

What is the solution?

Fortunately, Ansible ships with more than a thousand modules, including one for reading CSV files. This module can provide exactly what's needed for this task. You'll see the module in action below.

Consider the CSV file that includes multiple fields such as Username, UID, First Names, Last Names, Groups, and Password shown below. The requirement is to create all these users with their relevant information across multiple Linux servers. 

Username,UID,First_name,Last_name,Groups,Password
booker12,9012,Rachel,Booker,Operations,iambooker
grey07,2070,Laura,Grey,Developers,iamgrey
johnson81,4081,Craig,Johnson,Operations,iamjohnson
jenkins46,9346,Mary,Jenkins,Developers,iamjenkins
smith79,5079,Jamie,Smith,Operations,iamsmith

Step 1

Now that you have a CSV file, the next step is to get Ansible to read this CSV file. To achieve this, use the read_csv module. To print how Ansible has parsed the CSV, use the debug module. Notice the use of delegate_to: localhost in the first task. This is because the file username.csv is present on the control-node and not the managed-hosts. Ansible parses this CSV in a list format with multiple dictionaries inside. That is why you need to add the sub-variable list to the end of your original registered variable user_list.

---
- name: create users from csv file
  hosts: all
  tasks:
   - name: reading the csv file
     read_csv:
      path: username.csv
     register: user_list
     delegate_to: localhost

   - name: display user_list data
     debug:
      var: user_list.list

Step 2

As you run this playbook, you'll see that the output contains a list, as indicated by the pair of box brackets. This list further includes a dictionary, which is indicated by the curly brackets. Every row in the CSV file has been converted into a dictionary, based on the comma separation between them. A dictionary is used to store data in a pair of keys and values. For example, the key is First_name, and the value is Rachel.

ok: [192.168.0.3] => {
    "user_list.list": [
        {
            "First_name": "Rachel",
            "Groups": "Operations",
            "Last_name": "Booker",
            "Password": "iambooker",
            "UID": "9012",
            "Username": "booker12"
        },
        {
            "First_name": "Laura",
            "Groups": "Developers",
            "Last_name": "Grey",
            "Password": "iamgrey",
            "UID": "2070",
            "Username": "grey07"
        },
        {
            "First_name": "Craig",
            "Groups": "Operations",
            "Last_name": "Johnson",
            "Password": "iamjohnson",
            "UID": "4081",
            "Username": "johnson81"
        },
      -------OUTPUT OMITTED-------
        }
    ]
}

Step 3

You're successfully able to read and print the CSV file via Ansible. Now it's time to try extracting one of these values to see if you can manipulate this dictionary to suit the needs of the user module in Ansible. Try something basic like extracting the value of the Username key for all the dictionaries inside this list. To do this, you'll use the dictionary's Username key as a sub-variable for your Ansible loop.

----OUTPUT OMITTED----
- name: extract Username from all dictionaries
  debug:
    msg: "{{ item.Username }}"
    loop: "{{ user_list.list }}"

ok: [192.168.0.3] => (item={'Username': 'booker12', 'UID': '9012', 'First_name': 'Rachel', 'Last_name': 'Booker', 'Groups': 'Operations', 'Password': 'iambooker'}) => {
    "msg": "booker12"
}
ok: [192.168.0.3] => (item={'Username': 'grey07', 'UID': '2070', 'First_name': 'Laura', 'Last_name': 'Grey', 'Groups': 'Developers', 'Password': 'iamgrey'}) => {
    "msg": "grey07"
}
----OUTPUT OMITTED----

As you can see here, you've extracted the Username values from the dictionaries. Using the same concept, you can put these values in the name field of the user module to create the users.

Step 4

Now that you've extracted the value of the desired key, you should be able to work with all the key and value pairs. Put them in the user module to create your users with all the required information. Notice the password option of the user module. It contains a filter to encrypt the Password value using the SHA-512 algorithm. This is done because RHEL8 uses SHA-512 to encrypt user passwords. This password is stored in an encrypted format in the /etc/shadow file on the managed-hosts. Also, the comment option contains two variables because you want the GECOS (User comments) field of the user to have their first name and last name. For example, the user booker12 will have their GECOS as "Rachel Booker." Furthermore, you're using privilege escalation in this task because user creation requires root privileges.

-----OUTPUT OMITTED-----  
- name: create users from the csv
  user:
    name: "{{ item.Username }}"
    uid: "{{ item.UID }}"
    groups: "{{ item.Groups }}"
    append: true
    password: "{{ item.Password | password_hash('sha512') }}"
    comment: "{{ item.First_Name }} {{ item.Last_Name }}"
    state: present
  loop: "{{ user_list.list }}"
  become: true

[ A free course for you: Virtualization and Infrastructure Migration Technical Overview. ] 

Wrap up

You successfully created the given users with their UID, Groups, Password, and GECOS by extracting the desired values from a CSV file. This comes in handy because most organizations use formats such as CSV to store and manage their data. An Ansible developer who can manipulate CSV files can efficiently manage their environment without writing everything from scratch directly into the playbook or an external variable YAML file. To effectively manage your environment further, I would recommend using Ansible Tower, which is the enterprise Ansible solution offered by Red Hat. Perhaps go for the DO447 - Advanced Automation: Ansible Best Practices training offering, as well.


저자 소개

Technological consultant and instructor for a Red Hat training partner based in India. Works on Ansible Tower, Red Hat Satellite, Python, and Ethical Hacking. Experience in delivering security and automation solutions as per business needs.

UI_Icon-Red_Hat-Close-A-Black-RGB

채널별 검색

automation icon

오토메이션

기술, 팀, 인프라를 위한 IT 자동화 최신 동향

AI icon

인공지능

고객이 어디서나 AI 워크로드를 실행할 수 있도록 지원하는 플랫폼 업데이트

open hybrid cloud icon

오픈 하이브리드 클라우드

하이브리드 클라우드로 더욱 유연한 미래를 구축하는 방법을 알아보세요

security icon

보안

환경과 기술 전반에 걸쳐 리스크를 감소하는 방법에 대한 최신 정보

edge icon

엣지 컴퓨팅

엣지에서의 운영을 단순화하는 플랫폼 업데이트

Infrastructure icon

인프라

세계적으로 인정받은 기업용 Linux 플랫폼에 대한 최신 정보

application development icon

애플리케이션

복잡한 애플리케이션에 대한 솔루션 더 보기

Virtualization icon

가상화

온프레미스와 클라우드 환경에서 워크로드를 유연하게 운영하기 위한 엔터프라이즈 가상화의 미래