从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,当前仅需实现读取/生成的分支逻辑)
问题分析
核心问题在于两个关键点:
- 未定义变量的直接引用:
vars.yaml中使用vars['passwort_' + host]直接引用变量,当该变量不存在时会直接抛出未定义错误,而非返回空值,导致变量定义失败 - 变量求值顺序:变量文件在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
相关产品推荐
相关产品推荐

