refactor(users): migrate system.user to system.users[] for multi-user support
This commit is contained in:
@@ -5,3 +5,14 @@
|
||||
dest: /mnt/etc/sudoers.d/01-wheel
|
||||
mode: "0440"
|
||||
validate: /usr/sbin/visudo --check --file=%s
|
||||
|
||||
- name: Deploy per-user sudoers rules
|
||||
when: item.sudo is defined and (item.sudo | string | length) > 0
|
||||
ansible.builtin.copy:
|
||||
content: "{{ item.name }} {{ item.sudo }}\n"
|
||||
dest: "/mnt/etc/sudoers.d/{{ item.name }}"
|
||||
mode: "0440"
|
||||
validate: /usr/sbin/visudo --check --file=%s
|
||||
loop: "{{ system_cfg.users }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
|
||||
@@ -1,38 +1,53 @@
|
||||
---
|
||||
- name: Create user account
|
||||
- name: Set root password
|
||||
vars:
|
||||
configuration_root_cmd: >-
|
||||
{{ chroot_command }} /usr/sbin/usermod --password
|
||||
'{{ system_cfg.root.password | password_hash('sha512') }}' root --shell /bin/bash
|
||||
ansible.builtin.command: "{{ configuration_root_cmd }}"
|
||||
register: configuration_root_result
|
||||
changed_when: configuration_root_result.rc == 0
|
||||
|
||||
- name: Create user accounts
|
||||
vars:
|
||||
configuration_user_group: >-
|
||||
{{ "sudo" if is_debian | bool else "wheel" }}
|
||||
configuration_useradd_cmd: >-
|
||||
{{ chroot_command }} /usr/sbin/useradd --create-home --user-group
|
||||
--groups {{ configuration_user_group }} {{ system_cfg.user.name }}
|
||||
--password {{ system_cfg.user.password | password_hash('sha512') }} --shell /bin/bash
|
||||
configuration_root_cmd: >-
|
||||
{{ chroot_command }} /usr/sbin/usermod --password
|
||||
'{{ system_cfg.root.password | password_hash('sha512') }}' root --shell /bin/bash
|
||||
ansible.builtin.command: "{{ item }}"
|
||||
loop:
|
||||
- "{{ configuration_useradd_cmd }}"
|
||||
- "{{ configuration_root_cmd }}"
|
||||
--uid {{ 1000 + ansible_loop.index0 }}
|
||||
--groups {{ configuration_user_group }} {{ item.name }}
|
||||
--password {{ item.password | password_hash('sha512') }} --shell /bin/bash
|
||||
ansible.builtin.command: "{{ configuration_useradd_cmd }}"
|
||||
loop: "{{ system_cfg.users }}"
|
||||
loop_control:
|
||||
extended: true
|
||||
label: "{{ item.name }}"
|
||||
register: configuration_user_result
|
||||
changed_when: configuration_user_result.rc == 0
|
||||
|
||||
- name: Ensure .ssh directory exists
|
||||
when: system_cfg.user.keys | length > 0
|
||||
when: item.keys | default([]) | length > 0
|
||||
ansible.builtin.file:
|
||||
path: /mnt/home/{{ system_cfg.user.name }}/.ssh
|
||||
path: "/mnt/home/{{ item.name }}/.ssh"
|
||||
state: directory
|
||||
owner: 1000
|
||||
group: 1000
|
||||
owner: "{{ 1000 + ansible_loop.index0 }}"
|
||||
group: "{{ 1000 + ansible_loop.index0 }}"
|
||||
mode: "0700"
|
||||
loop: "{{ system_cfg.users }}"
|
||||
loop_control:
|
||||
extended: true
|
||||
label: "{{ item.name }}"
|
||||
|
||||
- name: Add SSH public keys to authorized_keys
|
||||
when: system_cfg.user.keys | length > 0
|
||||
vars:
|
||||
_uid: "{{ 1000 + (system_cfg.users | map(attribute='name') | list).index(item.0.name) }}"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /mnt/home/{{ system_cfg.user.name }}/.ssh/authorized_keys
|
||||
line: "{{ item }}"
|
||||
owner: 1000
|
||||
group: 1000
|
||||
path: "/mnt/home/{{ item.0.name }}/.ssh/authorized_keys"
|
||||
line: "{{ item.1 }}"
|
||||
owner: "{{ _uid }}"
|
||||
group: "{{ _uid }}"
|
||||
mode: "0600"
|
||||
create: true
|
||||
loop: "{{ system_cfg.user.keys }}"
|
||||
loop: "{{ system_cfg.users | subelements('keys', skip_missing=True) }}"
|
||||
loop_control:
|
||||
label: "{{ item.0.name }}: {{ item.1[:40] }}..."
|
||||
|
||||
@@ -40,10 +40,7 @@ system_defaults:
|
||||
path: ""
|
||||
packages: []
|
||||
disks: []
|
||||
user:
|
||||
name: ""
|
||||
password: ""
|
||||
keys: []
|
||||
users: []
|
||||
root:
|
||||
password: ""
|
||||
luks:
|
||||
|
||||
@@ -66,9 +66,9 @@
|
||||
- system_cfg.type == "virtual"
|
||||
- hypervisor_type != "vmware"
|
||||
ansible.builtin.set_fact:
|
||||
ansible_user: "{{ system_cfg.user.name }}"
|
||||
ansible_password: "{{ system_cfg.user.password }}"
|
||||
ansible_become_password: "{{ system_cfg.user.password }}"
|
||||
ansible_user: "{{ system_cfg.users[0].name }}"
|
||||
ansible_password: "{{ system_cfg.users[0].password }}"
|
||||
ansible_become_password: "{{ system_cfg.users[0].password }}"
|
||||
ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
||||
changed_when: false
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
that:
|
||||
- system is mapping
|
||||
- system.network is not defined or system.network is mapping
|
||||
- system.user is not defined or system.user is mapping
|
||||
- system.users is not defined or (system.users is iterable and system.users is not string and system.users is not mapping)
|
||||
- system.root is not defined or system.root is mapping
|
||||
- system.luks is not defined or system.luks is mapping
|
||||
- system.features is not defined or system.features is mapping
|
||||
fail_msg: "system and its nested keys (network, user, root, luks, features) must be dictionaries."
|
||||
fail_msg: "system and its nested keys (network, root, luks, features) must be dictionaries; system.users must be a list."
|
||||
quiet: true
|
||||
|
||||
- name: Validate DNS and user.keys are lists (not strings)
|
||||
- name: Validate DNS lists (not strings)
|
||||
when: system.network is defined and system.network.dns is defined
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
@@ -25,13 +25,18 @@
|
||||
fail_msg: "system.network.dns.servers and system.network.dns.search must be lists, not strings."
|
||||
quiet: true
|
||||
|
||||
- name: Validate user.keys is a list
|
||||
when: system.user is defined and system.user.keys is defined
|
||||
- name: Validate system.users entries
|
||||
when: system.users is defined and system.users | length > 0
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- system.user.keys is iterable and system.user.keys is not string
|
||||
fail_msg: "system.user.keys must be a list of SSH public key strings."
|
||||
- item is mapping
|
||||
- item.name is defined and (item.name | string | length) > 0
|
||||
- item.keys is not defined or (item.keys is iterable and item.keys is not string)
|
||||
fail_msg: "Each system.users[] entry must be a dict with 'name'; 'keys' must be a list."
|
||||
quiet: true
|
||||
loop: "{{ system.users }}"
|
||||
loop_control:
|
||||
label: "{{ item.name | default('(unnamed)') }}"
|
||||
|
||||
- name: Validate system features input types
|
||||
when: system.features is defined
|
||||
@@ -122,10 +127,7 @@
|
||||
| list
|
||||
}}
|
||||
disks: "{{ system_raw.disks | default([]) }}"
|
||||
user:
|
||||
name: "{{ system_raw.user.name | string }}"
|
||||
password: "{{ system_raw.user.password | string }}"
|
||||
keys: "{{ system_raw.user.keys | default([]) }}"
|
||||
users: "{{ system_raw.users | default([]) }}"
|
||||
root:
|
||||
password: "{{ system_raw.root.password | string }}"
|
||||
luks:
|
||||
|
||||
@@ -48,25 +48,9 @@
|
||||
fail_msg: "Unsupported system keys: {{ system_unknown_keys | join(', ') }}."
|
||||
quiet: true
|
||||
|
||||
- name: Validate nested system mappings
|
||||
loop:
|
||||
- network
|
||||
- user
|
||||
- root
|
||||
- luks
|
||||
- features
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- system[item] is not defined or system[item] is mapping
|
||||
fail_msg: "system.{{ item }} must be a dictionary."
|
||||
quiet: true
|
||||
|
||||
- name: Validate system sub-dict schemas
|
||||
loop:
|
||||
- network
|
||||
- user
|
||||
- root
|
||||
- luks
|
||||
loop_control:
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
api_host: "{{ hypervisor_cfg.url }}"
|
||||
api_user: "{{ hypervisor_cfg.username }}"
|
||||
api_password: "{{ hypervisor_cfg.password }}"
|
||||
ciuser: "{{ system_cfg.user.name }}"
|
||||
cipassword: "{{ system_cfg.user.password }}"
|
||||
ciuser: "{{ system_cfg.users[0].name }}"
|
||||
cipassword: "{{ system_cfg.users[0].password }}"
|
||||
ciupgrade: false
|
||||
node: "{{ hypervisor_cfg.host }}"
|
||||
vmid: "{{ system_cfg.id }}"
|
||||
|
||||
@@ -4,9 +4,18 @@ ssh_pwauth: true
|
||||
package_update: false
|
||||
package_upgrade: false
|
||||
users:
|
||||
- name: "{{ system_cfg.user.name }}"
|
||||
primary_group: "{{ system_cfg.user.name }}"
|
||||
{% for user in system_cfg.users %}
|
||||
- name: "{{ user.name }}"
|
||||
primary_group: "{{ user.name }}"
|
||||
groups: users
|
||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||
passwd: "{{ system_cfg.user.password | password_hash('sha512') }}"
|
||||
lock_passwd: False
|
||||
sudo: "{{ user.sudo | default('ALL=(ALL) NOPASSWD:ALL') }}"
|
||||
passwd: "{{ user.password | password_hash('sha512') }}"
|
||||
lock_passwd: false
|
||||
{% set ssh_keys = user.keys | default([]) %}
|
||||
{% if ssh_keys | length > 0 %}
|
||||
ssh_authorized_keys:
|
||||
{% for key in ssh_keys %}
|
||||
- "{{ key }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
Reference in New Issue
Block a user