Ansible 变量与加密文件全解析:从基础定义到安全实践
Ansible 变量与加密文件全解析:从基础定义到安全实践
一、变量命名规则
- 变量名只能包含 字母、数字、下划线
- 必须以 字母开头(不能以数字或下划线开头)
- 区分大小写(
my_var
和My_Var
是不同变量) - 避免使用 Ansible 预定义的特殊变量名(如
inventory_hostname
、groups
等)
二、变量优先级(受版本影响可能会有略微不同)
1. Global 范围(最高优先级)
作用于整个 Ansible 执行过程,覆盖所有 Play 和主机,通常用于 “全局强制配置”。
主要来源:
-
命令行变量:通过
-e
/--extra-vars
传递,是优先级最高的变量(除非特殊配置),常用于临时覆盖其他变量。[student@master ansible]$ ansible-playbook abc.yml -e "env=prod app_port=8080"
-
Ansible 配置文件变量:在
ansible.cfg
中定义的变量(如remote_user
、inventory
),属于全局默认配置。 -
环境变量:系统环境变量中以
ANSIBLE_
开头的变量(如ANSIBLE_REMOTE_USER
),会覆盖ansible.cfg
中的对应配置。
2. Play 范围(中优先级)
作用于单个 Play 内的所有主机,仅在当前 Play 生效,常用于 “Play 级别的统一配置”。
-
set_fact定义变量:也是将值赋值给变量。
-
Play 的 vars 块:在 Play 中直接定义的变量,优先级高于 Host 范围变量。
示例:
- name: aaaaaahosts: node1vars: # Play 级变量- aaa: 11- bbb: 22tasks:- name: abcddebug:var: aaa,bbb [student@master ansible]$ ansible-playbook aaa.yml ok: [node1] => {"aaa,bbb": "(11, 22)" }
-
Play 的 vars_files 块:通过外部 YAML/JSON 文件引入的变量(如
vars/prod.yml
),与vars
块优先级相同(按定义顺序,后定义的覆盖先定义的)。[student@master ansible]$ vim bbb.yml aaa: 123 bbb: 321 - name: aaahosts: node5vars_files: /home/student/ansible/bbb.ymltasks:- name: abcddebug:var: aaa,bbb [student@master ansible]$ ansible-playbook aaa.yml ok: [node5] => {"aaa,bbb": "(123, 321)" }
-
Role 的 vars 目录:Role 内部
vars/main.yml
中定义的变量,优先级高于 Role 的defaults
,且属于 Play 范围(因为 Role 依附于 Play 执行)。 -
Role 的 defaults 目录:Role 内部
defaults/main.yml
中定义的变量,是 Role 的 “默认值”,优先级低于 Play 的 vars 和 Host 范围变量(注意:这是 Play 范围内的 “次优先级”,容易混淆)。
3. Host 范围(最低优先级)
作用于特定主机或主机组,仅对目标主机生效,常用于 “主机个性化配置”。
主要来源:
- Inventory 主机变量:直接在 Inventory 文件中为单个主机定义的变量(如
web1 ansible_host=192.168.1.10 app_port=80
)。 - Inventory 组变量:为 Inventory 中的主机组定义的变量(如在
group_vars/webservers.yml
中定义web_root=/var/www/html
),组内所有主机共享。 - Facts 变量:Ansible 自动收集的主机信息(如
ansible_os_family
、ansible_memtotal_mb
),变量名以ansible_
开头。默认情况下,Facts 变量不能被普通变量覆盖(需通过gather_facts: no
关闭,或修改ansible.cfg
中的allow_world_readable_facts
配置)。 - Register 变量:通过
register
关键字捕获任务执行结果的变量(如捕获command
模块的输出),仅在当前 Play 内的目标主机生效,属于 “临时 Host 变量”。
示例:
注册和定义变量的各种方式
ansible中定义变量的方式有很多种,大致有:
(1) 将模块的执⾏结果注册为变量
(2) 直接定义字典类型的变量;
(3) role中⽂件内定义变量;
(4) 命令⾏传递变量;
(5) 借助with_items迭代将多个task的结果赋值给⼀个变量;
(6) inventory中的主机或主机组变量;
(7) 内置变量。
(8)事实变量
(1) 将模块的执⾏结果注册为变量
在 Ansible 中,register
是一个非常实用的选项,它能将当前任务(task)的执行结果完整捕获并赋值给一个自定义变量。这个变量可以包含任务的输出内容、状态信息、返回码等细节,供后续任务进行判断、提取数据或做进一步处理。
核心作用
- 保存任务执行的详细结果(成功 / 失败状态、输出内容、返回码等)
- 实现 “基于前序任务结果的条件执行”
- 提取任务输出中的关键信息(如命令返回值、文件状态等)
基本语法
- name: 任务名称模块名:模块参数register: 自定义变量名 # 将结果赋值给该变量
例:
---
- name: aaahosts: node1tasks:- name: cat fileshell:cmd: sudo cat /tmp/1aaregister: abc- name: creste debugdebug:var: abc[student@master ansible]$ ansible-playbook aaa.yml PLAY [aaa] *********************************************************************************TASK [Gathering Facts] *********************************************************************
ok: [node1]TASK [cat file] ****************************************************************************
changed: [node1]TASK [creste debug] ************************************************************************
ok: [node1] => {"abc": {"changed": true,"cmd": "sudo cat /tmp/1aa","delta": "0:00:00.014112","end": "2025-09-01 20:19:39.712909","failed": false,"msg": "","rc": 0,"start": "2025-09-01 20:19:39.698797","stderr": "","stderr_lines": [],"stdout": "aaaaaaaa","stdout_lines": ["aaaaaaaa"]}
}PLAY RECAP *********************************************************************************
node1 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
如果只想要任务执行的结果
将var后面的值改成abc.stdout
---
- name: aaahosts: node1tasks:- name: cat fileshell:cmd: sudo cat /tmp/1aaregister: abc- name: creste debugdebug:var: abc.stdout[student@master ansible]$ ansible-playbook aaa.yml
TASK [creste debug] ************************************************************************
ok: [node1] => {"abc.stdout": "aaaaaaaa"
}
(2) 直接定义字典类型的变量;
在 Ansible 中,字典(dictionary)类型变量用于存储键值对(key-value)形式的数据,非常适合组织关联信息(如配置参数、多属性对象等)。直接定义字典变量的方式灵活,可在 Playbook、变量文件、set_fact
等场景中使用,语法遵循 YAML 格式。
一、基本语法(YAML 字典格式)
Ansible 中字典的基本格式为:
键值对
字典名:键1: 值1键2: 值2键3: 值3 # 值可以是字符串、数字、列表、甚至嵌套字典
键(key)通常不需要引号(特殊字符除外),值(value)支持多种类型(字符串、数字、列表、布尔值、嵌套字典等)。
实列在上面Play 范围(中优先级)中有写
(3) role中⽂件内定义变量;
未学之后补
(4) 命令⾏传递变量;
在 Ansible 中,通过命令行传递变量是一种灵活的方式,常用于临时覆盖配置、动态指定参数(如环境标识、版本号等)。命令行传递的变量优先级最高,会覆盖 Playbook、变量文件、Inventory 等其他位置定义的同名变量,非常适合临时调整任务行为。
核心语法
通过 -e
或 --extra-vars
选项传递变量,基本格式:
ansible-playbook 剧本名.yml -e "变量名=值" # 单个变量
ansible-playbook 剧本名.yml -e "变量1=值1 变量2=值2" # 多个变量(空格分隔)
列:
---
- name: aaahosts: node1tasks:- name: debugdebug:msg: aaa={{ccc}} bbb={{ddd}}[student@master ansible]$ ansible-playbook -e "ccc=111 ddd=222" aaa.yml ok: [node1] => {"msg": "aaa=111 bbb=222"
}
(5) 借助with_items迭代将多个task的结果赋值给⼀个变量;
在 Ansible 中,当使用 with_items
(或较新的 loop
)进行迭代时,任务会对列表中的每个项执行一次。此时,通过 register
注册的变量会自动包含一个 results
列表,存储每个迭代项的执行结果。我们可以通过这个 results
列表,将多个迭代任务的结果汇总到一个变量中,实现 “将多个 task 结果赋值给一个变量” 的效果。
核心原理
- 当任务使用
with_items
循环时,register
注册的变量会生成一个results
属性(列表类型)。 results
列表中的每个元素对应一次迭代的结果,包含当前迭代项(item
)和该次任务的详细输出(如stdout
、rc
、stat
等)。- 可通过遍历
results
列表,提取每个迭代的结果,实现对多个任务结果的集中处理。
例:
---
- name: aaahosts: node1tasks:- name: debugshell:cmd: echo {{ item }}with_items:- aaaa- bbbb- ccccregister: cy- name: look cydebug:var: cy.results[{{ item }}].stdoutwith_items:- 0- 1- 2[student@master ansible]$ ansible-playbook aaa.yml *******************************************************************************
changed: [node1] => (item=aaaa)
changed: [node1] => (item=bbbb)
changed: [node1] => (item=cccc)TASK [look cy] *****************************************************************************
ok: [node1] => (item=0) => {"ansible_loop_var": "item","cy.results[0].stdout": "aaaa","item": 0
}
ok: [node1] => (item=1) => {"ansible_loop_var": "item","cy.results[1].stdout": "bbbb","item": 1
}
ok: [node1] => (item=2) => {"ansible_loop_var": "item","cy.results[2].stdout": "cccc","item": 2
}
(6) inventory中的主机或主机组变量;
在 Ansible 中,inventory( inventory 文件或动态 inventory )不仅用于定义主机和主机组,还可以直接为主机或主机组定义变量。这些变量可以在 Playbook、模板、模块中直接引用,用于定制针对特定主机或主机组的操作。
1. 主机变量(Host Variables)
主机变量是针对单个主机定义的变量,仅对该主机生效。
通常用于描述主机的个性化属性(如 IP、端口、特定配置等)。
定义方式(在 inventory 文件中):
node1 aaa=1111
node2 aaa=2222
node3 aaa=3333
node4
node5
在剧本中
---
- name: aaaaaahosts: node1,node2,node3tasks:- name: abcddebug:var: aaa
运行结果
[student@master ansible]$ ansible-playbook bbb.yml PLAY [aaaaaa] ******************************************************************************TASK [Gathering Facts] *********************************************************************
ok: [node1]
ok: [node3]
ok: [node2]TASK [abcd] ********************************************************************************
ok: [node1] => {"aaa": 1111
}
ok: [node2] => {"aaa": 2222
}
ok: [node3] => {"aaa": 3333
}
也可用组的形式
inventory
[t1]
node1
node2[t2]
node3
node4[t3]
node5[t1:vars]
aaa=123456[t2:vars]
aaa=654321[t3:vars]
aaa=abcdef
剧本
---
- name: aaaaaahosts: alltasks:- name: abcddebug:var: aaa
运行结果
[student@master ansible]$ ansible-playbook bbb.yml ok: [node1] => {"aaa": 123456
}
ok: [node2] => {"aaa": 123456
}
ok: [node3] => {"aaa": 654321
}
ok: [node4] => {"aaa": 654321
}
ok: [node5] => {"aaa": "abcdef"
}
创建host和组的专属存放变量文件的目录
- host_vars 目录(主机专属变量)
- 路径:
/etc/ansible/host_vars/
(全局)或 Playbook 所在目录下的host_vars/
(项目内)。 - 文件名与主机名一致,用于定义特定主机的变量。
- 路径:
- group_vars 目录(组专属变量)
- 路径:
/etc/ansible/group_vars/
(全局)或 Playbook 所在目录下的group_vars/
(项目内)。 - 文件名与组名一致,用于定义特定组内所有主机共享的变量。
- 路径:
[student@master ansible]$ mkdir host_vars
[student@master ansible]$ mkdir group_vars[student@master ansible]$ vim host_vars/node1
aaa: 12345678[student@master ansible]$ vim host_vars/node1.yml
aaa: abcdefg[student@master ansible]$ vim group_vars/t1
bbb: 1234
剧本
---
- name: aaaaaahosts: node1tasks:- name: abcddebug:var: aaa,bbb
运行效果
[student@master ansible]$ ansible-playbook bbb.yml PLAY [aaaaaa] ******************************************************************************TASK [Gathering Facts] *********************************************************************
ok: [node1]TASK [abcd] ********************************************************************************
ok: [node1] => {"aaa,bbb": "(12345678, 1234)"
}
删除/etc/ansible/host_vars/node1 保留/etc/ansible/host_vars/node1.yml,再次执行playbook
[student@master ansible]$ ansible-playbook bbb.yml PLAY [aaaaaa] ******************************************************************************TASK [Gathering Facts] *********************************************************************
ok: [node1]TASK [abcd] ********************************************************************************
ok: [node1] => {"aaa,bbb": "('abcdefg', 1234)"
}
(7)事实变量与内置变量
1. 事实变量(Facts Variables)
- 定义:Ansible 在执行 Playbook 时,通过
setup
模块自动从目标主机收集的系统 / 环境信息,是 “关于目标主机的动态事实”。 - 本质:是目标主机的 “属性快照”,内容完全依赖目标主机的实际状态(如操作系统版本、IP 地址、硬件配置等),不同主机的事实变量可能完全不同。
- 特点:默认自动收集(可通过
gather_facts: no
关闭),内容动态、主机相关。
2. 内置变量(Built-in Variables)
- 定义:Ansible 框架自带的、不依赖目标主机的元数据变量,用于获取 Ansible 运行时信息、Inventory 配置信息或 Play/Task 上下文。
- 本质:是 “关于 Ansible 自身或执行上下文的固定 / 半固定信息”,不依赖目标主机,仅与 Ansible 环境、Inventory 配置或当前 Play 逻辑相关。
- 特点:无需主动收集,Playbook 中可直接引用;内容静态(如 Ansible 版本)或基于配置(如 Inventory 分组),与目标主机无关。
1. 常用事实变量(Facts)
通过ansible node1 -m setup 可以查询node1主机所有的事实变量
ansible_hostname
:目标主机的主机名(如web-server-01
)。ansible_os_family
:目标主机的操作系统家族(如RedHat
、Debian
、Windows
),常用于条件判断(例:RedHat 系装yum
包,Debian 系装apt
包)。ansible_enp1s0.ipv4.address
:目标主机网卡enp1s0
的 IPv4 地址(如192.168.122.10
)。ansible_default_ipv4.address
:目标主机的默认网卡ipv4地址ansible_memtotal_mb
:目标主机的总内存(单位:MB,如16384
)。ansible_pkg_mgr
:目标主机默认的包管理器(如dnf
、apt
、pip
)。ansible_fqdn
: 目标主机完全合格域名(FQDN)- ansible_bios_version
ansible_devices.vda.size
: vda硬盘大小ansible_devices.vdb.size
: vdb硬盘大小ansible_lvm.vgs
: 逻辑卷中卷组
2. 常用内置变量(Built-in)
-
ansible_version
:当前 Ansible 的版本信息(字典类型,如ansible_version.full
为2.16.3
),常用于确保 Playbook 兼容特定版本。 -
inventory_hostname
:目标主机在 Inventory 文件中定义的 “主机名 / 别名”(如 Inventory 中写web01 ansible_host=192.168.1.100
,则inventory_hostname
为web01
)。 -
play_hosts
:当前 Play 的目标主机列表(列表类型,如["web01", "web02"]
),常用于批量操作(例:获取所有目标主机 IP)。 -
ansible_play_name
:当前 Play 的名称(如 Play 定义name: 部署Web服务
,则此变量值为部署Web服务
)。 -
groups
-
group_names
:当前主机所属的 Inventory 分组列表(如["web_servers", "prod"]
),常用于按分组执行任务。 -
groups.all
所有清单主机 -
groups.ungrouped
:未分组的主机 -
inventory_dir
:Inventory 文件所在的目录路径(如/etc/ansible/inventory
)。
set_fact定义变量
在 Ansible 中,set_fact
是用于主动定义自定义事实变量(custom facts) 的模块。这些变量会被添加到主机的事实(facts)集合中,可在后续任务、甚至跨 Play 中像其他内置 facts(如 ansible_hostname
)一样直接引用。set_fact
更接近 “动态变量赋值” 的逻辑,尤其适合基于现有变量(如 facts、register
结果、其他变量)构造新变量。
例
---
- name: aaahosts: alltasks:- name: set_fact #将目标主机的域名变量和ip地址变量写成1一个变量set_fact:dns_and_ip: "{{ ansible_fqdn }}:{{ ansible_enp1s0.ipv4.address }} "- name: debug1debug:msg: "{{ ansible_hostname }} is {{ dns_and_ip }} "[student@master ansible]$ ansible-playbook aaa.yml
ok: [node1] => {"msg": "node1 is node1.example.com:192.168.122.10 "
}
ok: [node2] => {"msg": "node2 is node2.example.com:192.168.122.20 "
}
ok: [node3] => {"msg": "node3 is node3.example.com:192.168.122.30 "
}
ok: [node4] => {"msg": "node4 is node4.example.com:192.168.122.40 "
}
ok: [node5] => {"msg": "node5 is node5.example.com:192.168.122.50 "
}
ansible_vault使用详解
Ansible Vault 是 Ansible 自带的敏感信息加密工具,用于加密包含密码、API 密钥、数据库凭证等敏感数据的文件(如变量文件、inventory 清单、playbook 片段等),防止敏感信息以明文形式存储在代码或配置文件中。
ansible_vault核心操作命令
创建加密的文件:
要创建新的加密文件,使用命令
ansible-vault create [选项] 文件名
常用选项:
- –vault-id 标识@密码文件`:指定加密密码(多密码场景)。
--ask-vault-pass
:手动输入密码(默认方式)。
例
[student@master ansible]$ ansible-vault create ccc.yml
New Vault password: #输入密码
Confirm New Vault password: #再次输入密码
使用vim和cat查看文件就会显示加密信息
[student@master ansible]$ cat ccc.yml
$ANSIBLE_VAULT;1.1;AES256
36363464306637663362313261363430636565626364663233663030396136343862386161323565
6562643230383161623263663235383239613137353736650a396166656163333763373739633561
.......[student@master ansible]$ vim ccc.yml
$ANSIBLE_VAULT;1.1;AES256
36363464306637663362313261363430636565626364663233663030396136343862386161323565
6562643230383161623263663235383239613137353736650a396166656163333763373739633561
......
零时查看加密文件:
查看加密信息就要使用命令
ansible-vault view [选项] 文件名
例
[student@master ansible]$ ansible-vault view ccc.yml
Vault password: #输入密码
---
- name: ccchosts: node1tasks: - name: debug1debug: msg: echo 123456
输入密码后即可查看内容
修改加密文件:
修改使用命令
ansible-vault edit [选项] 文件名
例:
[student@master ansible]$ ansible-vault edit ccc.yml
Vault password: #输入密码
---
- name: ccchosts: node1tasks:- name: debug1debug:msg: echo 123456
解密加密文件:
解密的命令
ansible-vault decrypt [选项] 文件名
常用选项:
--output 新文件名
:解密到新文件(保留原加密文件)。
例
[student@master ansible]$ ansible-vault decrypt ccc.yml
Vault password:
Decryption successful
之后就可以直接查看和修改ccc.yml
[student@master ansible]$ cat ccc.yml
---
- name: ccchosts: node1tasks: - name: debug1debug: msg: echo 123456
对已有的明文文件加密:
对文件加密使用
ansible-vault encrypt [选项] 文件名1 文件名2 ...
例
[student@master ansible]$ ansible-vault encrypt ccc.yml
New Vault password:
Confirm New Vault password:
Encryption successful
再次查看就会发现
[student@master ansible]$ cat ccc.yml
$ANSIBLE_VAULT;1.1;AES256
61373961663061356430643531613730623135373936663732353335393638643739623635613332
3530646333376437326330323532616330643131376234650a346362613663656564313635316466
..........
重设密码:
重设密码使用命令:
ansible-vault rekey [选项] 文件名1 文件名2 ...
例
[student@master ansible]$ ansible-vault rekey ccc.yml
Vault password: #旧密码
New Vault password: #新密码
Confirm New Vault password: #再出输入新密码
Rekey successful
ansible-vault encrypt_string
执行加密剧本
如果直接执行加密剧本
[student@master ansible]$ ansible-playbook ccc.yml
ERROR! Attempting to decrypt but no vault secrets found
这时候就需要命令
ansible-playbook 文件名 --vault-id @prompt
或者
ansible-playbook 文件名 --ask-vault-pass
例
[student@master ansible]$ ansible-playbook ccc.yml --ask-vault-pass
Vault password: #输入密码PLAY [ccc] *********************************************************************************TASK [Gathering Facts] *********************************************************************
ok: [node1]TASK [debug1] ******************************************************************************
ok: [node1] => {"msg": "echo 123456"
}
用装有密码的文件输入密码
加上选项 --vault-id 存放密码的文件
#创建存放密码的文件
[student@master ansible]$ echo 3edc4rfv > pass
#将文件设置为仅自己可读写提升安全性
[student@master ansible]$ chmod 600 pass
#运行加密脚本
[student@master ansible]$ ansible-playbook ccc.yml --vault-id passPLAY [ccc] ********************************************************************************TASK [Gathering Facts] ********************************************************************
ok: [node1]TASK [debug1] *****************************************************************************
ok: [node1] => {"msg": "echo 123456"
}
执行使用了加密文件的剧本
创建一个加密的存放变量的文件
[student@master ansible]$ ansible-vault create var.yml
New Vault password:
Confirm New Vault password:
创建密码文件
[student@master ansible]$ echo 123456 > varpass
[student@master ansible]$ chmod 600 varpass
编写剧本
---
- name: ccchosts: node1vars_files: /home/student/ansible/var.ymltasks:- name: debug1debug:msg: "{{aaa,bbb}}"
如果直接运行就会
[student@master ansible]$ ansible-playbook ccc.yml
ERROR! Attempting to decrypt but no vault secrets found
需要带上密码文件的地址
[student@master ansible]$ ansible-playbook ccc.yml --vault-id varpassPLAY [ccc] ********************************************************************************TASK [Gathering Facts] ********************************************************************
ok: [node1]TASK [debug1] *****************************************************************************
ok: [node1] => {"msg": "(112233, 332211)"
}