3

I am trying to change password for a non-root Linux user from Ansible playbook. To do so I tried to follow this link

Following the instruction I can successfully change the password of a non-root user by typing the code below in the terminal.

$ echo -e "your_current_pass\nlinuxpassword\nlinuxpassword" | passwd
Changing password for testuser.
(current) UNIX password: Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully

After that I am trying to automate the code with an Ansible playbook like below,

---
- hosts: all
  gather_facts: no

  tasks:
    - name: "Check if user exists"
      register: user1_exists
      raw: getent passwd {{ ansible_user }}
      ignore_errors: true

    - name: "Change {{ ansible_user }} password"
      raw: echo -e "my_current_pass\nmy_new_pass\nmy_new_pass" | passwd
      when: user1_exists|success

I am using the raw module of Ansible here as most of my machines don't have Python installed. I do not have superuser (sudo) permission either to use become: True in playbook.

Also using password based authentication here to run the Ansible playbook on target machine. Not ssh based authentication.

But while I am executing the playbook I am getting this error,

TASK [change user1 password] ***************************************************
fatal: [192.168.0.57]: FAILED! => {"changed": true, "failed": true, "rc": 10, 
"stderr": "Shared connection to 192.168.0.57 closed.\r\n", "stdout": "Changing 
password for testuser.\r\n(current) UNIX password: passwd: Authentication 
token manipulation error\r\npasswd: password unchanged\r\n", "stdout_lines": 
["Changing password for testuser.", "(current) UNIX password: passwd: 
Authentication token manipulation error", "passwd: password unchanged"]}

Could anyone show me the mistakes I am making here?

Leo Ufimtsev
  • 6,240
  • 5
  • 40
  • 48
kuttumiah
  • 525
  • 1
  • 11
  • 19

3 Answers3

9

Use the built-in user module instead of a shell command. This requires become: True in your playbook. Note that the password parameter of the user module requires an encrypted value. The password_hash jinja filter will help you there.

  - name: change user's password
    user:
      name: foo
      password: "{{ 'passwordsaresecret' | password_hash('sha512') }}"
falsePockets
  • 3,826
  • 4
  • 18
  • 37
kfreezy
  • 1,499
  • 12
  • 16
  • Sorry to inform that I do not have superuser privilege to become an escalated user. I'm editing my question to clarify that. Also as I said I can do not have python on the target machine so I think the built-in user module won't work either. – kuttumiah Aug 31 '17 at 22:33
  • unfortunately the proposed solution may not work for unprivileged users, but apart from that, I would propose to change this solution to use the [vars_prompt](https://docs.ansible.com/ansible/latest/user_guide/playbooks_prompts.html) module with 'private' flag to ask for the new password, rather than hard-coding in the playbook – Monger39 Feb 17 '22 at 15:16
1

Your playbook is almost correct. I had the same kind of requirement and I used your playbook. There was just one mistake in your playbook, you forgot to enclose your password variables in '{{}}' braces. So I changed your playbook like below and it worked for me.

  hosts: all
  gather_facts: no

  tasks:
    - name: "Check if user exists"
      register: user1_exists
      raw: getent passwd {{ ansible_user }}
      ignore_errors: true

    - name: "Change {{ ansible_user }} password"
      raw: echo -e "{{ ansible_password }}\n{{newpwd}}\n{{newpwd}}" | passwd
      when: user1_exists|success
Amarjit Singh
  • 2,068
  • 19
  • 52
0

I've hacked together the following to solve this. The password's don't show in log or even verbose log '-vvvvv' and are not visible in history on remote systems:

---
- name: Change password when connecting as a non-root/non-sudoer user.
#
# Ansible's 'user' module can only change a password if it is ran as a root user or 'become' is used.
# For a non-root user, when you run 'passwd', it asks for current password before you can enter a new one.
# Workaround: Create a a temporary script that updates the password and run that script remoteley 
#             and use 'no_log' directive to prevent passwords being visible in any log.
#             Tested that passwords not visible in verbose output '-vvvvv' and not in 'history' of remote computers.
#             The temporary script is deleted remotley automatically by 'script' module.
# Note:
# New password must comply with your passwd security policy.

  hosts: all
  gather_facts: no

  vars_prompt:
  - name: "curr_pass"
    prompt: Type in current password
    private: yes

  - name: "new_pass"
    prompt: Type in new password
    private: yes
    confirm: yes

  ## If you need to *temporary* hard-code credentials, use below.
  ## Delete after use or use vault if you want long-term storage.
  #vars:
  #- curr_pass: MyOldPass
  #- new_pass: MyNewPass123!!

  tasks:
  - name: Create a temporary local script which will change the users password
    copy:
      dest: updatePassNonRootDynamic.sh
      content: echo -e '{{curr_pass}}\n{{new_pass}}\n{{new_pass}}' | passwd
    delegate_to: localhost
    no_log: True
    run_once: true

  - name: Change password via temporary script on all hosts
    script: updatePassNonRootDynamic.sh

  - name: Remove the temporary local script
    file:
      path: updatePassNonRootDynamic.sh
      state: absent
    delegate_to: localhost
    run_once: true
Leo Ufimtsev
  • 6,240
  • 5
  • 40
  • 48
  • Great example and when I run the script directly via shell it works. However, via Ansible I'm getting token manipulation error. Any hints? – newduino Apr 04 '22 at 07:25