├── defaults └── main.yml ├── meta └── main.yml ├── LICENSE ├── .travis.yml ├── tasks └── main.yml ├── README.md └── tests └── test.yml /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Create a group for every user and make that their primary group 3 | users_create_per_user_group: true 4 | # If we're not creating a per-user group, then this is the group all users 5 | # belong to 6 | users_group: users 7 | # The default shell for a user if none is specified 8 | users_default_shell: /bin/bash 9 | # Create home dirs for new users? Set this to false if you manage home 10 | # directories in some other way. 11 | users_create_homedirs: true 12 | 13 | # Lists of users to create and delete 14 | users: [] 15 | users_deleted: [] 16 | 17 | # List of groups to create 18 | # Example: 19 | # groups_to_create: 20 | # - name: developers 21 | # gid: 10000 22 | groups_to_create: [] 23 | 24 | authorized_keys_file: ".ssh/authorized_keys" 25 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: Mark Harrison (Modified by SinglePlatform Engineering) 4 | description: User creation role 5 | license: MIT 6 | min_ansible_version: 1.3 7 | platforms: 8 | - name: EL 9 | versions: 10 | - all 11 | - name: GenericUNIX 12 | versions: 13 | - all 14 | - any 15 | - name: Fedora 16 | versions: 17 | - all 18 | - name: opensuse 19 | versions: 20 | - all 21 | - name: Ubuntu 22 | versions: 23 | - all 24 | - name: SLES 25 | versions: 26 | - all 27 | - name: GenericLinux 28 | versions: 29 | - all 30 | - any 31 | - name: Debian 32 | versions: 33 | - all 34 | galaxy_tags: 35 | - system 36 | 37 | dependencies: [] 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2013 Mark Harrison 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | sudo: required 3 | language: python 4 | python: "2.7" 5 | 6 | install: 7 | - pip install ansible 8 | 9 | # Add ansible.cfg to pick up roles path. 10 | - "{ echo '[defaults]'; echo 'roles_path = ../'; } >> ansible.cfg" 11 | 12 | script: 13 | # Syntax Check 14 | - ansible-playbook -i localhost, tests/test.yml --syntax-check 15 | 16 | # Run test.yml 17 | - ansible-playbook -i localhost, --connection=local -b tests/test.yml 18 | 19 | # Run the role/playbook again, checking to make sure it's idempotent. 20 | - > 21 | ansible-playbook -i localhost, --connection=local -b tests/test.yml 22 | | grep -q 'changed=0.*failed=0' 23 | && (echo 'Idempotence test: pass' && exit 0) 24 | || (echo 'Idempotence test: fail' && exit 1) 25 | 26 | # Lets check on the state of the users. I would invoke severspec myself however 27 | # its a big thing to bring in on a small pull. 28 | - id ansibletestuser | grep --silent "uid=2222(ansibletestuser) gid=2222(ansibletestuser) groups=2222(ansibletestuser),2(bin),100(users)" 29 | - id ansibletestuser2 | grep --silent "uid=2223(ansibletestuser2) gid=2223(ansibletestuser2) groups=2223(ansibletestuser2),2(bin),100(users)" 30 | - id ansibletestuser3 | grep --silent "uid=2224(ansibletestuser3) gid=4001(ansibletestgroup1) groups=4001(ansibletestgroup1),2(bin),100(users)" 31 | - id ansibletestuser4 | grep --silent "uid=2225(ansibletestuser4) gid=100(users) groups=100(users),2(bin)" 32 | - id ansibletestuser5 | grep --silent "uid=2226(ansibletestuser5) gid=4000(ansibletestgroup) groups=4000(ansibletestgroup),2(bin),100(users)" 33 | - grep --silent "^ansibletestgroup:" /etc/group 34 | - grep --silent "^ansibletestgroup1:" /etc/group 35 | - ls -lgd /home/ansibletestuser | awk '{exit $3!="ansibletestuser"}' 36 | - ls -lgd /home/otherdirectory | awk '{exit $3!="ansibletestuser2"}' 37 | - ls -lgd /home/ansibletestuser3 | awk '{exit $3!="ansibletestgroup1"}' 38 | - ls -lgd /home/otherdirectory1 | awk '{exit $3!="users"}' 39 | - ls -lgd /home/ansibletestuser5 | awk '{exit $3!="ansibletestgroup"}' 40 | - ls -lg /home/ansibletestuser/.profile | awk '{exit $3!="ansibletestuser"}' 41 | - ls -lg /home/otherdirectory/.profile | awk '{exit $3!="ansibletestuser2"}' 42 | - ls -lg /home/ansibletestuser3/.profile | awk '{exit $3!="ansibletestgroup1"}' 43 | - ls -lg /home/otherdirectory1/.profile | awk '{exit $3!="users"}' 44 | - ls -lgd /home/ansibletestuser5/.profile | awk '{exit $3!="ansibletestgroup"}' 45 | 46 | notifications: 47 | webhooks: https://galaxy.ansible.com/api/v1/notifications/ 48 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Creating groups 3 | group: 4 | name: "{{ item.name }}" 5 | gid: "{{ item.gid | default(omit) }}" 6 | with_items: "{{ groups_to_create }}" 7 | tags: ["users", "groups", "configuration"] 8 | 9 | - name: Per-user group creation 10 | group: 11 | name: "{{ item.username }}" 12 | gid: "{{ item.gid | default(item.uid) | default(omit) }}" 13 | with_items: "{{ users }}" 14 | when: "'group' not in item and users_create_per_user_group" 15 | tags: ["users", "configuration"] 16 | 17 | - name: User creation 18 | user: 19 | name: "{{ item.username }}" 20 | group: "{{ item.group | default(item.username if users_create_per_user_group else users_group) }}" 21 | # empty string removes user from all secondary groups 22 | groups: "{{ item.groups | join(',') if 'groups' in item else '' }}" 23 | append: "{{ item.append | default(omit) }}" 24 | shell: "{{ item.shell if item.shell is defined else users_default_shell }}" 25 | password: "{{ item.password if item.password is defined else '!' }}" 26 | comment: "{{ item.name if item.name is defined else '' }}" 27 | uid: "{{ item.uid | default(omit) }}" 28 | home: "{{ item.home | default('/home/' + item.username) }}" 29 | createhome: "{{ 'yes' if users_create_homedirs else 'no' }}" 30 | generate_ssh_key: "{{ item.generate_ssh_key | default(omit) }}" 31 | update_password: "{{ item.update_password | default(omit) }}" 32 | with_items: "{{ users }}" 33 | tags: ["users", "configuration"] 34 | 35 | - name: SSH keys 36 | authorized_key: 37 | user: "{{ item.0.username }}" 38 | key: "{{ item.1 }}" 39 | path: "{{ item.0.home | default('/home/' + item.0.username) }}/{{ authorized_keys_file }}" 40 | with_subelements: 41 | - "{{ users }}" 42 | - ssh_key 43 | - skip_missing: yes 44 | tags: ["users", "configuration"] 45 | 46 | - name: Setup user profiles 47 | blockinfile: 48 | block: "{{ item.profile }}" 49 | dest: "{{ item.home | default('/home/' + item.username) }}/.profile" 50 | owner: "{{ item.username }}" 51 | group: "{{ item.group | default(item.username if users_create_per_user_group else users_group) }}" 52 | mode: 0644 53 | create: true 54 | when: users_create_homedirs and item.profile is defined 55 | with_items: "{{ users }}" 56 | 57 | - name: Deleted user removal 58 | user: 59 | name: "{{ item.username }}" 60 | state: absent 61 | remove: "{{ item.remove | default(omit) }}" 62 | force: "{{ item.force | default(omit) }}" 63 | with_items: "{{ users_deleted }}" 64 | tags: ["users", "configuration"] 65 | 66 | - name: Deleted per-user group removal 67 | group: 68 | name: "{{ item.username }}" 69 | state: absent 70 | with_items: "{{ users_deleted }}" 71 | when: users_create_per_user_group 72 | tags: ["users", "configuration"] 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/singleplatform-eng/ansible-users.svg?branch=master)](https://travis-ci.org/singleplatform-eng/ansible-users) 2 | 3 | # ansible-users 4 | 5 | Role to manage users on a system. 6 | 7 | ## Role configuration 8 | 9 | * users_create_per_user_group (default: true) - when creating users, also 10 | create a group with the same username and make that the user's primary 11 | group. 12 | * users_group (default: users) - if users_create_per_user_group is _not_ set, 13 | then this is the primary group for all created users. 14 | * users_default_shell (default: /bin/bash) - the default shell if none is 15 | specified for the user. 16 | * users_create_homedirs (default: true) - create home directories for new 17 | users. Set this to false if you manage home directories separately. 18 | * authorized_keys_file (default: .ssh/authorized_keys) - Set this if the 19 | ssh server is configured to use a non standard authorized keys file. 20 | 21 | ## Creating users 22 | 23 | Add a users variable containing the list of users to add. A good place to put 24 | this is in `group_vars/all` or `group_vars/groupname` if you only want the 25 | users to be on certain machines. 26 | 27 | The following attributes are required for each user: 28 | 29 | * username - The user's username. 30 | * name - The full name of the user (gecos field). 31 | * home - The home directory of the user to create (optional, defaults to /home/username). 32 | * uid - The numeric user id for the user (optional). This is required for uid consistency 33 | across systems. 34 | * gid - The numeric group id for the group (optional). Otherwise, the 35 | uid will be used. 36 | * password - If a hash is provided then that will be used, but otherwise the 37 | account will be locked. 38 | * update_password - This can be either 'always' or 'on_create' 39 | - 'always' will update passwords if they differ. (default) 40 | - 'on_create' will only set the password for newly created users. 41 | * group - Optional primary group override. 42 | * groups - A list of supplementary groups for the user. 43 | * append - If yes, will only add groups, not set them to just the list in groups (optional). 44 | * profile - A string block for setting custom shell profiles. 45 | * ssh_key - This should be a list of SSH keys for the user (optional). Each SSH key 46 | should be included directly and should have no newlines. 47 | * generate_ssh_key - Whether to generate a SSH key for the user (optional, defaults to no). 48 | 49 | In addition, the following items are optional for each user: 50 | 51 | * shell - The user's shell. This defaults to /bin/bash. The default is 52 | configurable using the users_default_shell variable if you want to give all 53 | users the same shell, but it is different than /bin/bash. 54 | 55 | Example: 56 | 57 | --- 58 | users: 59 | - username: foo 60 | name: Foo Barrington 61 | groups: ['wheel','systemd-journal'] 62 | uid: 1001 63 | home: /local/home/foo 64 | profile: | 65 | alias ll='ls -lah' 66 | ssh_key: 67 | - "ssh-rsa AAAAA.... foo@machine" 68 | - "ssh-rsa AAAAB.... foo2@machine" 69 | groups_to_create: 70 | - name: developers 71 | gid: 10000 72 | users_deleted: 73 | - username: bar 74 | name: Bar User 75 | uid: 1002 76 | 77 | ## Deleting users 78 | 79 | The `users_deleted` variable contains a list of users who should no longer be 80 | in the system, and these will be removed on the next ansible run. The format 81 | is the same as for users to add, but the only required field is `username`. 82 | However, it is recommended that you also keep the `uid` field for reference so 83 | that numeric user ids are not accidentally reused. 84 | 85 | You can optionally choose to remove the user's home directory and mail spool with 86 | the `remove` parameter, and force removal of files with the `force` parameter. 87 | 88 | users_deleted: 89 | - username: bar 90 | uid: 1002 91 | remove: yes 92 | force: yes 93 | -------------------------------------------------------------------------------- /tests/test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | remote_user: root 4 | vars: 5 | groups_to_create: 6 | - name: ansibletestgroup 7 | gid: 4000 8 | users: 9 | - name: Ansible Test User 10 | username: ansibletestuser 11 | uid: 2222 12 | groups: [users, bin] 13 | shell: /bin/sh 14 | profile: | 15 | alias ll='ls -lah' 16 | alias cp='cp -iv' 17 | ssh_key: 18 | - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDVpUJQCOaPg3p5xro9e+1fkGRWNOGrrExiKMqTE91Fwu349bxfMnMzRS0PAERouR9EEL+Ee4Yzhav/uNc35eCtXzACtluXnAncMrQj6pM3IqASynhvXTygHljmcMbBSDQtLrTZeW+YzIcOgk5UM1yBi26WoUYva2aCr9IRvKdYreAK08OiMdZedpOye0ZdvIYJGcyITwc6YMmrAhP7jZlrk/mDEkf2a4eBp+475o7MJtaC9npqYkToM8vqvx5AGEKqXt7/f1/paOY7KsR+VGPQy6k2RkXjWBsXPesZ3d3XLZHE60wAk0EsuJO8A25+uWSB6ILQeRSYYmGea/WIf6kd noone@throwaway.example.com" 19 | 20 | roles: 21 | - ansible-users 22 | 23 | - hosts: localhost 24 | remote_user: root 25 | vars: 26 | users: 27 | - name: Ansible Test User2 28 | username: ansibletestuser2 29 | uid: 2223 30 | groups: [users, bin] 31 | shell: /bin/sh 32 | home: /home/otherdirectory 33 | profile: | 34 | alias ll='ls -lah' 35 | alias cp='cp -iv' 36 | ssh_key: 37 | - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDVpUJQCOaPg3p5xro9e+1fkGRWNOGrrExiKMqTE91Fwu349bxfMnMzRS0PAERouR9EEL+Ee4Yzhav/uNc35eCtXzACtluXnAncMrQj6pM3IqASynhvXTygHljmcMbBSDQtLrTZeW+YzIcOgk5UM1yBi26WoUYva2aCr9IRvKdYreAK08OiMdZedpOye0ZdvIYJGcyITwc6YMmrAhP7jZlrk/mDEkf2a4eBp+475o7MJtaC9npqYkToM8vqvx5AGEKqXt7/f1/paOY7KsR+VGPQy6k2RkXjWBsXPesZ3d3XLZHE60wAk0EsuJO8A25+uWSB6ILQeRSYYmGea/WIf6kd noone@throwaway.example.com" 38 | 39 | roles: 40 | - ansible-users 41 | 42 | - hosts: localhost 43 | remote_user: root 44 | vars: 45 | users_create_per_user_group: false 46 | users_group: ansibletestgroup 47 | groups_to_create: 48 | - name: ansibletestgroup1 49 | gid: 4001 50 | users: 51 | - name: Ansible Test User3 52 | username: ansibletestuser3 53 | uid: 2224 54 | group: ansibletestgroup1 55 | groups: [users, bin] 56 | shell: /bin/sh 57 | profile: | 58 | alias ll='ls -lah' 59 | alias cp='cp -iv' 60 | ssh_key: 61 | - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDVpUJQCOaPg3p5xro9e+1fkGRWNOGrrExiKMqTE91Fwu349bxfMnMzRS0PAERouR9EEL+Ee4Yzhav/uNc35eCtXzACtluXnAncMrQj6pM3IqASynhvXTygHljmcMbBSDQtLrTZeW+YzIcOgk5UM1yBi26WoUYva2aCr9IRvKdYreAK08OiMdZedpOye0ZdvIYJGcyITwc6YMmrAhP7jZlrk/mDEkf2a4eBp+475o7MJtaC9npqYkToM8vqvx5AGEKqXt7/f1/paOY7KsR+VGPQy6k2RkXjWBsXPesZ3d3XLZHE60wAk0EsuJO8A25+uWSB6ILQeRSYYmGea/WIf6kd noone@throwaway.example.com" 62 | 63 | roles: 64 | - ansible-users 65 | 66 | - hosts: localhost 67 | remote_user: root 68 | vars: 69 | users_create_per_user_group: false 70 | users_group: users 71 | users: 72 | - name: Ansible Test User4 73 | username: ansibletestuser4 74 | uid: 2225 75 | groups: [users, bin] 76 | shell: /bin/sh 77 | home: /home/otherdirectory1 78 | profile: | 79 | alias ll='ls -lah' 80 | alias cp='cp -iv' 81 | ssh_key: 82 | - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDVpUJQCOaPg3p5xro9e+1fkGRWNOGrrExiKMqTE91Fwu349bxfMnMzRS0PAERouR9EEL+Ee4Yzhav/uNc35eCtXzACtluXnAncMrQj6pM3IqASynhvXTygHljmcMbBSDQtLrTZeW+YzIcOgk5UM1yBi26WoUYva2aCr9IRvKdYreAK08OiMdZedpOye0ZdvIYJGcyITwc6YMmrAhP7jZlrk/mDEkf2a4eBp+475o7MJtaC9npqYkToM8vqvx5AGEKqXt7/f1/paOY7KsR+VGPQy6k2RkXjWBsXPesZ3d3XLZHE60wAk0EsuJO8A25+uWSB6ILQeRSYYmGea/WIf6kd noone@throwaway.example.com" 83 | 84 | roles: 85 | - ansible-users 86 | 87 | - hosts: localhost 88 | remote_user: root 89 | vars: 90 | users: 91 | - name: Ansible Test User5 92 | username: ansibletestuser5 93 | uid: 2226 94 | group: ansibletestgroup 95 | groups: [users, bin] 96 | shell: /bin/sh 97 | profile: | 98 | alias ll='ls -lah' 99 | alias cp='cp -iv' 100 | ssh_key: 101 | - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDVpUJQCOaPg3p5xro9e+1fkGRWNOGrrExiKMqTE91Fwu349bxfMnMzRS0PAERouR9EEL+Ee4Yzhav/uNc35eCtXzACtluXnAncMrQj6pM3IqASynhvXTygHljmcMbBSDQtLrTZeW+YzIcOgk5UM1yBi26WoUYva2aCr9IRvKdYreAK08OiMdZedpOye0ZdvIYJGcyITwc6YMmrAhP7jZlrk/mDEkf2a4eBp+475o7MJtaC9npqYkToM8vqvx5AGEKqXt7/f1/paOY7KsR+VGPQy6k2RkXjWBsXPesZ3d3XLZHE60wAk0EsuJO8A25+uWSB6ILQeRSYYmGea/WIf6kd noone@throwaway.example.com" 102 | 103 | roles: 104 | - ansible-users 105 | --------------------------------------------------------------------------------