--- # 只读收敛入口;秘密首次创建、删除或轮换不放进 site.yml。 - name: 在任何主机变更前读取并校验已有凭据 hosts: localhost connection: local gather_facts: false tasks: - name: 要求有效的显式 Bao 身份 ansible.builtin.assert: that: - pg_bao_token | length > 0 - pg_bao_url is match('^https://') no_log: true - name: 读取两个实例的管理凭据 ansible.builtin.uri: url: "{{ pg_bao_url }}/v1/kv/data/{{ pg_secret_paths[item] }}" headers: X-Vault-Token: "{{ pg_bao_token }}" status_code: 200 loop: [prod, dev] register: pg_secret_response no_log: true - name: 整理并验证凭据结构 ansible.builtin.set_fact: pg_loaded_credentials: "{{ pg_loaded_credentials | default({}) | combine({item.item: item.json.data.data}) }}" loop: "{{ pg_secret_response.results }}" no_log: true - name: 拒绝缺失或短密码 ansible.builtin.assert: that: - pg_loaded_credentials[item].superuser_password | length >= 32 - pg_loaded_credentials[item].ayatori_password | length >= 32 - pg_loaded_credentials[item].ayatori_username == 'ayatori' loop: [prod, dev] no_log: true - name: 校验生产复制与 API 凭据 ansible.builtin.assert: that: - pg_loaded_credentials.prod.replication_password | length >= 32 - pg_loaded_credentials.prod.rest_password | length >= 32 no_log: true - name: 读取已有 etcd 消费者凭据 ansible.builtin.uri: url: "{{ pg_bao_url }}/v1/kv/data/{{ pg_etcd_secret_path }}" headers: X-Vault-Token: "{{ pg_bao_token }}" status_code: 200 register: pg_etcd_response no_log: true - name: 校验 etcd prefix 并交付内存引用 ansible.builtin.assert: that: - pg_etcd_response.json.data.data.username == 'patroni-pg-prod' - pg_etcd_response.json.data.data.prefix == '/homelab/patroni/pg-prod/' no_log: true - name: 保存短生命周期内存引用 ansible.builtin.set_fact: pg_loaded_etcd: "{{ pg_etcd_response.json.data.data }}" no_log: true