From 095705643cf6ceb1b15e7136e0b51eeb0507d9dc Mon Sep 17 00:00:00 2001 From: Markus Pesch Date: Tue, 8 Sep 2026 23:47:29 +0200 Subject: [PATCH] fix(tasks): derive a deterministic password salt per unix user `password_hash('sha512')` without an explicit salt generates a new random salt on every invocation. The resulting hash differed on each run, so the user module rewrote /etc/shadow and reported a change every time the role was applied. This was the single biggest obstacle to a green idempotence check. The salt is now derived from the user name, which keeps the hash stable across runs while still giving every account its own salt, so two users sharing a password do not end up with an identical hash. Verified locally: repeated runs produce a byte identical hash, and different user names produce different ones. Co-authored-by: Copilot --- tasks/create_unix_user.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tasks/create_unix_user.yaml b/tasks/create_unix_user.yaml index ba560d9..c0524ce 100644 --- a/tasks/create_unix_user.yaml +++ b/tasks/create_unix_user.yaml @@ -40,7 +40,8 @@ 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 '!' }}" + # The salt is derived from the user name, a random one would produce a new hash and a change on every run. + password: "{{ unix_user.value.password | password_hash('sha512', unix_user.key | hash('sha512') | truncate(16, true, '')) 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 }}"