refactor(prompts): remove vars_prompt, require users defined in inventory

This commit is contained in:
2026-03-20 15:06:32 +01:00
committed by MORAWSKI Norbert
parent fc53b6c786
commit 6afe9dbd1c
2 changed files with 20 additions and 80 deletions

View File

@@ -202,14 +202,29 @@ When `interfaces` is empty, the flat fields (`bridge`, `ip`, `prefix`, `gateway`
#### `system.users` #### `system.users`
Dict keyed by username. At least one user must have a `password` (used for SSH access during bootstrap). Users without a password get locked accounts (key-only auth).
```yaml
system:
users:
svcansible:
password: "vault_lookup"
keys:
- "ssh-ed25519 AAAA..."
appuser:
sudo: "ALL=(ALL) NOPASSWD: ALL"
keys:
- "ssh-ed25519 BBBB..."
```
| Key | Type | Default | Description | | Key | Type | Default | Description |
| ---------- | ----------- | ------- | -------------------------------------------------- | | ---------- | ----------- | ------- | -------------------------------------------------- |
| `name` | string | -- | Username (required) | | *(dict key)* | string | -- | Username (required) |
| `password` | string | -- | User password (required for first user) | | `password` | string | -- | User password (required for at least one user) |
| `keys` | list | `[]` | SSH public keys | | `keys` | list | `[]` | SSH public keys |
| `sudo` | bool/string | -- | `true` for NOPASSWD ALL, or custom sudoers string | | `sudo` | bool/string | -- | `true` for NOPASSWD ALL, or custom sudoers string |
The first user's credentials are prompted interactively via `vars_prompt` unless supplied in inventory or `-e`. Users must be defined in inventory. The dict format enables additive merging across inventory layers with `hash_behaviour=merge`.
#### `system.root` #### `system.root`
@@ -398,7 +413,7 @@ ansible-playbook -i inventory.yml main.yml
ansible-playbook -i inventory.yml main.yml -e @vars.yml ansible-playbook -i inventory.yml main.yml -e @vars.yml
``` ```
Credentials for the first user and root are prompted interactively via `vars_prompt` unless already set in inventory or passed via `-e`. All credentials (`system.users`, `system.root.password`) must be defined in inventory or passed via `-e`.
Example inventory files are included: Example inventory files are included:
@@ -408,7 +423,7 @@ Example inventory files are included:
## 7. Security ## 7. Security
Use **Ansible Vault** for all sensitive values (`hypervisor.password`, `system.luks.passphrase`, `system.users[].password`, `system.root.password`). Use **Ansible Vault** for all sensitive values (`hypervisor.password`, `system.luks.passphrase`, user passwords in `system.users`, `system.root.password`).
## 8. Safety ## 8. Safety

View File

@@ -14,82 +14,7 @@
strategy: free # noqa: run-once[play] strategy: free # noqa: run-once[play]
gather_facts: false gather_facts: false
become: true become: true
vars_prompt:
- name: user_name
prompt: |
What is your username?
default: ""
private: false
- name: user_public_key
prompt: |
What is your ssh key?
default: ""
private: false
- name: user_password
prompt: |
What is your password?
default: ""
confirm: true
- name: root_password
prompt: |
What is your root password?
default: ""
confirm: true
pre_tasks: pre_tasks:
- name: Apply prompted authentication values to system input
no_log: true
vars:
system_input: "{{ system | default({}) }}"
system_users_input: "{{ system_input.users | default({}) }}"
_first_entry: "{{ system_users_input | dict2items | first | default({'key': '', 'value': {}}) }}"
_first_name: "{{ _first_entry.key }}"
_first_attrs: "{{ _first_entry.value if _first_entry.value is mapping else {} }}"
system_root_input: "{{ (system_input.root | default({})) if (system_input.root is mapping) else {} }}"
prompt_user_name: "{{ user_name | default(system_user_name | default(''), true) | string }}"
prompt_user_key: "{{ user_public_key | default(user_key | default(system_user_key | default(''), true), true) | string | trim }}"
prompt_user_password: "{{ user_password | default(system_user_password | default(''), true) | string }}"
prompt_root_password: "{{ root_password | default(system_root_password | default(''), true) | string }}"
resolved_name: "{{ _first_name if (_first_name | length > 0) else prompt_user_name }}"
resolved_attrs:
keys: >-
{{
_first_attrs['keys']
if (_first_attrs['keys'] is defined
and _first_attrs['keys'] is iterable
and _first_attrs['keys'] is not string
and _first_attrs['keys'] | length > 0)
else (
[prompt_user_key]
if (prompt_user_key | length > 0)
else []
)
}}
password: >-
{{
_first_attrs.password | string
if (_first_attrs.password | default('') | string | length) > 0
else prompt_user_password
}}
ansible.builtin.set_fact:
system: >-
{{
system_input
| combine(
{
'users': system_users_input | combine({resolved_name: (_first_attrs | combine(resolved_attrs, recursive=True))}),
'root': {
'password': (
(system_root_input.password | default('') | string | length) > 0
) | ternary(system_root_input.password | string, prompt_root_password)
}
},
recursive=True
)
}}
- name: Load global defaults - name: Load global defaults
ansible.builtin.import_role: ansible.builtin.import_role:
name: global_defaults name: global_defaults