Last active
March 8, 2021 09:14
-
-
Save QNimbus/30671b33abde3a1b81b8b9b117062d5f to your computer and use it in GitHub Desktop.
Ansible playbook to run if provisioning hosts that enforce the user to enter a new password (due to expired password after initial setup/installation e.g. Ubuntu 20.04 LTS Server ARM64 for Raspberry Pi). This play will attempt to login to the hosts and update the password and thereby resetting the password expiry.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
- hosts: all:!localhost | |
gather_facts: no | |
# This play attempts to establish an SSH connection with inventory hosts | |
# and when it encounters an expired password it will change and reset the password | |
# so other playbooks and roles can normally execute without failing because of expired password. | |
# Tested with: | |
# - Ubuntu | |
# - RedHat | |
# - Fedora | |
# - Centos | |
# Multiple possible results for command (ssh) task: | |
# - Successful password login (rc == 0) | |
# - Successful public key login (rc == 0) | |
# - Successful login with password, password expired (rc == 1, stderr: WARNING: Your password has expired.) | |
# - Successful login with pubkey, password expired (rc == 1, stderr: WARNING: Your password has expired.) | |
# - No password auth possible (rc == 255, stderr: Permission denied (publickey).) | |
# - No pubkey auth possible (rc == 255, std_err: Permission denied (password).) | |
# - Wrong password (rc == 5, std_err: Permission denied, please try again.) | |
vars: | |
os_dependencies: | |
- ssh | |
- sshpass | |
original_host: '{{ ansible_host }}' | |
ssh_options: | |
- '-T' | |
- '-o StrictHostKeyChecking=no' | |
- '-o UserKnownHostsFile=/dev/null' | |
ssh_options_tty: | |
- '-tt' | |
- '-o StrictHostKeyChecking=no' | |
- '-o UserKnownHostsFile=/dev/null' | |
tasks: | |
- name: Ensure OS dependencies are installed. | |
connection: local | |
shell: "which {{ os_dependencies | join(' ') }}" | |
changed_when: false | |
failed_when: false | |
ignore_errors: true | |
register: os_dependencies_check | |
- name: Fail execution if any of the needed OS tools is missing. | |
fail: | |
msg: "One or more of the: {{ os_dependencies | join(', ') }} are missing on this machine. Please install them - using your distribution's recommended method - before continuing." | |
when: os_dependencies_check.rc != 0 | |
- name: Test ssh connection. | |
connection: local | |
command: sshpass -p {{ ansible_password }} -- ssh {{ ssh_options | join(' ') }} '{{ ansible_user }}@{{ original_host }}' | |
no_log: yes | |
failed_when: false | |
changed_when: false | |
register: result | |
- set_fact: | |
successful_login: '{{ result.rc == 0 }}' | |
expired_password: '{{ result.rc == 1 and result.stderr is search("warning: your password has expired", ignorecase=True) }}' | |
wrong_password: '{{ result.rc == 5 and result.stderr is search("permission denied, please try again", ignorecase=True) }}' | |
no_valid_auth: '{{ result.rc == 255 and result.stderr is search("permission denied \([^)]+\)", ignorecase=True) }}' | |
- name: Check reason for possible failed ssh connection. | |
block: | |
- fail: | |
msg: Password authentication for remote host {{ ansible_host }} failed due to wrong password. | |
when: wrong_password == true | |
- fail: | |
msg: No valid authentication method for remote host {{ ansible_host }} available. | |
when: no_valid_auth == true | |
- fail: | |
msg: Unable to login using ssh. | |
when: expired_password != true | |
when: successful_login != true | |
- block: | |
- name: Generate temporary password. | |
set_fact: | |
temp_passwd: "{{ lookup('password', '/dev/null length=14 chars=ascii_letters,digits') }}" | |
- name: Set expired password to temp password. | |
no_log: yes | |
connection: local | |
expect: | |
command: sshpass -p {{ ansible_password }} -- ssh {{ ssh_options_tty | join(' ') }} '{{ ansible_user }}@{{ original_host }}' | |
responses: | |
'(?i)\(current\)|current (UNIX\s)?password': '{{ ansible_password }}' | |
'(?i)new (UNIX\s)?password': | |
- '{{ temp_passwd }}' | |
- '{{ temp_passwd }}' | |
failed_when: "result.rc != 0 and 'password updated successfully' not in result.stdout" | |
register: result | |
- name: Ensure {{ ansible_user }} has sudo privileges. | |
no_log: yes | |
connection: local | |
command: sshpass -p {{ temp_passwd }} -- ssh {{ ssh_options_tty | join(' ') }} '{{ ansible_user }}@{{ original_host }}' "echo {{ temp_passwd }} | sudo -S id > /dev/null 2>&1 || exit 1" | |
changed_when: false | |
failed_when: false | |
register: result | |
- fail: | |
msg: User {{ ansible_user }} does not have sudo privileges. Password for {{ ansible_user }}@{{ original_host }} set to '{{ temp_passwd }}' | |
when: result.rc != 0 | |
- name: Reset expired password to original password. | |
no_log: yes | |
connection: local | |
expect: | |
command: sshpass -p {{ temp_passwd }} -- ssh {{ ssh_options_tty | join(' ') }} '{{ ansible_user }}@{{ original_host }}' sudo passwd {{ ansible_user }}" | |
responses: | |
'(?i)\[sudo\] password for': | |
- '{{ temp_passwd }}' | |
'(?i)new (UNIX\s)?password': | |
- '{{ ansible_password }}' | |
- '{{ ansible_password }}' | |
failed_when: "result.rc != 0 and 'password updated successfully' not in result.stdout" | |
register: result | |
when: expired_password == true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank for that!
I've replaced the
connection: local
withdelegate_to: localhost
as it wasn't taking the proper python instance (and not the virtualenv running ansible) but it is working perfectly!