cogini.users
Users
This Ansible role is designed to manage user accounts and control access using SSH keys.
It is used to deploy one or more applications on a server. This role helps create accounts for app deployment, as well as for system admins and developers.
It essentially serves as a helpful guide for the Ansible user module.
User Types
The role allows the creation of the following user account types:
- Global System Admins / Ops Team
These users have their own logins on the server with permissions to use sudo. They are added to the wheel
or admin
group and allowed to use sudo without entering a password.
When we set up a server, the accounts for our system admin team are created automatically, regardless of the project.
- Project Admins / Power Users
These users have the same privileges as global admins but are set up per project or server. This is managed using inventory host/group variables. Usually, the tech lead for the project will have admin privileges.
- Deploy Account
This user account is responsible for deploying the application to the server. It owns the necessary application files and has write access to the deployment and configuration directories.
Neither the app nor deploy accounts have sudo permissions unless specified in a sudoers file that allows them to run specific commands (like starting the app). This is managed by the role that installs and configures the app.
For instance, create a file like /etc/sudoers.d/deploy-foo
:
deploy ALL=(ALL) NOPASSWD: /bin/systemctl start foo, /bin/systemctl stop foo, /bin/systemctl restart foo, /bin/systemctl status foo
- App Account
This account runs the application.
It has write access to necessary runtime directories, such as logs, and has read-only access to its code and configuration files.
- Developers
Developers may need access to the deploy or app accounts to check logs and debug. We add their SSH keys to these accounts, enabling SSH login.
- Project Users
These users are similar to admins but don’t have sudo access. An example would be a customer account that allows logging in to execute queries against the database without needing admin rights. Permissions can be granted, such as access to app log files, by adding them to the app group and modifying file permissions.
Configuration
By default, this role does nothing. You must add configuration variables for it to function. This can be done through group variables (e.g., inventory/group_vars/app_servers
), a vars
section in a playbook, or a combination.
You can set different options for hosts or groups, like allowing developer access in the dev environment but not in production.
App Accounts
The account that deploys the application. This is optional; if not specified, the deploy user will not be created.
users_deploy_user: deploy
users_deploy_group: deploy
The account that runs the app. This is also optional; if not specified, the app user will not be created.
users_app_user: foo
users_app_group: foo
User Accounts
The users_users
field defines Unix account names and SSH keys for users.
It is a list of dictionaries, containing four fields:
user
: Unix account namename
: User's name (optional, for documentation).key
: SSH public key file (place these in your playbook'sfiles
directory).github
: User's GitHub ID. The role fetches user keys fromhttps://github.com/{{ github }}.keys
Example:
users_users:
- user: jake
name: "Jake Morrison"
github: reachfh
- user: ci
name: "CI server"
key: ci.pub
Lists of Users
After defining accounts in users_users
, configure lists of users using the IDs specified in the user
key. By default, these lists are empty, so if you don’t specify users, they won’t be created.
Global admin users with separate Unix accounts and sudo permissions:
users_global_admin_users:
- jake
Project-level admin users:
users_admin_users:
- fred
Project users without sudo permission:
users_regular_users:
- bob
Users with SSH keys who can access the deploy account:
users_deploy_users:
- ci
Users who can access the app account:
users_app_users:
- fred
Group Configuration
You can specify additional groups that different user types will belong to. By default, these lists are empty, but they can help tailor access to the app.
Typically, we configure SSH so that a user must be in an sshusers
group to log in.
Add this to /etc/ssh/sshd_config
:
AllowGroups sshusers sftpusers
Then, include sshusers
in users_admin_groups
, for example:
users_admin_groups:
- sshusers
Unix Groups for Admin Users
The role will always add users to the wheel
or admin
group, depending on the system. If admin users are defined, it sets up sudo permissions in the /etc/sudoers.d/00-admin
file, allowing admin users to use sudo without a password.
users_admin_groups:
- sshusers
Unix Groups for Regular Users:
users_regular_groups:
- sshusers
Unix Groups for the Deploy User:
users_deploy_groups:
- sshusers
Unix Groups for the App User:
users_app_groups:
- sshusers
Deleting Users
This role tracks users it creates by including "ansible-" in their comment. This allows it to manage user additions and deletions easily.
You can also specify accounts to delete in the users_delete_users
list. This is useful for cleaning up outdated accounts.
You can decide whether to remove the user's home directory when deleting an account using users_delete_remove
and users_delete_force
variables. For safety, these are set to no
by default, but if you’re using this role to manage system users, you may want to change them to yes
.
users_delete_remove: yes
users_delete_force: yes
The role can also optionally remove authorized keys from system users like 'root' or 'ubuntu' for security, preventing backup of root keys once named admin users are set up.
users_remove_system_authorized_keys: true
Setup
The usual practice is to run this role first on a new instance. This creates admin users and sets up their keys, allowing them to run other roles that configure the server. A project-specific role prepares the server for the app by creating directories and installing dependencies. Normally, we deploy the app from a build or CI server without sudo, using the deploy
user account.
Here is a typical playbook:
- name: Manage users
hosts: '*'
vars:
users_app_user: foo
users_app_group: foo
users_deploy_user: deploy
users_deploy_group: deploy
users_users:
- user: jake
name: "Jake Morrison"
github: reachfh
users_app_users:
- jake
users_deploy_users:
- jake
roles:
- { role: cogini.users, become: true }
Add the host to the inventory/hosts
file.
[web-servers]
web-server-01
Add the host to .ssh/config
or a project-specific ssh.config
file.
Host web-server-01
HostName 123.45.67.89
For a physical server where we start with a root account and no SSH keys, we need to bootstrap the server the first time, providing the password with -k.
ansible-playbook -k -u root -v -l web-server-01 playbooks/manage-users.yml --extra-vars "ansible_host=123.45.67.89"
On macOS, the -k command requires the askpass utility, which isn't installed by default, so it falls back to paramiko. This method doesn't recognize .ssh/config
, so we specify ansible_host
manually.
On subsequent runs, after setting up the admin users, use:
ansible-playbook -u $USER -v -l web-server-01 playbooks/manage-users.yml
Deleting Legacy Users
Define legacy user accounts for deletion in the users_delete_users
list, for example:
ansible-playbook -u $USER -v -l web-servers playbooks/manage-users.yml --extra-vars "users_delete_users=[fred] users_delete_remove=yes users_delete_force=yes"
License
MIT
Author Information
Jake Morrison at Cogini