mirror of
https://github.com/kubernetes-sigs/kubespray.git
synced 2026-03-17 17:07:36 -02:30
Vault security hardening and role isolation
This commit is contained in:
21
roles/vault/tasks/shared/auth_backend.yml
Normal file
21
roles/vault/tasks/shared/auth_backend.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
|
||||
- name: shared/auth_backend | Test if the auth backend exists
|
||||
uri:
|
||||
url: "{{ vault_leader_url }}/v1/sys/auth/{{ auth_backend_path }}/tune"
|
||||
headers: "{{ vault_headers }}"
|
||||
validate_certs: false
|
||||
ignore_errors: true
|
||||
register: vault_auth_backend_check
|
||||
|
||||
- name: shared/auth_backend | Add the cert auth backend if needed
|
||||
uri:
|
||||
url: "{{ vault_leader_url }}/v1/sys/auth/{{ auth_backend_path }}"
|
||||
headers: "{{ vault_headers }}"
|
||||
method: POST
|
||||
body_format: json
|
||||
body:
|
||||
description: "{{ auth_backend_description|d('') }}"
|
||||
type: "{{ auth_backend_type }}"
|
||||
status_code: 204
|
||||
when: vault_auth_backend_check|failed
|
||||
21
roles/vault/tasks/shared/cert_auth_mount.yml
Normal file
21
roles/vault/tasks/shared/cert_auth_mount.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
|
||||
- include: ../shared/mount.yml
|
||||
vars:
|
||||
mount_name: auth-pki
|
||||
mount_options:
|
||||
description: PKI mount to generate certs for the Cert Auth Backend
|
||||
config:
|
||||
default_lease_ttl: "{{ vault_default_lease_ttl }}"
|
||||
max_lease_ttl: "{{ vault_max_lease_ttl }}"
|
||||
type: pki
|
||||
|
||||
- name: shared/auth_mount | Create a dummy role for issuing certs from auth-pki
|
||||
uri:
|
||||
url: "{{ hostvars[groups.vault|first]['vault_leader_url'] }}/v1/auth-pki/roles/dummy"
|
||||
headers: "{{ hostvars[groups.vault|first]['vault_headers'] }}"
|
||||
method: POST
|
||||
body_format: json
|
||||
body:
|
||||
{'allow_any_name': true}
|
||||
status_code: 204
|
||||
19
roles/vault/tasks/shared/check_etcd.yml
Normal file
19
roles/vault/tasks/shared/check_etcd.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
|
||||
- name: check_etcd | Check if etcd is up an reachable
|
||||
uri:
|
||||
url: "{{ vault_etcd_url }}/health"
|
||||
validate_certs: no
|
||||
failed_when: false
|
||||
register: vault_etcd_health_check
|
||||
|
||||
- name: check_etcd | Set fact based off the etcd_health_check response
|
||||
set_fact:
|
||||
vault_etcd_available: "{{ vault_etcd_health_check.get('json', {}).get('health')|bool }}"
|
||||
|
||||
- name: check_etcd | Fail if etcd is not available and needed
|
||||
fail:
|
||||
msg: >
|
||||
Unable to start Vault cluster! Etcd is not available at
|
||||
{{ vault_etcd_url }} however it is needed by Vault as a backend.
|
||||
when: vault_etcd_needed|d() and not vault_etcd_available
|
||||
31
roles/vault/tasks/shared/check_vault.yml
Normal file
31
roles/vault/tasks/shared/check_vault.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
|
||||
# Stop temporary Vault if it's running (can linger if playbook fails out)
|
||||
- name: stop vault-temp container
|
||||
shell: docker stop {{ vault_temp_container_name }} || rkt stop {{ vault_temp_container_name }}
|
||||
failed_when: false
|
||||
register: vault_temp_stop
|
||||
changed_when: vault_temp_stop|succeeded
|
||||
|
||||
# Check if vault is reachable on the localhost
|
||||
- name: check_vault | Attempt to pull local https Vault health
|
||||
uri:
|
||||
url: "{{ vault_config.listener.tcp.tls_disable|d()|ternary('http', 'https') }}://localhost:{{ vault_port }}/v1/sys/health"
|
||||
headers: "{{ vault_client_headers }}"
|
||||
status_code: 200,429,500,501
|
||||
validate_certs: no
|
||||
failed_when: false
|
||||
register: vault_local_service_health
|
||||
|
||||
- name: check_vault | Set facts about local Vault health
|
||||
set_fact:
|
||||
vault_is_running: "{{ vault_local_service_health|succeeded }}"
|
||||
vault_is_initialized: "{{ vault_local_service_health.get('json', {}).get('initialized', false) }}"
|
||||
vault_is_sealed: "{{ vault_local_service_health.get('json', {}).get('sealed', true) }}"
|
||||
#vault_in_standby: "{{ vault_local_service_health.get('json', {}).get('standby', true) }}"
|
||||
#vault_run_version: "{{ vault_local_service_health.get('json', {}).get('version', '') }}"
|
||||
|
||||
- name: check_vault | Set fact about the Vault cluster's initialization state
|
||||
set_fact:
|
||||
vault_cluster_is_initialized: "{{ vault_is_initialized or hostvars[item]['vault_is_initialized'] }}"
|
||||
with_items: "{{ groups.vault }}"
|
||||
30
roles/vault/tasks/shared/config_ca.yml
Normal file
30
roles/vault/tasks/shared/config_ca.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
|
||||
- name: config_ca | Read root CA cert for Vault
|
||||
command: "cat /etc/vault/ssl/{{ ca_name }}.pem"
|
||||
register: vault_ca_cert_cat
|
||||
|
||||
- name: config_ca | Pull current CA cert from Vault
|
||||
uri:
|
||||
url: "{{ vault_leader_url }}/v1/{{ mount_name }}/ca/pem"
|
||||
headers: "{{ vault_headers }}"
|
||||
return_content: true
|
||||
status_code: 200,204
|
||||
validate_certs: no
|
||||
register: vault_pull_current_ca
|
||||
|
||||
- name: config_ca | Read root CA key for Vault
|
||||
command: "cat /etc/vault/ssl/{{ ca_name }}-key.pem"
|
||||
register: vault_ca_key_cat
|
||||
when: vault_ca_cert_cat.stdout.strip() != vault_pull_current_ca.content.strip()
|
||||
|
||||
- name: config_ca | Configure pki mount to use the found root CA cert and key
|
||||
uri:
|
||||
url: "{{ vault_leader_url }}/v1/{{ mount_name }}/config/ca"
|
||||
headers: "{{ vault_headers }}"
|
||||
method: POST
|
||||
body_format: json
|
||||
body:
|
||||
pem_bundle: "{{ vault_ca_cert_cat.stdout + '\n' + vault_ca_key_cat.stdout }}"
|
||||
status_code: 204
|
||||
when: vault_ca_cert_cat.stdout.strip() != vault_pull_current_ca.get("content","").strip()
|
||||
74
roles/vault/tasks/shared/create_role.yml
Normal file
74
roles/vault/tasks/shared/create_role.yml
Normal file
@@ -0,0 +1,74 @@
|
||||
---
|
||||
|
||||
# The JSON inside JSON here is intentional (Vault API wants it)
|
||||
- name: create_role | Create a policy for the new role allowing issuing
|
||||
uri:
|
||||
url: "{{ hostvars[groups.vault|first]['vault_leader_url'] }}/v1/sys/policy/{{ create_role_name }}"
|
||||
headers: "{{ hostvars[groups.vault|first]['vault_headers'] }}"
|
||||
method: PUT
|
||||
body_format: json
|
||||
body:
|
||||
rules: >-
|
||||
{%- if create_role_policy_rules|d("default") == "default" -%}
|
||||
{{
|
||||
{ 'path': {
|
||||
'pki/issue/' + create_role_name: {'policy': 'write'},
|
||||
'pki/roles/' + create_role_name: {'policy': 'read'}
|
||||
}} | to_json + '\n'
|
||||
}}
|
||||
{%- else -%}
|
||||
{{ create_role_policy_rules | to_json + '\n' }}
|
||||
{%- endif -%}
|
||||
status_code: 204
|
||||
when: inventory_hostname == groups[create_role_group]|first
|
||||
|
||||
- name: create_role | Create the new role in the pki mount
|
||||
uri:
|
||||
url: "{{ hostvars[groups.vault|first]['vault_leader_url'] }}/v1/pki/roles/{{ create_role_name }}"
|
||||
headers: "{{ hostvars[groups.vault|first]['vault_headers'] }}"
|
||||
method: POST
|
||||
body_format: json
|
||||
body: >-
|
||||
{%- if create_role_options|d("default") == "default" -%}
|
||||
{'allow_any_name': true}
|
||||
{%- else -%}
|
||||
{{ create_role_options }}
|
||||
{%- endif -%}
|
||||
status_code: 204
|
||||
when: inventory_hostname == groups[create_role_group]|first
|
||||
|
||||
## Cert based auth method
|
||||
|
||||
- include: gen_cert.yml
|
||||
vars:
|
||||
gen_cert_copy_ca: true
|
||||
gen_cert_hosts: "{{ groups[create_role_group] }}"
|
||||
gen_cert_mount: "auth-pki"
|
||||
gen_cert_path: "{{ vault_roles_dir }}/{{ create_role_name }}/issuer.pem"
|
||||
gen_cert_vault_headers: "{{ hostvars[groups.vault|first]['vault_headers'] }}"
|
||||
gen_cert_vault_role: "dummy"
|
||||
gen_cert_vault_url: "{{ hostvars[groups.vault|first]['vault_leader_url'] }}"
|
||||
when: vault_role_auth_method == "cert" and inventory_hostname in groups[create_role_group]
|
||||
|
||||
- name: create_role | Insert the auth-pki CA as the authenticating CA for that role
|
||||
uri:
|
||||
url: "{{ hostvars[groups.vault|first]['vault_leader_url'] }}/v1/auth/cert/certs/{{ create_role_name }}"
|
||||
headers: "{{ hostvars[groups.vault|first]['vault_headers'] }}"
|
||||
method: POST
|
||||
body_format: json
|
||||
body:
|
||||
certificate: "{{ hostvars[groups[create_role_group]|first]['gen_cert_result']['json']['data']['issuing_ca'] }}"
|
||||
policies: "{{ create_role_name }}"
|
||||
status_code: 204
|
||||
when: vault_role_auth_method == "cert" and inventory_hostname == groups[create_role_group]|first
|
||||
|
||||
## Userpass based auth method
|
||||
|
||||
- include: gen_userpass.yml
|
||||
vars:
|
||||
gen_userpass_group: "{{ create_role_group }}"
|
||||
gen_userpass_password: "{{ create_role_password|d(''|to_uuid) }}"
|
||||
gen_userpass_policies: "{{ create_role_name }}"
|
||||
gen_userpass_role: "{{ create_role_name }}"
|
||||
gen_userpass_username: "{{ create_role_name }}"
|
||||
when: vault_role_auth_method == "userpass" and inventory_hostname in groups[create_role_group]
|
||||
17
roles/vault/tasks/shared/find_leader.yml
Normal file
17
roles/vault/tasks/shared/find_leader.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
|
||||
- name: find_leader | Find the current http Vault leader
|
||||
uri:
|
||||
url: "{{ vault_config.listener.tcp.tls_disable|d()|ternary('http', 'https') }}://localhost:{{ vault_port }}/v1/sys/health"
|
||||
headers: "{{ hostvars[groups.vault|first]['vault_headers'] }}"
|
||||
method: HEAD
|
||||
status_code: 200,429
|
||||
register: vault_leader_check
|
||||
until: "vault_leader_check|succeeded"
|
||||
retries: 10
|
||||
|
||||
- name: find_leader | Set fact for current http leader
|
||||
set_fact:
|
||||
vault_leader_url: "{{ vault_config.listener.tcp.tls_disable|d()|ternary('http', 'https') }}://{{ item }}:{{ vault_port }}"
|
||||
with_items: "{{ groups.vault }}"
|
||||
when: "hostvars[item]['vault_leader_check'].get('status') == 200"
|
||||
30
roles/vault/tasks/shared/gen_userpass.yml
Normal file
30
roles/vault/tasks/shared/gen_userpass.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
|
||||
- name: shared/gen_userpass | Create the Username/Password combo for the role
|
||||
uri:
|
||||
url: "{{ hostvars[groups.vault|first]['vault_leader_url'] }}/v1/auth/userpass/users/{{ gen_userpass_username }}"
|
||||
headers: "{{ hostvars[groups.vault|first]['vault_headers'] }}"
|
||||
method: POST
|
||||
body_format: json
|
||||
body:
|
||||
username: "{{ gen_userpass_username }}"
|
||||
password: "{{ gen_userpass_password }}"
|
||||
policies: "{{ gen_userpass_role }}"
|
||||
status_code: 204
|
||||
when: inventory_hostname == groups[gen_userpass_group]|first
|
||||
|
||||
- name: shared/gen_userpass | Ensure destination directory exists
|
||||
file:
|
||||
path: "{{ vault_roles_dir }}/{{ gen_userpass_role }}"
|
||||
state: directory
|
||||
when: inventory_hostname in groups[gen_userpass_group]
|
||||
|
||||
- name: shared/gen_userpass | Copy credentials to all hosts in the group
|
||||
copy:
|
||||
content: >
|
||||
{{
|
||||
{'username': gen_userpass_username,
|
||||
'password': gen_userpass_password} | to_nice_json(indent=4)
|
||||
}}
|
||||
dest: "{{ vault_roles_dir }}/{{ gen_userpass_role }}/userpass"
|
||||
when: inventory_hostname in groups[gen_userpass_group]
|
||||
66
roles/vault/tasks/shared/issue_cert.yml
Normal file
66
roles/vault/tasks/shared/issue_cert.yml
Normal file
@@ -0,0 +1,66 @@
|
||||
---
|
||||
|
||||
# This could be a role or custom module
|
||||
|
||||
# Vars:
|
||||
# issue_cert_alt_name: Requested Subject Alternative Names, in a list.
|
||||
# issue_cert_common_name: Common Name included in the cert
|
||||
# issue_cert_dir_mode: Mode of the placed cert directory
|
||||
# issue_cert_file_group: Group of the placed cert file and directory
|
||||
# issue_cert_file_mode: Mode of the placed cert file
|
||||
# issue_cert_file_owner: Owner of the placed cert file and directory
|
||||
# issue_cert_format: Format for returned data. Can be pem, der, or pem_bundle
|
||||
# issue_cert_headers: Headers passed into the issue request
|
||||
# issue_cert_hosts: List of hosts to distribute the cert to
|
||||
# issue_cert_ip_sans: Requested IP Subject Alternative Names, in a list
|
||||
# issue_cert_mount: Mount point in Vault to make the request to
|
||||
# issue_cert_path: Full path to the cert, include its name
|
||||
# issue_cert_role: The Vault role to issue the cert with
|
||||
# issue_cert_url: Url to reach Vault, including protocol and port
|
||||
|
||||
- name: issue_cert | Ensure target directory exists
|
||||
file:
|
||||
path: "{{ issue_cert_path | dirname }}"
|
||||
state: directory
|
||||
group: "{{ issue_cert_file_group | d('root' )}}"
|
||||
mode: "{{ issue_cert_dir_mode | d('0755') }}"
|
||||
owner: "{{ issue_cert_file_owner | d('root') }}"
|
||||
|
||||
- name: issue_cert | Generate the cert
|
||||
uri:
|
||||
url: "{{ issue_cert_url }}/v1/{{ issue_cert_mount|d('pki') }}/issue/{{ issue_cert_role }}"
|
||||
headers: "{{ issue_cert_headers }}"
|
||||
method: POST
|
||||
body_format: json
|
||||
body:
|
||||
alt_names: "{{ issue_cert_alt_names | d([]) | join(',') }}"
|
||||
common_name: "{{ issue_cert_common_name | d(issue_cert_path.rsplit('/', 1)[1].rsplit('.', 1)[0]) }}"
|
||||
format: "{{ issue_cert_format | d('pem') }}"
|
||||
ip_sans: "{{ issue_cert_ip_sans | default([]) | join(',') }}"
|
||||
register: issue_cert_result
|
||||
when: inventory_hostname == issue_cert_hosts|first
|
||||
|
||||
- name: issue_cert | Copy the cert to all hosts
|
||||
copy:
|
||||
content: "{{ hostvars[issue_cert_hosts|first]['issue_cert_result']['json']['data']['certificate'] }}"
|
||||
dest: "{{ issue_cert_path }}"
|
||||
group: "{{ issue_cert_file_group | d('root' )}}"
|
||||
mode: "{{ issue_cert_file_mode | d('0644') }}"
|
||||
owner: "{{ issue_cert_file_owner | d('root') }}"
|
||||
|
||||
- name: issue_cert | Copy the key to all hosts
|
||||
copy:
|
||||
content: "{{ hostvars[issue_cert_hosts|first]['issue_cert_result']['json']['data']['private_key'] }}"
|
||||
dest: "{{ issue_cert_path.rsplit('.', 1)|first }}-key.{{ issue_cert_path.rsplit('.', 1)|last }}"
|
||||
group: "{{ issue_cert_file_group | d('root' )}}"
|
||||
mode: "{{ issue_cert_file_mode | d('0640') }}"
|
||||
owner: "{{ issue_cert_file_owner | d('root') }}"
|
||||
|
||||
- name: issue_cert | Copy issuing CA cert
|
||||
copy:
|
||||
content: "{{ hostvars[issue_cert_hosts|first]['issue_cert_result']['json']['data']['issuing_ca'] }}"
|
||||
dest: "{{ issue_cert_path | dirname }}/ca.pem"
|
||||
group: "{{ issue_cert_file_group | d('root' )}}"
|
||||
mode: "{{ issue_cert_file_mode | d('0644') }}"
|
||||
owner: "{{ issue_cert_file_owner | d('root') }}"
|
||||
when: issue_cert_copy_ca|default(false)
|
||||
18
roles/vault/tasks/shared/mount.yml
Normal file
18
roles/vault/tasks/shared/mount.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
|
||||
- name: shared/mount | Test if PKI mount exists
|
||||
uri:
|
||||
url: "{{ vault_leader_url }}/v1/sys/mounts/{{ mount_name }}/tune"
|
||||
headers: "{{ vault_headers }}"
|
||||
ignore_errors: true
|
||||
register: vault_pki_mount_check
|
||||
|
||||
- name: shared/mount | Mount PKI mount if needed
|
||||
uri:
|
||||
url: "{{ vault_leader_url }}/v1/sys/mounts/{{ mount_name }}"
|
||||
headers: "{{ vault_headers }}"
|
||||
method: POST
|
||||
body_format: json
|
||||
body: "{{ mount_options|d() }}"
|
||||
status_code: 204
|
||||
when: vault_pki_mount_check|failed
|
||||
11
roles/vault/tasks/shared/pki_mount.yml
Normal file
11
roles/vault/tasks/shared/pki_mount.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
|
||||
- include: mount.yml
|
||||
vars:
|
||||
mount_name: pki
|
||||
mount_options:
|
||||
config:
|
||||
default_lease_ttl: "{{ vault_default_lease_ttl }}"
|
||||
max_lease_ttl: "{{ vault_max_lease_ttl }}"
|
||||
description: The default PKI mount for Kubernetes
|
||||
type: pki
|
||||
47
roles/vault/tasks/shared/sync.yml
Normal file
47
roles/vault/tasks/shared/sync.yml
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
|
||||
- name: "sync_file | Cat the file"
|
||||
command: "cat {{ sync_file_path }}"
|
||||
register: sync_file_cat
|
||||
when: inventory_hostname == sync_file_srcs|first
|
||||
|
||||
- name: "sync_file | Cat the key file"
|
||||
command: "cat {{ sync_file_key_path }}"
|
||||
register: sync_file_key_cat
|
||||
when: sync_file_is_cert|d() and inventory_hostname == sync_file_srcs|first
|
||||
|
||||
- name: "sync_file | Set facts for file contents"
|
||||
set_fact:
|
||||
sync_file_contents: "{{ hostvars[sync_file_srcs|first]['sync_file_cat']['stdout'] }}"
|
||||
|
||||
- name: "sync_file | Set fact for key contents"
|
||||
set_fact:
|
||||
sync_file_key_contents: "{{ hostvars[sync_file_srcs|first]['sync_file_key_cat']['stdout'] }}"
|
||||
when: sync_file_is_cert|d()
|
||||
|
||||
- name: "sync_file | Ensure the directory exists"
|
||||
file:
|
||||
group: "{{ sync_file_group|d('root') }}"
|
||||
mode: "{{ sync_file_dir_mode|default('0750') }}"
|
||||
owner: "{{ sync_file_owner|d('root') }}"
|
||||
path: "{{ sync_file_dir }}"
|
||||
state: directory
|
||||
when: inventory_hostname not in sync_file_srcs
|
||||
|
||||
- name: "sync_file | Copy the file to hosts that don't have it"
|
||||
copy:
|
||||
content: "{{ sync_file_contents }}"
|
||||
dest: "{{ sync_file_path }}"
|
||||
group: "{{ sync_file_group|d('root') }}"
|
||||
mode: "{{ sync_file_mode|default('0640') }}"
|
||||
owner: "{{ sync_file_owner|d('root') }}"
|
||||
when: inventory_hostname not in sync_file_srcs
|
||||
|
||||
- name: "sync_file | Copy the key file to hosts that don't have it"
|
||||
copy:
|
||||
content: "{{ sync_file_key_contents }}"
|
||||
dest: "{{ sync_file_key_path }}"
|
||||
group: "{{ sync_file_group|d('root') }}"
|
||||
mode: "{{ sync_file_mode|default('0640') }}"
|
||||
owner: "{{ sync_file_owner|d('root') }}"
|
||||
when: sync_file_is_cert|d() and inventory_hostname not in sync_file_srcs
|
||||
17
roles/vault/tasks/shared/sync_auth_certs.yml
Normal file
17
roles/vault/tasks/shared/sync_auth_certs.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
|
||||
- include: sync_file.yml
|
||||
vars:
|
||||
sync_file: "auth-ca.pem"
|
||||
sync_file_dir: "{{ vault_cert_dir }}"
|
||||
sync_file_hosts: "{{ groups.vault }}"
|
||||
sync_file_is_cert: true
|
||||
|
||||
- name: shared/sync_auth_certs | Set facts for vault sync_file results
|
||||
set_fact:
|
||||
vault_auth_ca_cert_needed: "{{ sync_file_results[0]['no_srcs'] }}"
|
||||
|
||||
|
||||
- name: shared/sync_auth_certs | Unset sync_file_results after auth-ca.pem sync
|
||||
set_fact:
|
||||
sync_file_results: []
|
||||
97
roles/vault/tasks/shared/sync_file.yml
Normal file
97
roles/vault/tasks/shared/sync_file.yml
Normal file
@@ -0,0 +1,97 @@
|
||||
---
|
||||
|
||||
# NOTE: This should be a role (or custom module), but currently include_role is too buggy to use
|
||||
|
||||
- name: "sync_file | Set facts for directory and file when sync_file_path is defined"
|
||||
set_fact:
|
||||
sync_file_dir: "{{ sync_file_path | dirname }}"
|
||||
sync_file: "{{ sync_file_path | basename }}"
|
||||
when: sync_file_path is defined and sync_file_path != ''
|
||||
|
||||
- name: "sync_file | Set fact for sync_file_path when undefined"
|
||||
set_fact:
|
||||
sync_file_path: "{{ (sync_file_dir, sync_file)|join('/') }}"
|
||||
when: sync_file_path is not defined or sync_file_path == ''
|
||||
|
||||
- name: "sync_file | Set fact for key path name"
|
||||
set_fact:
|
||||
sync_file_key_path: "{{ sync_file_path.rsplit('.', 1)|first + '-key.' + sync_file_path.rsplit('.', 1)|last }}"
|
||||
when: >-
|
||||
sync_file_is_cert|d() and (sync_file_key_path is not defined or sync_file_key_path == '')
|
||||
|
||||
- name: "sync_file | Check if file exists"
|
||||
stat:
|
||||
path: "{{ sync_file_path }}"
|
||||
register: sync_file_stat
|
||||
|
||||
- name: "sync_file | Check if key file exists"
|
||||
stat:
|
||||
path: "{{ sync_file_key_path }}"
|
||||
register: sync_file_key_stat
|
||||
when: sync_file_is_cert|d()
|
||||
|
||||
- name: "sync_file | Combine all possible file sync sources"
|
||||
set_fact:
|
||||
sync_file_srcs: "{{ sync_file_srcs|default([]) + [host_item] }}"
|
||||
with_items: "{{ sync_file_hosts | unique }}"
|
||||
loop_control:
|
||||
loop_var: host_item
|
||||
when: hostvars[host_item]["sync_file_stat"]["stat"]["exists"]|bool
|
||||
|
||||
- name: "sync_file | Combine all possible key file sync sources"
|
||||
set_fact:
|
||||
sync_file_key_srcs: "{{ sync_file_key_srcs|default([]) + [host_item] }}"
|
||||
with_items: "{{ sync_file_hosts | unique }}"
|
||||
loop_control:
|
||||
loop_var: host_item
|
||||
when: sync_file_is_cert|d() and hostvars[host_item]["sync_file_key_stat"]["stat"]["exists"]|bool
|
||||
|
||||
- name: "sync_file | Remove sync sources with files that do not match sync_file_srcs|first"
|
||||
set_fact:
|
||||
_: "{% if inventory_hostname in sync_file_srcs %}{{ sync_file_srcs.remove(inventory_hostname) }}{% endif %}"
|
||||
when: >-
|
||||
sync_file_srcs|d([])|length > 1 and
|
||||
inventory_hostname != sync_file_srcs|first and
|
||||
sync_file_stat.stat.get("checksum") != hostvars[sync_file_srcs|first]["sync_file_stat"]["stat"]["checksum"]
|
||||
|
||||
- name: "sync_file | Remove sync sources with keys that do not match sync_file_srcs|first"
|
||||
set_fact:
|
||||
_: "{% if inventory_hostname in sync_file_srcs %}{{ sync_file_srcs.remove(inventory_hostname) }}{% endif %}"
|
||||
when: >-
|
||||
sync_file_is_cert|d() and
|
||||
sync_file_key_srcs|d([])|length > 1 and
|
||||
inventory_hostname != sync_file_key_srcs|first and
|
||||
sync_file_key_stat.stat.checksum != hostvars[sync_file_srcs|first]["sync_file_key_stat"]["stat"]["checksum"]
|
||||
|
||||
- name: "sync_file | Consolidate file and key sources"
|
||||
set_fact:
|
||||
sync_file_srcs: "{{ sync_file_srcs|d([]) | intersect(sync_file_key_srcs) }}"
|
||||
when: sync_file_is_cert|d()
|
||||
|
||||
- name: "sync_file | Set facts for situations where sync is not needed"
|
||||
set_fact:
|
||||
sync_file_no_srcs: "{{ true if sync_file_srcs|d([])|length == 0 else false }}"
|
||||
sync_file_unneeded: "{{ true if sync_file_srcs|d([])|length == sync_file_hosts|length else false }}"
|
||||
|
||||
- name: "sync_file | Set sync_file_result fact"
|
||||
set_fact:
|
||||
sync_file_result:
|
||||
no_srcs: "{{ sync_file_no_srcs }}"
|
||||
path: "{{ sync_file_path }}"
|
||||
sync_unneeded: "{{ sync_file_unneeded }}"
|
||||
|
||||
- name: "sync_file | Update sync_file_results fact"
|
||||
set_fact:
|
||||
sync_file_results: "{{ sync_file_results|default([]) + [sync_file_result] }}"
|
||||
|
||||
- include: sync.yml
|
||||
when: not (sync_file_no_srcs or sync_file_unneeded)
|
||||
|
||||
- name: "Unset local vars to avoid variable bleed into next iteration"
|
||||
set_fact:
|
||||
sync_file: ''
|
||||
sync_file_dir: ''
|
||||
sync_file_key_path: ''
|
||||
sync_file_key_srcs: []
|
||||
sync_file_path: ''
|
||||
sync_file_srcs: []
|
||||
Reference in New Issue
Block a user