Ansible连接失败时如何继续执行play实现多凭据自动切换
Ansible双凭据自动切换连接实现方案
原有实现的问题
你最初编写的block/rescue逻辑如下:
--- - name: "Connection attempt 1" block: - name: "Credentials" set_fact: ansible_ssh_user: "{{ username_from_vault }}" ansible_password: "{{ password_from_vault }}" - name: "Try connection" ping: rescue: - name: "Other credentials" set_fact: ansible_ssh_user: "{{ other_username_from_vault }}" ansible_password: "{{ other_password_from_vault }}" - name: "Try connection again" ping:
这个逻辑无法生效的核心原因有两个:
block/rescue结构仅能捕获任务执行阶段返回的失败状态,SSH连接建立阶段触发的UNREACHABLE(主机不可达/认证失败)错误发生在任务正式执行前,不属于任务执行失败范畴,不会触发rescue分支,这也是你加failed_when: false也无法阻止play终止的根本原因——任务级容错参数对连接阶段的错误不生效。- 同个play内通过
set_fact修改连接变量存在时序和连接缓存问题:Ansible会在play初始化阶段加载主机连接参数,且默认复用已建立的SSH连接,即便你通过set_fact修改了凭据变量,后续任务也可能直接复用之前失败的连接,不会重新建立连接。
你提到的本地委托sshpass执行的方案确实存在密码泄露风险:密码会明文出现在本地进程的命令行参数中,同机其他用户可通过进程列表直接获取密码,不推荐在生产环境使用。
推荐实现方案
采用拆分前置探测Play的方式实现,全程使用Ansible原生SSH连接插件,无密码泄露风险,同时可以正确捕获连接失败状态,自动适配两种凭据的主机。
完整实现逻辑如下:
--- # 第一步:用临时凭据探测所有主机 - name: Probe connection with temporary credentials hosts: all gather_facts: false vars: ansible_ssh_user: "{{ username_from_vault }}" ansible_password: "{{ password_from_vault }}" tasks: - name: Attempt connection with temp credentials ping: register: temp_cred_result ignore_unreachable: true ignore_errors: true no_log: true - name: Mark hosts accessible via temp credentials set_fact: valid_ssh_user: "{{ username_from_vault }}" valid_ssh_password: "{{ password_from_vault }}" when: temp_cred_result is succeeded and temp_cred_result.ping == 'pong' # 第二步:对临时凭据连接失败的主机,用正式凭据探测 - name: Probe connection with formal credentials hosts: all gather_facts: false vars: ansible_ssh_user: "{{ other_username_from_vault }}" ansible_password: "{{ other_password_from_vault }}" tasks: - name: Attempt connection with formal credentials ping: register: formal_cred_result ignore_unreachable: true ignore_errors: true no_log: true when: valid_ssh_user is not defined - name: Mark hosts accessible via formal credentials set_fact: valid_ssh_user: "{{ other_username_from_vault }}" valid_ssh_password: "{{ other_password_from_vault }}" when: - valid_ssh_user is not defined - formal_cred_result is succeeded - formal_cred_result.ping == 'pong' # 可选:校验所有主机都能被正常连接 - name: Validate credential probe result hosts: all gather_facts: false tasks: - name: Fail on hosts with no valid credentials fail: msg: "Host is unreachable with both temporary and formal credentials" when: valid_ssh_user is not defined # 第三步:使用探测到的有效凭据执行业务任务 - name: Run actual business tasks hosts: all gather_facts: true vars: ansible_ssh_user: "{{ valid_ssh_user }}" ansible_password: "{{ valid_ssh_password }}" tasks: # 此处替换为实际需要执行的业务任务即可 - name: Verify final connection status ping:
方案说明
- 核心用到
ignore_unreachable: true参数,这是Ansible专门为连接阶段错误设计的容错开关,开启后主机连接失败不会终止整个play的执行,会将错误状态写入注册变量中供后续判断使用。 - 拆分为独立Play的方式可以规避Ansible的连接缓存问题:每个独立Play启动时都会重新加载连接参数,为未建立连接的主机重新创建SSH连接,不会复用之前的失败连接。
- 全程使用Ansible原生连接插件,敏感密码变量由Ansible内部机制保护,配合
no_log: true参数可以避免密码出现在控制台输出、日志文件中,完全规避sshpass方案的泄露风险。 - 无需人工标记主机状态,自动识别主机当前使用的凭据类型,适配从状态A到状态B的迁移过程。
版本兼容提示:Ansible 2.9及更早版本需要同时配置
ignore_unreachable: true和ignore_errors: true才能正确捕获连接错误,2.10及以上版本仅配置ignore_unreachable: true即可生效。
内容的提问来源于stack exchange,提问作者Lirion
相关产品推荐
相关产品推荐

