231 lines
7.3 KiB
YAML
231 lines
7.3 KiB
YAML
---
|
|
# ==========================================================
|
|
# 1️⃣ Install Vault and Dependencies
|
|
# ==========================================================
|
|
- name: Ensure HashiCorp repository (RHEL9)
|
|
ansible.builtin.copy:
|
|
dest: /etc/yum.repos.d/hashicorp.repo
|
|
mode: "0644"
|
|
content: |
|
|
[hashicorp]
|
|
name=HashiCorp Stable Repository
|
|
baseurl=https://rpm.releases.hashicorp.com/RHEL/9/x86_64/stable/
|
|
enabled=1
|
|
gpgcheck=1
|
|
gpgkey=https://rpm.releases.hashicorp.com/gpg
|
|
|
|
- name: Install Vault (includes vault-agent)
|
|
ansible.builtin.dnf:
|
|
name: vault
|
|
state: present
|
|
|
|
# ==========================================================
|
|
# 2️⃣ Firewall Configuration
|
|
# ==========================================================
|
|
- name: Ensure firewalld is running and enabled
|
|
ansible.builtin.systemd:
|
|
name: firewalld
|
|
enabled: true
|
|
state: started
|
|
|
|
- name: Allow outbound access to Vault (VAULT_PORT/tcp)
|
|
ansible.posix.firewalld:
|
|
rich_rule: >
|
|
rule family="ipv4"
|
|
destination address="VAULT_IP"
|
|
port port="VAULT_PORT" protocol="tcp" accept
|
|
permanent: true
|
|
state: enabled
|
|
immediate: true
|
|
|
|
# ==========================================================
|
|
# 3️⃣ Vault-Agent Directories and Configs
|
|
# ==========================================================
|
|
- name: Ensure Vault-Agent directories exist
|
|
ansible.builtin.file:
|
|
path: "{{ vault_dir.path }}"
|
|
state: directory
|
|
owner: root
|
|
group: root
|
|
mode: "{{ vault_dir.mode | default('0750') }}"
|
|
loop:
|
|
- { path: "{{ vault_templates_dir }}" }
|
|
- { path: "/etc/vault-agent", mode: "0700" }
|
|
loop_control:
|
|
loop_var: vault_dir
|
|
|
|
- name: Deploy Vault-Agent configuration
|
|
ansible.builtin.template:
|
|
src: vault-agent-config.hcl.j2
|
|
dest: "{{ vault_agent_config_path }}"
|
|
owner: root
|
|
group: root
|
|
mode: "0600"
|
|
|
|
- name: Install Vault-Agent systemd unit
|
|
ansible.builtin.template:
|
|
src: vault-agent.service.j2
|
|
dest: "{{ vault_agent_systemd_unit }}"
|
|
owner: root
|
|
group: root
|
|
mode: "0644"
|
|
notify: Reload systemd
|
|
|
|
- name: Enable Vault-Agent but do not start yet
|
|
ansible.builtin.systemd:
|
|
name: "{{ vault_agent_service }}"
|
|
enabled: true
|
|
state: stopped
|
|
|
|
# ==========================================================
|
|
# 4️⃣ Vault-Agent Templates and Cert Paths
|
|
# ==========================================================
|
|
- name: Copy Vault-Agent templates
|
|
ansible.builtin.copy:
|
|
src: "{{ vault_item.src }}"
|
|
dest: "{{ vault_templates_dir }}/{{ vault_item.src | basename }}"
|
|
owner: root
|
|
group: root
|
|
mode: "0600"
|
|
loop: "{{ vault_agent_templates }}"
|
|
loop_control:
|
|
loop_var: vault_item
|
|
|
|
- name: Ensure directories for Vault-rendered files exist
|
|
ansible.builtin.file:
|
|
path: "{{ vault_template.dest | dirname }}"
|
|
state: directory
|
|
owner: root
|
|
group: root
|
|
mode: "0755"
|
|
loop: "{{ vault_agent_templates }}"
|
|
loop_control:
|
|
loop_var: vault_template
|
|
|
|
- name: Start Vault-Agent (now that templates exist)
|
|
ansible.builtin.systemd:
|
|
name: "{{ vault_agent_service }}"
|
|
state: started
|
|
|
|
# ==========================================================
|
|
# 5️⃣ AppRole Authentication Setup
|
|
# ==========================================================
|
|
- name: Fetch AppRole credentials for this host
|
|
delegate_to: localhost
|
|
block:
|
|
- name: Get role_id
|
|
ansible.builtin.command:
|
|
cmd: >
|
|
vault read -field=role_id auth/approle/role/{{ inventory_hostname }}-role/role-id
|
|
register: role_id_raw
|
|
changed_when: false
|
|
failed_when: role_id_raw.stdout | trim == ""
|
|
environment:
|
|
VAULT_ADDR: "http://VAULT_IP:VAULT_PORT"
|
|
VAULT_TOKEN: "{{ vault_token }}"
|
|
|
|
- name: Get secret_id
|
|
ansible.builtin.command:
|
|
cmd: >
|
|
vault write -f -field=secret_id auth/approle/role/{{ inventory_hostname }}-role/secret-id
|
|
register: secret_id_raw
|
|
changed_when: false
|
|
failed_when: secret_id_raw.stdout | trim == ""
|
|
environment:
|
|
VAULT_ADDR: "http://VAULT_IP:VAULT_PORT"
|
|
VAULT_TOKEN: "{{ vault_token }}"
|
|
|
|
- name: Write AppRole credentials to Vault-Agent directory
|
|
ansible.builtin.copy:
|
|
dest: "/etc/vault-agent/{{ cred.name }}"
|
|
content: "{{ cred.content }}"
|
|
owner: root
|
|
group: root
|
|
mode: "0600"
|
|
loop:
|
|
- { name: "role_id", content: "{{ role_id_raw.stdout | trim }}" }
|
|
- { name: "secret_id", content: "{{ secret_id_raw.stdout | trim }}" }
|
|
loop_control:
|
|
loop_var: cred
|
|
label: "{{ cred.name }}"
|
|
|
|
# ==========================================================
|
|
# 6️⃣ Register Service in Vault
|
|
# ==========================================================
|
|
- name: Login to Vault with AppRole and register VM
|
|
delegate_to: localhost
|
|
block:
|
|
- name: Login to Vault with AppRole
|
|
ansible.builtin.command:
|
|
cmd: >
|
|
vault write -field=token auth/approle/login
|
|
role_id={{ role_id_raw.stdout | trim }}
|
|
secret_id={{ secret_id_raw.stdout | trim }}
|
|
register: vault_login
|
|
changed_when: false
|
|
environment:
|
|
VAULT_ADDR: "http://VAULT_IP:VAULT_PORT"
|
|
|
|
- name: Register VM IP in Vault KV
|
|
ansible.builtin.uri:
|
|
url: "http://VAULT_IP:VAULT_PORT/v1/kv/data/services/{{ inventory_hostname }}"
|
|
method: POST
|
|
headers:
|
|
X-Vault-Token: "{{ vault_login.stdout }}"
|
|
body:
|
|
data:
|
|
ip: "{{ ansible_default_ipv4.address }}"
|
|
body_format: json
|
|
status_code: [200, 204]
|
|
|
|
# ==========================================================
|
|
# 7️⃣ SELinux Context for Vault Rendered Paths
|
|
# ==========================================================
|
|
- name: Check if SELinux is enforcing
|
|
ansible.builtin.command: getenforce
|
|
register: selinux_status
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: Gather all Vault-Agent template and rendered paths
|
|
ansible.builtin.set_fact:
|
|
all_vault_paths: >-
|
|
{{
|
|
(
|
|
(vault_agent_templates | default([]) | map(attribute='dest') | map('dirname') | list)
|
|
+
|
|
(vault_agent_templates | default([]) | map(attribute='dest') | list)
|
|
) | unique
|
|
}}
|
|
when: vault_agent_templates is defined and vault_agent_templates | length > 0
|
|
|
|
- name: Filter only paths that exist on the host
|
|
ansible.builtin.find:
|
|
paths: "{{ all_vault_paths }}"
|
|
file_type: directory
|
|
register: existing_selinux_paths
|
|
when: all_vault_paths is defined and all_vault_paths | length > 0
|
|
|
|
- name: Apply SELinux fcontext to all existing Vault paths
|
|
ansible.builtin.command:
|
|
cmd: semanage fcontext -a -t etc_t '{{ selinux_path_item.path }}(/.*)?'
|
|
loop: "{{ existing_selinux_paths.files | default([]) }}"
|
|
loop_control:
|
|
loop_var: selinux_path_item
|
|
ignore_errors: true
|
|
when: selinux_status.stdout == "Enforcing"
|
|
|
|
- name: Restore SELinux context for all existing Vault paths
|
|
ansible.builtin.command:
|
|
cmd: restorecon -Rv "{{ selinux_path_item.path }}"
|
|
loop: "{{ existing_selinux_paths.files | default([]) }}"
|
|
loop_control:
|
|
loop_var: selinux_path_item
|
|
ignore_errors: true
|
|
when: selinux_status.stdout == "Enforcing"
|
|
|
|
- name: Warn if SELinux is not enforcing
|
|
ansible.builtin.debug:
|
|
msg: "⚠️ SELinux is not enforcing — Vault-Agent directories may not be properly confined."
|
|
when: selinux_status.stdout != "Enforcing"
|