You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从Ansible Vault动态获取密码的Playbook报错求助

Ansible Vault动态读取/生成密码问题排查与解决

尝试从Ansible Vault文件中动态读取对应主机的密码变量,逻辑为:变量存在则读取,不存在则自动生成新密码。但当前执行时始终无法读取现有密码,总是生成新密码,且执行DEBUG existing_secret任务时触发变量未定义报错,错误信息如下:

fatal: [abc.domain.net]: FAILED! => {"msg": "The task includes an option with an undefined variable. 
The error was: {{ pw_key_from_vault }}: 
{{ vars['passwort_' + host] }}: 'dict object' has no attribute 'passwort_abc'. 'dict object' has no attribute 'passwort_abc'. 
{{ vars['passwort_' + host] }}: 'dict object' has no attribute 'passwort_abc'. 'dict object' has no attribute 'passwort_abc'. 
{{ pw_key_from_vault }}: {{ vars['passwort_' + host] }}: 'dict object' has no attribute 'passwort_abc'. 'dict object' has no attribute 'passwort_abc'. 
{{ vars['passwort_' + host] }}: 'dict object' has no attribute 'passwort_abc'. 'dict object' has no attribute 'passwort_abc'

The error appears to be in './deploy_postgresql.yaml': line 11, column 7, but may be 
elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

pre_tasks:
   - name: DEBUG existing_secret
     ^ here\n"}

复现流程

  • Playbook加载vars_files中的Vault文件和普通变量文件
  • 执行DEBUG existing_secret任务,尝试打印Vault中存在的密钥
  • 执行GENERATE special_secret or fetch from vault_file任务,创建special_secret变量,优先使用Vault现有值,不存在则生成新密码
  • 执行DEBUG special_secret任务,打印最终的special_secret值

相关代码

Playbook代码

---
- name: Deploy something
  hosts: abc.domain.net, klm.domain.net, xyz.domain.net
  vars_files:
    - /path/to/vault.yaml
    - /path/to/vars.yaml
  pre_tasks:
    - name: DEBUG existing_secret
      ansible.builtin.debug:
        msg: "{{ existing_secret | d('I don't have any secret to show yet') }}"

    - name: "GENERATE special_secret or fetch from vault_file"
      ansible.builtin.set_fact:
        special_secret : "{{ existing_secret | default(generate_secret_string) }}"

    - name: DEBUG special_secret
      ansible.builtin.debug:
        msg: "{{ special_secret }}"

变量文件(vars.yaml)代码

---
hostname: "{{ inventory_hostname }}"
host: "{{ hostname | regex_replace('^(.*?).domain.net$', '\\1') }}"
pw_key_from_vault: "{{ vars['passwort_' + host] }}"
existing_secret: "{{ pw_key_from_vault }}"
generate_secret_string: "{{ lookup('ansible.builtin.password','/dev/null length=30 chars=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!§$@&/()=#+?_.,') }}"

Vault文件(vault.yaml)代码

---
passwort_abc: supersecretabc
passwort_xyz: supersecretklm

预期需求

  • 当Vault中存在对应主机的passwort_<主机前缀>变量时,正确读取该值
  • 当Vault中无对应变量时,自动生成符合规则的新密码(后续需写入Vault,当前仅需实现读取/生成的分支逻辑)

问题分析

核心问题在于两个关键点:

  1. 未定义变量的直接引用:vars.yaml中使用vars['passwort_' + host]直接引用变量,当该变量不存在时会直接抛出未定义错误,而非返回空值,导致变量定义失败
  2. 变量求值顺序:变量文件在play执行前加载,此时直接引用不存在的Vault变量会触发致命错误,后续任务无法正常执行

解决方案

方案1:安全读取变量(修改vars.yaml)

使用lookup('vars', ..., default='')替代直接vars[var_name],安全处理变量不存在的场景,避免加载阶段报错:

---
hostname: "{{ inventory_hostname }}"
host: "{{ hostname | regex_replace('^(.*?).domain.net$', '\\1') }}"
pw_key_from_vault: "{{ lookup('vars', 'passwort_' + host, default='') }}"
existing_secret: "{{ pw_key_from_vault if pw_key_from_vault != '' else omit }}"
generate_secret_string: "{{ lookup('ansible.builtin.password','/dev/null length=30 chars=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!§$@&/()=#+?_.,') }}"

方案2:任务中动态判断(修改Playbook)

将动态变量判断逻辑移到任务执行阶段,避免变量加载阶段的错误,同时简化变量文件:

修改后的Playbook pre_tasks

pre_tasks:
  - name: DEBUG existing_secret
    ansible.builtin.debug:
      msg: "{{ lookup('vars', 'passwort_' + host, default='I don't have any secret to show yet') }}"

  - name: "GENERATE special_secret or fetch from vault_file"
    ansible.builtin.set_fact:
      special_secret: "{{ lookup('vars', 'passwort_' + host, default=generate_secret_string) }}"

  - name: DEBUG special_secret
    ansible.builtin.debug:
      msg: "{{ special_secret }}"

简化后的vars.yaml

---
hostname: "{{ inventory_hostname }}"
host: "{{ hostname | regex_replace('^(.*?).domain.net$', '\\1') }}"
generate_secret_string: "{{ lookup('ansible.builtin.password','/dev/null length=30 chars=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!§$@&/()=#+?_.,') }}"

关键优化说明

  • 使用lookup('vars', var_name, default='')是安全读取动态变量的标准方式,支持默认值处理
  • 将逻辑移到任务阶段,能避免变量加载时的致命错误,让default过滤器正常触发分支逻辑
  • 使用omit标记未定义变量,可让后续任务的default逻辑更清晰

内容的提问来源于stack exchange,提问作者dbalucas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 13:18:04