--- # Validation tasks for vault infrastructure health # Concept: These assertions fail fast if vault prerequisites are missing or misconfigured. # Run as part of the main role or standalone to diagnose vault setup issues. # Why assert instead of conditional blocks? # - assert provides clear, fail-fast feedback in the Ansible log # - conditional blocks silently skip, hiding problems # - assert messages are easy to test and CI-friendly - name: Check vault password file exists ansible.builtin.stat: path: "{{ vault_password_file }}" register: password_file_stat tags: - validate # Why ansible.builtin.assert instead of shell 'test -f'? # - assert provides human-readable failure messages # - Multiple conditions can be checked in one task # - Integrates with Ansible's fail_msg and exception handling # - Shell 'test' silently passes/fails; harder to debug in logs - name: Assert vault password file exists and has secure permissions ansible.builtin.assert: that: - password_file_stat.stat.exists - password_file_stat.stat.mode == "0600" fail_msg: | Vault password file is missing or has wrong permissions. Expected: {{ vault_password_file }} with mode 0600 Actual: exists={{ password_file_stat.stat.exists }}, mode={{ password_file_stat.stat.mode | default('N/A') }} To fix: 1. Create the file with a strong password: echo 'YOUR-STRONG-PASSWORD' > {{ vault_password_file }} 2. Secure it: chmod 0600 {{ vault_password_file }} For interactive vault prompts (instead of password file), use: ansible-playbook ansible/playbooks/onboarding/setup_ansible_secrets.yml --ask-vault-pass when: not skip_validation | default(false) tags: - validate - name: Check vault directory permissions ansible.builtin.stat: path: "{{ vault_base_dir }}" register: vault_dir_stat tags: - validate - name: Assert vault directory has secure permissions ansible.builtin.assert: that: - vault_dir_stat.stat.exists - vault_dir_stat.stat.isdir - vault_dir_stat.stat.mode == "0700" fail_msg: | Vault directory has wrong permissions or does not exist. Expected: {{ vault_base_dir }} as directory with mode 0700 Actual: exists={{ vault_dir_stat.stat.exists }}, isdir={{ vault_dir_stat.stat.isdir | default(false) }}, mode={{ vault_dir_stat.stat.mode | default('N/A') }} To fix: mkdir -p {{ vault_base_dir }} chmod 0700 {{ vault_base_dir }} when: not skip_validation | default(false) tags: - validate - name: Check encrypted vars directory ansible.builtin.stat: path: "{{ vault_vars_dir }}" register: vault_vars_dir_stat tags: - validate - name: Assert encrypted vars directory exists ansible.builtin.assert: that: - vault_vars_dir_stat.stat.exists - vault_vars_dir_stat.stat.isdir fail_msg: | Vault encrypted vars directory does not exist. Expected: {{ vault_vars_dir }} To fix (automatic on next role run): ansible-playbook playbooks/onboarding/setup_ansible_secrets.yml --tags bootstrap when: not skip_validation | default(false) tags: - validate - name: Check encrypted vars file state ansible.builtin.stat: path: "{{ vault_encrypted_file }}" register: vault_encrypted_file_stat tags: - validate - name: Assert encrypted vars file exists when required ansible.builtin.assert: that: - vault_encrypted_file_stat.stat.exists - vault_encrypted_file_stat.stat.isreg fail_msg: | Vault encrypted vars file is required but missing. Expected: {{ vault_encrypted_file }} To fix: ansible-vault create {{ vault_encrypted_file }} when: - not skip_validation | default(false) - vault_require_encrypted_vars_file | bool tags: - validate - name: Read encrypted vars file header ansible.builtin.slurp: src: "{{ vault_encrypted_file }}" register: vault_encrypted_file_content when: - not skip_validation | default(false) - vault_require_encrypted_vars_file | bool - vault_encrypted_file_stat.stat.exists no_log: true tags: - validate - name: Assert encrypted vars file is vault-encrypted ansible.builtin.assert: that: - "(vault_encrypted_file_content.content | b64decode).startswith('$ANSIBLE_VAULT;')" fail_msg: | Vault vars file exists but is not encrypted with Ansible Vault. File: {{ vault_encrypted_file }} To fix: ansible-vault encrypt {{ vault_encrypted_file }} when: - not skip_validation | default(false) - vault_require_encrypted_vars_file | bool - vault_encrypted_file_stat.stat.exists no_log: true tags: - validate - name: Load encrypted vars for required key checks ansible.builtin.include_vars: file: "{{ vault_encrypted_file }}" name: loaded_vault_vars when: - not skip_validation | default(false) - vault_require_encrypted_vars_file | bool - vault_encrypted_file_stat.stat.exists - (vault_encrypted_vars_required_keys | length) > 0 no_log: true tags: - validate - name: Assert required encrypted keys exist ansible.builtin.assert: that: - "item in loaded_vault_vars" - "(loaded_vault_vars[item] | string | trim | length) > 0" fail_msg: "Missing required vault key: {{ item }}" loop: "{{ vault_encrypted_vars_required_keys }}" when: - not skip_validation | default(false) - vault_require_encrypted_vars_file | bool - vault_encrypted_file_stat.stat.exists - (vault_encrypted_vars_required_keys | length) > 0 no_log: true tags: - validate - name: Report validation success ansible.builtin.debug: msg: | ✓ Vault infrastructure is healthy. ✓ Vault password file: {{ vault_password_file }} (mode {{ password_file_stat.stat.mode }}) ✓ Vault base directory: {{ vault_base_dir }} (mode {{ vault_dir_stat.stat.mode }}) ✓ Encrypted vars directory: {{ vault_vars_dir }} {% if vault_require_encrypted_vars_file | bool %}✓ Encrypted vars file: {{ vault_encrypted_file }}{% endif %} when: not skip_validation | default(false) tags: - validate