Linux – Is it possible to change the current user’s password in-band with ansible

ansiblelinuxyaml

I have a Linux distribution that is freshly installed. It has a regular user with a default password, and a locked down root account (no password on root – can't be SSHed as directly). I want to be able to run an ansible playbook to configure this server, and lock down this default account by changing its password, without doing extra out-of-band steps.

Most of the setup that my playbook does needs root, so it is configured to ssh in as the default user, become root, and run all the commands. That works fine. The problem is changing passwords.

If I try to have ansible change the password of the user using the user module, it succeeds, but all tasks after that fail. Even if I do the change as the last step in my playbook, all the handlers that are supposed to run at the end fail.

There are 2 suggestions I have come across online to similar questions:

  • Use RSA keys
  • Use an initial play to somehow test for, and change the password

Using RSA keys requires you to setup RSA ahead of time, and is therefore not in-band.

I've been trying to use an initial play to somehow do this, but so far, the second the initial play fails to login with the default password, ansible exits with an error, and ignores other tasks, and the next play.

There's also a way to do this using ssh-pass, as demonstrated here, which should work, but that seems more of a hack, and ssh-pass isn't always easily available, like on MacOS machines running ansible.

A similar topic was discussed here over a decade ago, but it looks like Dave got around this by setting Linux to display an "Account Disabled" message when you try to login as the default user, and changing the user instead, which also sounds like it should work, but is different than simply changing the default user's password.

Is there anything that can be done by ansible to change the password of the user it is running as, without disconnecting?

Best Answer

Is there a way to make Ansible try the default password, and keep running the playbook if that fails?

Here is an example, it doesn't exactly match what you mentioned, but might be a starting point.

---
# SYNOPSIS
# try authentication using keys, if that fails, fall back to default credentials

- import_playbook: ../bootstrap.yml

- hosts: linux_systems
  gather_facts: no
  become: yes
  any_errors_fatal: true
  vars: 
    ansible_user_first_run: vagrant
    ansible_pass_first_run: vagrant
  tasks:

  - block:
    - name: Check if connection is possible using keys
      command: ssh -F {{project_dir}}/.ssh/ansible_ssh_config -o User={{ ansible_user }} -o ConnectTimeout=10 -o PreferredAuthentications=publickey -o PubkeyAuthentication=yes {{ ansible_host }} /bin/true
      register: result
      connection: local
      ignore_errors: yes
      changed_when: False

    - name: If using user_first_run
      connection: local
      set_fact:
        using_first_run: true
      when: result is failed

    - name: If no connection, change ansible_user
      connection: local
      set_fact:
        ansible_user: "{{ ansible_user_first_run }}"
      when: result is failed

    - name: If no connection, change ansible_ssh_pass
      connection: local
      set_fact:
        ansible_ssh_pass: "{{ ansible_pass_first_run }}"
      when: result is failed

    - name: If no connection, change ansible_become_pass
      connection: local
      set_fact:
        ansible_become_pass: "{{ ansible_pass_first_run }}"
      when: result is failed

    # since any_errors_fatal this should fail the play
    # if we still cannot reach all hosts.
    - name: Check if connection is possible
      raw: /bin/true
      changed_when: False

    tags:
    - always

  - name: Perform a ansible ping
    ping: {}