The role changed a lot and none of it was verified against a real system so far. The scenario starts one container per supported distribution family, applies the role and asserts afterwards that the users and groups exist as declared, that the managed files carry the documented mode, owner and content, that a user without optional settings does not receive any of the optional files and that a user declared as absent is gone again. The idempotence step is the actual reason for the scenario. The deterministic password salt and the btrfs device lookup were changed to stop reporting a change on every run, and only a second converge proves that. A btrfs home is not covered, because a container has no btrfs filesystem to create a subvolume on. The ssh key pair the scenario feeds into the role is generated during create and removed again during destroy, so no private key material ends up in the repository. The generated files are ignored for the case that a destroy never runs. Co-authored-by: Copilot <copilot@github.com>
246 lines
7.2 KiB
Markdown
246 lines
7.2 KiB
Markdown
# volker-raschek.unix-users
|
|
|
|

|
|
|
|
The ansible role `volker-raschek.unix-users` create and manage users on Linux based distributions. For example for Arch
|
|
Linux, Fedora and Ubuntu. Furthermore, the role can also be used to create groups, `~/.forward`, `~/.netrc` and to
|
|
manage the `~/.ssh` directory.
|
|
|
|
## Requirements
|
|
|
|
The role requires `ansible-core` 2.11 or newer. A home directory can optionally be created as btrfs subvolume, which
|
|
relies on the `btrfs_subvolume` module of the collection `community.general`.
|
|
|
|
```bash
|
|
ansible-galaxy collection install -r requirements.yml
|
|
```
|
|
|
|
The role manages users, groups and their home directories, so it has to be executed with `become: true`.
|
|
|
|
## Tests
|
|
|
|
The role is tested with [Molecule](https://ansible.readthedocs.io/projects/molecule/). The scenario starts one docker
|
|
container per supported distribution family, applies the role, asserts that a second run reports no change and finally
|
|
verifies the created users and groups, the permissions and the content of the managed files and that a user declared
|
|
as `absent` is gone again. A btrfs home is not covered, because a container has no btrfs filesystem to create a
|
|
subvolume on.
|
|
|
|
The ssh key pair the scenario feeds into the role is generated during `molecule create` and removed again during
|
|
`molecule destroy`, so no private key is kept in the repository.
|
|
|
|
Molecule ships only its `default` driver, therefore `docker` is required besides molecule itself. The collections are
|
|
declared in `molecule/default/collections.yml` and installed by molecule.
|
|
|
|
```bash
|
|
pip install molecule docker
|
|
```
|
|
|
|
The complete sequence creates the containers, tests them and removes them afterwards.
|
|
|
|
```bash
|
|
molecule test
|
|
```
|
|
|
|
While working on the role the containers are better kept alive.
|
|
|
|
```bash
|
|
# create the containers and apply the role
|
|
molecule converge
|
|
|
|
# run the assertions of molecule/default/verify.yml against the running containers
|
|
molecule verify
|
|
|
|
# open a shell in one of the containers
|
|
molecule login --host unix-users-debian
|
|
|
|
# remove the containers
|
|
molecule destroy
|
|
```
|
|
|
|
## Examples
|
|
|
|
### User and group
|
|
|
|
The following example create the user `toor` and group `toor`. Booth with a specific id.
|
|
|
|
```yaml
|
|
unix_groups:
|
|
toor:
|
|
gid: "1001"
|
|
state: present
|
|
|
|
unix_users:
|
|
toor:
|
|
state: present
|
|
name: Toor
|
|
uid: "1000"
|
|
home: /home/toor
|
|
shell: /bin/bash
|
|
password: toor
|
|
group: toor
|
|
```
|
|
|
|
### Btrfs home dir
|
|
|
|
Optionally, the home directory of a user can also be created as dedicated btrfs subvolume. This make it possible to
|
|
create snapshots of the home directory, for example via `btrbk`.
|
|
|
|
> [!WARNING]
|
|
> Removing a user with `state: absent` also deletes the btrfs subvolume of the home directory. Snapshots taken from that
|
|
> subvolume are not removed and keep the data available.
|
|
|
|
```yaml
|
|
unix_users:
|
|
toor:
|
|
state: present
|
|
name: Toor
|
|
uid: "1000"
|
|
home: /home/toor
|
|
btrfs: true
|
|
shell: /bin/bash
|
|
password: toor
|
|
group: toor
|
|
```
|
|
|
|
### .netrc
|
|
|
|
The ansible role supports the creation and management of the `.netrc` file in a user's home directory. The `.netrc` file
|
|
for the user `toor` is created below. This contains entries for GitHub.
|
|
|
|
```yaml
|
|
unix_users:
|
|
toor:
|
|
state: present
|
|
name: Toor
|
|
uid: "1000"
|
|
home: /home/toor
|
|
netrc:
|
|
- machine: github.com
|
|
login: octocat
|
|
password: pat_12345
|
|
- machine: api.github.com
|
|
login: octocat
|
|
password: pat_12345
|
|
shell: /bin/bash
|
|
password: toor
|
|
group: toor
|
|
```
|
|
|
|
### .ssh
|
|
|
|
The SSH client directory `~/.ssh` can also be managed via the Ansible role. This supports the creation and management of
|
|
`~/.ssh/config`, `~/.ssh/authorized_keys` as well as the maintenance of private and public SSH keys.
|
|
|
|
The following example create two entries in `~/.ssh/authorized_keys`. One normal SSH access for `claire`. If `bob`
|
|
establish a SSH connection the command `/usr/local/bin/upload-file.sh` will be executed and exited. Furthermore,
|
|
environment variables can be espcilitly defined, to consume it during execution of the command.
|
|
|
|
> [!IMPORTANT]
|
|
> To allow consuming environment variables must be set `PermitUserEnvironment yes` in `/etc/ssh/sshd_config`.
|
|
|
|
The private key `toor@toor-pc.ed25519.key` must be stored in `ssh/private_keys`. The public key will be automatically
|
|
extracted from the private key.
|
|
|
|
The public keys `claire@claire-pc.pub` as well as `bob@bob-pc.pub` must be stored in `ssh/authorized_keys`.
|
|
|
|
```yaml
|
|
unix_users:
|
|
toor:
|
|
state: present
|
|
name: Toor
|
|
uid: "1000"
|
|
home: /home/toor
|
|
ssh:
|
|
config:
|
|
- Host: "*"
|
|
StrictHostKeyChecking: "no"
|
|
UserKnownHostFile: /dev/null
|
|
authorized_keys:
|
|
- filename: claire@claire-pc.pub
|
|
- command: /usr/local/bin/upload-file.sh
|
|
envs:
|
|
- key: SSH_KEY_NAME
|
|
value: bob@bob-pc
|
|
filename: bob@bob-pc.pub
|
|
private_keys:
|
|
- toor@toor-pc.ed25519.key
|
|
shell: /bin/bash
|
|
password: toor
|
|
group: toor
|
|
```
|
|
|
|
### .forward
|
|
|
|
If on the system is postfix installed, postfix will respect the `~/.forward`
|
|
[file](https://www.postfix.org/local.8.html). This allows to forward local emails to external email addresses. The
|
|
following example create the `~/.forward` file for `toor` to forward emails to `toor@company.example.local`.
|
|
|
|
```yaml
|
|
unix_users:
|
|
toor:
|
|
state: present
|
|
name: Toor
|
|
uid: "1000"
|
|
home: /home/toor
|
|
email: toor@company.example.local
|
|
shell: /bin/bash
|
|
password: toor
|
|
group: toor
|
|
```
|
|
|
|
### shell_rc files
|
|
|
|
The role also supports the creation of bashrc drop-in files. These are created in `~/.bashrc.d` and included by
|
|
`~/.bashrc` via `source`.
|
|
|
|
Program-related configurations can be made via a drop-in file. For example, the configuration of the bash history via
|
|
the environment variables `HISTCONTROL` or `HISTFILE`. In addition to environment variables, aliases and complete
|
|
functions can also be defined.
|
|
|
|
```yaml
|
|
unix_users:
|
|
toor:
|
|
state: present
|
|
name: Toor
|
|
uid: "1000"
|
|
home: /home/toor
|
|
email: toor@company.example.local
|
|
shell: /bin/bash
|
|
shell_rc_files:
|
|
- file: "/home/toor/.bashrc.d/10-docker.bashrc" # absolute or relative path to home dir
|
|
aliases:
|
|
- key: "dcd"
|
|
value: "docker-compose down"
|
|
envs:
|
|
- export: true
|
|
key: "PATH"
|
|
value: "/home/toor/workspace/docker-compose/bin:${PATH}" # Add local compiled docker-compose into $PATH
|
|
functions:
|
|
- name: "foo"
|
|
value: |
|
|
if ! which docker 1> /dev/null; then
|
|
echo "ERROR: docker not found" 1>&2
|
|
exit 1
|
|
fi
|
|
password: toor
|
|
group: toor
|
|
```
|
|
|
|
## Further ansible roles
|
|
|
|
This ansible role is used in combination with other ansible roles of `volker-raschek`. You can search for the other
|
|
ansible roles via the following command.
|
|
|
|
```bash
|
|
$ ansible-galaxy role search --author "volker-raschek"
|
|
|
|
Found roles matching your search:
|
|
|
|
Name Description
|
|
---- -----------
|
|
volker-raschek.bind9 Role to install and configure bind9 on different distributions
|
|
volker-raschek.dhcpd Role to install and configure dhcpd on different distributions
|
|
volker-raschek.renovate Role to configure renovate as container image
|
|
...
|
|
```
|