Several defects accumulated in this task file and are fixed together, because they overlap in the same code paths.
The debug task was dead code. Its `msg` lacked the Jinja delimiters and would have printed the literal string
`_unix_users_btrfs_device.stdout`, and it was gated on `_unix_users_debug`, a variable that is neither defined in
defaults nor documented anywhere. It is removed instead of repaired, since the failure path already reports the device.
The four `ansible.builtin.user` tasks differed only in whether `uid` and `groups` were passed. They are collapsed into a
single task using `default(omit)`, which removes the risk that a fix lands in one of the four copies only. This also
fixes `comment`, which dereferenced `unix_user.value.name` unconditionally and aborted for every user that did not set
the undocumented and supposedly optional key.
Two conditions compared a length against zero with `>=`, which is true for any list. As a result an empty `ssh.config`
still produced a config file, and the removal counterpart never triggered. The create and remove pair for `.ssh/config`
now mirrors the one already used for `authorized_keys`.
The private key source was resolved through `{{ playbook_dir }}`, while the authorized key lookup in the template uses
the regular relative search path. Both now use the same mechanism, which is a superset of the previous location, so
existing playbook layouts keep working, and the role becomes testable from a molecule scenario.
BREAKING CHANGE:
The `.ssh` directory is only created when a user actually declares an `ssh` key, and an empty `ssh.config` list now
removes the client config instead of writing an empty one. Users who relied on the role to pre create an empty `~/.ssh`
have to declare `ssh: {}` explicitly.
Co-authored-by: Copilot <copilot@github.com>
180 lines
7.3 KiB
YAML
180 lines
7.3 KiB
YAML
---
|
|
|
|
- name: "Define home directory for unix user: {{ unix_user.key }}"
|
|
ansible.builtin.set_fact:
|
|
user_user_home: "{{ unix_user.value.home | default('/home/' + unix_user.key) }}"
|
|
|
|
- name: "Create btrfs volume for unix user: {{ unix_user.key }}"
|
|
when: unix_user.value.btrfs is defined and
|
|
unix_user.value.btrfs
|
|
block:
|
|
- name: "Find btrfs device"
|
|
ansible.builtin.command:
|
|
cmd: /bin/bash -c "findmnt -no SOURCE -T {{ user_user_home }} | sed 's/\[.*\]//'"
|
|
register: _unix_users_btrfs_device
|
|
failed_when: _unix_users_btrfs_device.rc != 0
|
|
changed_when: _unix_users_btrfs_device.rc == 0
|
|
|
|
- name: "Determine filesystem of device"
|
|
ansible.builtin.set_fact:
|
|
_unix_users_device_filesystem: "{{ ansible_facts['mounts'] | selectattr('device', 'equalto', _unix_users_btrfs_device.stdout) | map(attribute='fstype') | first }}"
|
|
|
|
- name: "Fail if device does not have a btrfs file system"
|
|
ansible.builtin.fail:
|
|
msg: "Determined device {{ _unix_users_btrfs_device.stdout }} does not have a btrfs filesystem"
|
|
when: _unix_users_device_filesystem != 'btrfs'
|
|
|
|
# The subvolume stays root owned until the user exists. It is chowned further below, after the user was created.
|
|
- name: "Create btrfs volume for unix user: {{ unix_user.key }}"
|
|
community.general.btrfs_subvolume:
|
|
filesystem_device: "{{ _unix_users_btrfs_device.stdout }}"
|
|
name: "{{ user_user_home }}"
|
|
state: present
|
|
|
|
- name: "Create unix user: {{ unix_user.key }}"
|
|
ansible.builtin.user:
|
|
name: "{{ unix_user.key }}"
|
|
uid: "{{ unix_user.value.uid | default(omit) }}"
|
|
group: "{{ unix_user.value.group | default('users') }}"
|
|
groups: "{{ unix_user.value.groups | default(omit) }}"
|
|
comment: "{{ unix_user.value.name | default(omit) }}"
|
|
create_home: "{{ unix_user.value.create_home | default(true) }}"
|
|
home: "{{ user_user_home }}"
|
|
shell: "{{ unix_user.value.shell | default('/bin/bash') }}"
|
|
password: "{{ unix_user.value.password | password_hash('sha512') if unix_user.value.password is defined and unix_user.value.password | length > 0 else '!' }}"
|
|
state: present
|
|
|
|
- name: "Adapt permissions and copy skel for unix user: {{ unix_user.key }}"
|
|
when: unix_user.value.btrfs is defined and
|
|
unix_user.value.btrfs
|
|
block:
|
|
- name: "Copy skel files"
|
|
ansible.builtin.include_tasks: copy_skel_file.yaml
|
|
loop_control:
|
|
loop_var: skel_file
|
|
with_items:
|
|
- ".bash_logout"
|
|
- ".bash_profile"
|
|
- ".bashrc"
|
|
- name: "Change permission unix users home dir: {{ unix_user.key }}"
|
|
ansible.builtin.file:
|
|
path: "{{ user_user_home }}"
|
|
owner: "{{ unix_user.key }}"
|
|
group: "{{ unix_user.value.group | default('users') }}"
|
|
state: directory
|
|
mode: "0755"
|
|
|
|
- name: "Create .ssh directory for unix user: {{ unix_user.key }}"
|
|
ansible.builtin.file:
|
|
path: "{{ user_user_home }}/.ssh"
|
|
owner: "{{ unix_user.key }}"
|
|
group: "{{ unix_user.value.group | default('users') }}"
|
|
mode: "0700"
|
|
state: directory
|
|
when: unix_user.value.ssh is defined
|
|
|
|
- name: "Create authorized_keys file for unix user: {{ unix_user.key }}"
|
|
ansible.builtin.template:
|
|
src: authorized_keys.j2
|
|
dest: "{{ user_user_home }}/.ssh/authorized_keys"
|
|
owner: "{{ unix_user.key }}"
|
|
group: "{{ unix_user.value.group | default('users') }}"
|
|
mode: "0600"
|
|
when: unix_user.value.ssh.authorized_keys is defined and unix_user.value.ssh.authorized_keys | length > 0
|
|
|
|
- name: "Remove authorized_keys file for unix user: {{ unix_user.key }}"
|
|
ansible.builtin.file:
|
|
path: "{{ user_user_home }}/.ssh/authorized_keys"
|
|
state: absent
|
|
when: unix_user.value.ssh.authorized_keys is not defined or unix_user.value.ssh.authorized_keys | length <= 0
|
|
|
|
# The relative source is resolved against the files directory of the playbook, like the lookup in authorized_keys.j2.
|
|
- name: "Create private SSH keys for unix user: {{ unix_user.key }}"
|
|
ansible.builtin.copy:
|
|
src: "ssh/private_keys/{{ item }}"
|
|
dest: "{{ user_user_home }}/.ssh/{{ item }}"
|
|
owner: "{{ unix_user.key }}"
|
|
group: "{{ unix_user.value.group | default('users') }}"
|
|
mode: "0600"
|
|
with_items:
|
|
- "{{ unix_user.value.ssh.private_keys }}"
|
|
when: unix_user.value.ssh.private_keys is defined and unix_user.value.ssh.private_keys | length > 0
|
|
|
|
- name: "Extract public SSH keys from private keys for unix user: {{ unix_user.key }}"
|
|
ansible.builtin.shell:
|
|
cmd: "ssh-keygen -y -f {{ user_user_home }}/.ssh/{{ item }} > {{ user_user_home }}/.ssh/{{ item }}.pub"
|
|
creates: "{{ user_user_home }}/.ssh/{{ item }}.pub"
|
|
with_items:
|
|
- "{{ unix_user.value.ssh.private_keys }}"
|
|
when: unix_user.value.ssh.private_keys is defined and unix_user.value.ssh.private_keys | length > 0
|
|
|
|
- name: "Correct permissions of public SSH keys for unix user: {{ unix_user.key }}"
|
|
ansible.builtin.file:
|
|
path: "{{ user_user_home }}/.ssh/{{ item }}.pub"
|
|
owner: "{{ unix_user.key }}"
|
|
group: "{{ unix_user.value.group | default('users') }}"
|
|
mode: "0644"
|
|
with_items:
|
|
- "{{ unix_user.value.ssh.private_keys }}"
|
|
when: unix_user.value.ssh.private_keys is defined and unix_user.value.ssh.private_keys | length > 0
|
|
|
|
- name: "Create custom SSH client config for unix user: {{ unix_user.key }}"
|
|
ansible.builtin.template:
|
|
src: config.j2
|
|
dest: "{{ user_user_home }}/.ssh/config"
|
|
owner: "{{ unix_user.key }}"
|
|
group: "{{ unix_user.value.group | default('users') }}"
|
|
mode: "0644"
|
|
when: unix_user.value.ssh.config is defined and unix_user.value.ssh.config | length > 0
|
|
|
|
- name: "Remove custom SSH client config for unix user: {{ unix_user.key }}"
|
|
ansible.builtin.file:
|
|
path: "{{ user_user_home }}/.ssh/config"
|
|
state: absent
|
|
when: unix_user.value.ssh.config is not defined or unix_user.value.ssh.config | length <= 0
|
|
|
|
- name: "Create .forward file to forward emails for unix user: {{ unix_user.key }}"
|
|
ansible.builtin.template:
|
|
src: forward.j2
|
|
dest: "{{ user_user_home }}/.forward"
|
|
owner: "{{ unix_user.key }}"
|
|
group: "{{ unix_user.value.group | default('users') }}"
|
|
mode: "0644"
|
|
when: unix_user.value.email is defined
|
|
|
|
- name: "Remove .forward file to forward emails for unix user: {{ unix_user.key }}"
|
|
ansible.builtin.file:
|
|
path: "{{ user_user_home }}/.forward"
|
|
state: absent
|
|
when: unix_user.value.email is not defined
|
|
|
|
- name: "Create XDG base directories"
|
|
ansible.builtin.file:
|
|
path: "{{ item }}"
|
|
owner: "{{ unix_user.key }}"
|
|
group: "{{ unix_user.value.group | default('users') }}"
|
|
mode: "0755"
|
|
state: "directory"
|
|
with_items:
|
|
- "{{ unix_user.value.xdg.dirs.cache | default(user_user_home + '/.cache') }}"
|
|
- "{{ unix_user.value.xdg.dirs.config | default(user_user_home + '/.config') }}"
|
|
- "{{ unix_user.value.xdg.dirs.data | default(user_user_home + '/.local/share') }}"
|
|
- "{{ unix_user.value.xdg.dirs.state | default(user_user_home + '/.local/state') }}"
|
|
|
|
- name: "Create shell rc files"
|
|
when: unix_user.value.shell_rc_files is defined
|
|
ansible.builtin.include_tasks: create_shell_rc_file.yaml
|
|
with_items:
|
|
- "{{ unix_user.value.shell_rc_files }}"
|
|
loop_control:
|
|
loop_var: shell_rc_file
|
|
|
|
- name: "Create .netrc file"
|
|
when: unix_user.value.netrc is defined and unix_user.value.netrc | length > 0
|
|
ansible.builtin.template:
|
|
src: netrc.j2
|
|
dest: "{{ user_user_home }}/.netrc"
|
|
owner: "{{ unix_user.key }}"
|
|
group: "{{ unix_user.value.group | default('users') }}"
|
|
mode: "0600"
|