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

Ansible中如何遍历字典数组验证多域名证书与密钥匹配?

Ansible批量验证证书公钥匹配及过期状态问题解决

我在Ansible数据操作上经常卡壳,不太熟悉Python和字典对象,下面这个批量验证证书的例子能概括我的困惑:

需要验证一批证书,官方文档只有单域名示例,现在要遍历多个域名做验证,证书存储目录结构如下:

certs/
├── domain.com
│   ├── domain.com.pem
│   └── domain.com.key
└── domain.org
    ├── domain.org.key
    └── domain.org.pem

我写的Playbook如下:

---
- name: "check certs"
  hosts: localhost
  gather_facts: no
  vars:
    domain_names:
      - domain.com
      - domain.org
    certs_folder: certs
  tasks: 
    - name: Get certificate information
      community.crypto.x509_certificate_info:
        path: "{{ certs_folder }}/{{ item }}/{{ item }}.pem"
        # for valid_at, invalid_at and valid_in
      register: result_certs
      loop: "{{ domain_names }}"
      failed_when: 0

    - name: Get private key information
      community.crypto.openssl_privatekey_info:
        path: "{{ certs_folder }}/{{ item }}/{{ item }}.key"
      register: result_privatekey
      loop: "{{ domain_names }}"
      failed_when: 0

    - name: Check cert and key match << DOES NOT WORK >>>
      assert: 
        that:
          - result_certs[ {{ item }} ].public_key == result_privatekey[ {{ item }} ].public_key
          # - ... other checks ...
          - not result[ {{ item }} ].expired
      loop: "{{ domain_names }}"

执行后得到的result_certs和result_privatekey变量,其results字段是字典数组,结构如下:

"result_certs": {
        "changed": false,
        "msg": "All items completed",
        "results": [
            {
                "expired": false,
                "item": "domain.org",
                "public_key": "<<PUBLIC KEY>>"
            },
            {
                "expired": false,
                "item": "domain.com",
                "public_key": "<<PUBLIC KEY>>"
            }
        ],
        "skipped": false
    }
"result_privatekey": {
    "changed": false,
    "msg": "All items completed",
    "results": [
    {
        "item": "domain.org",
        "public_key": "<< PUBLIC KEY >>"
    },
    {
        "item": "domain.com",
        "public_key": "<< PUBLIC KEY >>"
    }
    ],
    "skipped": false
}

我需要在assert任务中引用类似result_privatekey.results[item='domain.org'的字典].public_key的元素,来验证证书与密钥的公钥一致,以及证书未过期。我知道map和selectattr过滤器可能有用,但文档不够清晰,需要具体示例。


解决方案

方法1:直接用selectattr+first过滤器匹配域名

在assert任务中,通过selectattr('item', 'equalto', item)从results数组中筛选出当前域名对应的字典,再用first取第一个匹配结果(因为每个域名只会对应一条结果),之后就能正常读取字段了。

修改后的assert任务如下:

- name: Check cert and key match
  assert: 
    that:
      - (result_certs.results | selectattr('item', 'equalto', item) | first).public_key == 
        (result_privatekey.results | selectattr('item', 'equalto', item) | first).public_key
      - not (result_certs.results | selectattr('item', 'equalto', item) | first).expired
    fail_msg: "Domain {{ item }}: certificate validation failed"
    success_msg: "Domain {{ item }}: certificate is valid and matches private key"
  loop: "{{ domain_names }}"

方法2:提前将results转换为字典(更简洁)

如果觉得每次都写过滤器麻烦,可以先把results数组转换成以域名(item值)为键的字典,后续直接通过域名索引取值。

添加一个任务来生成转换后的字典:

- name: Transform results into domain-keyed dictionaries
  set_fact:
    certs_info_dict: "{{ result_certs.results | items2dict(key_name='item', value_name='') }}"
    privatekeys_info_dict: "{{ result_privatekey.results | items2dict(key_name='item', value_name='') }}"

之后的assert任务就能简化成:

- name: Check cert and key match (using dictionaries)
  assert: 
    that:
      - certs_info_dict[item].public_key == privatekeys_info_dict[item].public_key
      - not certs_info_dict[item].expired
    fail_msg: "Domain {{ item }}: certificate validation failed"
    success_msg: "Domain {{ item }}: certificate is valid and matches private key"
  loop: "{{ domain_names }}"

说明:items2dict过滤器会把数组里的每个字典,以指定的key_name字段值作为键,整个字典作为值,生成新的字典,这样直接用域名索引就能拿到对应的数据,写法更直观。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 13:05:19