我有一个新安装的 Linux 发行版。它有一个使用默认密码的普通用户和一个锁定的 root 帐户(root 没有密码 - 不能直接通过 SSH 连接)。我希望能够运行 ansible playbook 来配置此服务器,并通过更改其密码来锁定此默认帐户,而无需执行额外的带外步骤。
我的剧本所做的大部分设置都需要 root 权限,因此它配置为以默认用户身份 ssh 登录,成为 root 权限,然后运行所有命令。这很好。问题是更改密码。
如果我尝试使用用户模块让 ansible 更改用户的密码,它会成功,但此后的所有任务都会失败。即使我将更改作为剧本中的最后一步,所有应该在最后运行的处理程序都会失败。
我在网上看到过针对类似问题的两个建议:
- 使用 RSA 密钥
- 使用初始玩法以某种方式测试并更改密码
使用 RSA 密钥需要您提前设置 RSA,因此不是带内密钥。
我一直在尝试使用初始播放以某种方式做到这一点,但到目前为止,第二次初始播放使用默认密码登录失败,ansible 因错误退出,并忽略其他任务和下一个播放。
还有一种方法可以使用 ssh-pass 来实现,如下图所示这里,这应该可以工作,但这似乎更像是一种黑客攻击,并且 ssh-pass 并不总是容易获得,就像在运行 ansible 的 MacOS 机器上一样。
讨论了类似的话题这里十多年前就已经出现了,但看起来 Dave 通过将 Linux 设置为在您尝试以默认用户身份登录时显示“帐户已禁用”消息,并更改用户来解决这个问题,这听起来也应该可行,但与简单地更改默认用户的密码不同。
有什么办法可以通过 ansible 来更改正在运行的用户的密码,而无需断开连接?
答案1
有没有办法让 Ansible 尝试默认密码,如果失败则继续运行剧本?
这是一个例子,它并不完全符合您提到的,但可能是一个起点。
---
# 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: {}
答案2
哇哦,我太笨了。我简直不敢相信解决方案竟然如此简单。
我的剧本现在看起来像这样:
---
- hosts: RaspberryPis
become: True
become_user: root
tasks:
- name: Do stuff
notify:
- restart some service
handlers:
- name: restart some service
systemd:
name: some_service
state: restarted
- hosts: RaspberryPis
become: True
become_user: root
tasks:
- name: Set pi password
user:
name: pi
password: "{{ 'test'|password_hash('sha512', 'mysalt') }}"
我使用 来运行它ansible-playbook --ask-pass
。第一次运行时,我给它默认密码。下一次运行时,我给它新密码。基本上,它始终是设备当前的密码。
当然,出于安全原因,您希望新密码是一个来自 ansible 保险库的变量,或类似的东西,但这就是想法,而且它似乎有效。
将其放在最后的单独剧本中可确保主剧本中的处理程序在密码更改之前运行。这样,更改用户密码实际上是最后一步。
我不敢相信我以前竟然从没想过这个。
这是我能做到的最简单的事情。有没有办法让 Ansible 尝试默认密码,并在失败时继续运行剧本?这样,我的保险库中就可以同时拥有默认密码和新密码,并且只需要提供保险库密码 - 而不是当前用户密码和保险库密码?