new files from source
This commit is contained in:
132 files changed
+5335
No files matched your search
@@ -0,0 +1,55 @@
|
||||
# Vault connection
|
||||
vault_addr: "http://VAULT_IP:VAULT_PORT"
|
||||
|
||||
# Directory paths
|
||||
haproxy_certs_dir: "/etc/haproxy/certs"
|
||||
haproxy_cert_path: "{{ haproxy_pem_path }}"
|
||||
haproxy_pem_path: "{{ haproxy_certs_dir }}/haproxy.pem"
|
||||
haproxy_ca_path: "{{ haproxy_certs_dir }}/haproxy_ca.crt"
|
||||
|
||||
# Systemd service names
|
||||
haproxy_service: "haproxy"
|
||||
|
||||
# HAProxy tuning
|
||||
haproxy_global_maxconn: 4096
|
||||
haproxy_timeout_connect_ms: 5000
|
||||
haproxy_timeout_client_ms: 60000
|
||||
haproxy_timeout_server_ms: 60000
|
||||
haproxy_enable_hsts: true
|
||||
|
||||
vault_agent_templates:
|
||||
- src: "haproxy.pem.ctmpl"
|
||||
dest: "{{ haproxy_pem_path }}"
|
||||
service: "haproxy"
|
||||
- src: "haproxy_ca.ctmpl"
|
||||
dest: "{{ haproxy_ca_path }}"
|
||||
service: "haproxy"
|
||||
|
||||
# === Services routed internally through HAProxy ===
|
||||
securemtls_services:
|
||||
vault:
|
||||
hostname: vault.local.DOMAIN_PLACEHOLDER
|
||||
balance: roundrobin
|
||||
mode: http
|
||||
timeout_connect: 5s
|
||||
timeout_server: 30s
|
||||
default_server_inter: 3s
|
||||
default_server_rise: 2
|
||||
default_server_fall: 3
|
||||
backend_servers:
|
||||
- address: VAULT_IP
|
||||
port: VAULT_PORT
|
||||
proto: http
|
||||
headers:
|
||||
- "http-request set-header Host vault.local.DOMAIN_PLACEHOLDER"
|
||||
- "http-request set-header X-Forwarded-Proto https"
|
||||
rewrites:
|
||||
- "http-response replace-header Location ^http://VAULT_IP:VAULT_PORT/(.*) https://vault.local.DOMAIN_PLACEHOLDER/\\1"
|
||||
|
||||
technitium:
|
||||
hostname: "technitium.local.DOMAIN_PLACEHOLDER"
|
||||
backend_mode: http
|
||||
backend_servers:
|
||||
- address: TECHNITIUM_IP
|
||||
port: TECHNITIUM_PORT
|
||||
proto: "http"
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
- name: Reload HAProxy
|
||||
systemd:
|
||||
name: haproxy
|
||||
state: reloaded
|
||||
@@ -0,0 +1,107 @@
|
||||
---
|
||||
- name: Install HAProxy
|
||||
dnf:
|
||||
name: haproxy
|
||||
state: present
|
||||
|
||||
- name: Ensure firewalld is running and enabled
|
||||
systemd:
|
||||
name: firewalld
|
||||
enabled: true
|
||||
state: started
|
||||
|
||||
- name: Allow inbound HTTPS (443/tcp)
|
||||
ansible.posix.firewalld:
|
||||
service: https
|
||||
permanent: true
|
||||
state: enabled
|
||||
immediate: true
|
||||
|
||||
- name: Ensure HAProxy certificate directories exist
|
||||
file:
|
||||
path: "{{ cert_dir }}"
|
||||
state: directory
|
||||
owner: haproxy
|
||||
group: haproxy
|
||||
mode: "0750"
|
||||
loop:
|
||||
- "{{ haproxy_certs_dir }}"
|
||||
- "{{ haproxy_certs_dir }}/clients"
|
||||
loop_control:
|
||||
loop_var: cert_dir
|
||||
|
||||
- name: Apply SELinux context for HAProxy certs
|
||||
command: semanage fcontext -a -t etc_t "{{ haproxy_certs_dir }}(/.*)?"
|
||||
become: true
|
||||
register: semanage_fcontext_result
|
||||
failed_when: false
|
||||
changed_when: semanage_fcontext_result.rc == 0
|
||||
|
||||
- name: Restore SELinux context for HAProxy certs
|
||||
command: restorecon -Rv "{{ haproxy_certs_dir }}"
|
||||
become: true
|
||||
changed_when: false
|
||||
|
||||
- name: Allow HAProxy to connect to any port (SELinux)
|
||||
ansible.posix.seboolean:
|
||||
name: haproxy_connect_any
|
||||
state: true
|
||||
persistent: true
|
||||
|
||||
- name: Wait for HAProxy PEM and CA files
|
||||
wait_for:
|
||||
path: "{{ pem_item }}"
|
||||
state: present
|
||||
timeout: 120
|
||||
loop:
|
||||
- "{{ haproxy_pem_path }}"
|
||||
- "{{ haproxy_ca_path }}"
|
||||
loop_control:
|
||||
loop_var: pem_item
|
||||
|
||||
- name: Ensure permissions for HAProxy certs
|
||||
file:
|
||||
path: "{{ cert_item }}"
|
||||
owner: haproxy
|
||||
group: haproxy
|
||||
mode: "0644"
|
||||
loop:
|
||||
- "{{ haproxy_pem_path }}"
|
||||
- "{{ haproxy_ca_path }}"
|
||||
loop_control:
|
||||
loop_var: cert_item
|
||||
|
||||
- name: Deploy HAProxy configuration
|
||||
template:
|
||||
src: haproxy.cfg.j2
|
||||
dest: /etc/haproxy/haproxy.cfg
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
notify: Reload HAProxy
|
||||
|
||||
- name: Ensure HAProxy service starts after vault-agent
|
||||
lineinfile:
|
||||
path: /usr/lib/systemd/system/haproxy.service
|
||||
regexp: "^After="
|
||||
line: "After=network-online.target vault-agent.service"
|
||||
backup: yes
|
||||
|
||||
- name: Reload systemd daemon
|
||||
command: systemctl daemon-reload
|
||||
|
||||
- name: Enable and start HAProxy
|
||||
systemd:
|
||||
name: haproxy
|
||||
enabled: yes
|
||||
state: started
|
||||
|
||||
- name: Check SELinux mode
|
||||
command: getenforce
|
||||
register: selinux_state
|
||||
changed_when: false
|
||||
|
||||
- name: Warn if SELinux is not enforcing
|
||||
debug:
|
||||
msg: "⚠️ SELinux is not enforcing — HAProxy cert contexts may not be correctly applied."
|
||||
when: selinux_state.stdout != "Enforcing"
|
||||
@@ -0,0 +1,86 @@
|
||||
# ==========================================
|
||||
# HAProxy global settings
|
||||
# ==========================================
|
||||
global
|
||||
log /dev/log local0
|
||||
log /dev/log local1 notice
|
||||
chroot /var/lib/haproxy
|
||||
pidfile /run/haproxy.pid
|
||||
maxconn {{ haproxy_global_maxconn | default(4096) }}
|
||||
user haproxy
|
||||
group haproxy
|
||||
daemon
|
||||
|
||||
defaults
|
||||
log global
|
||||
option httplog
|
||||
option dontlognull
|
||||
timeout connect {{ haproxy_timeout_connect_ms | default('5000') }}
|
||||
timeout client {{ haproxy_timeout_client_ms | default('60000') }}
|
||||
timeout server {{ haproxy_timeout_server_ms | default('60000') }}
|
||||
option http-server-close
|
||||
option forwardfor
|
||||
retries 3
|
||||
maxconn 2000
|
||||
|
||||
# ==========================================
|
||||
# HAProxy frontends and backends template
|
||||
# ==========================================
|
||||
|
||||
frontend https-in
|
||||
mode http
|
||||
bind *:443 ssl crt {{ haproxy_pem_path }} ca-file {{ haproxy_ca_path }} verify required alpn h2,http/1.1
|
||||
option httplog
|
||||
option forwardfor
|
||||
timeout client 30s
|
||||
|
||||
http-request set-header X-Client-Cert %[ssl_c_der,base64]
|
||||
|
||||
{% for service_name, service in securemtls_services.items() %}
|
||||
acl host_{{ service_name }} hdr(host) -i {{ service.hostname }}
|
||||
use_backend {{ service_name }} if host_{{ service_name }}
|
||||
{% endfor %}
|
||||
|
||||
# ==========================================
|
||||
# Backends
|
||||
# ==========================================
|
||||
{% for service_name, service in securemtls_services.items() %}
|
||||
backend {{ service_name }}
|
||||
balance {{ service.balance | default('roundrobin') }}
|
||||
mode {{ service.mode | default('http') }}
|
||||
timeout connect {{ service.timeout_connect | default('5s') }}
|
||||
timeout server {{ service.timeout_server | default('30s') }}
|
||||
option {{ service.options | default('http-server-close') }}
|
||||
default-server inter {{ service.default_server_inter | default('3s') }}
|
||||
default-server rise {{ service.default_server_rise | default('2') }}
|
||||
default-server fall {{ service.default_server_fall | default('3') }}
|
||||
|
||||
{% for server in service.backend_servers %}
|
||||
{% if server.proto == "https" %}
|
||||
server {{ service_name }}-{{ loop.index }} {{ server.address }}:{{ server.port }} ssl verify none check
|
||||
{% else %}
|
||||
server {{ service_name }}-{{ loop.index }} {{ server.address }}:{{ server.port }} check
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if service.headers is defined %}
|
||||
{% for hdr in service.headers %}
|
||||
{{ hdr }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if service.rewrites is defined %}
|
||||
{% for rewrite in service.rewrites %}
|
||||
{{ rewrite }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
# ==========================================
|
||||
# Vault backend for HAProxy
|
||||
# ==========================================
|
||||
backend vault_backend
|
||||
mode tcp
|
||||
option ssl-hello-chk
|
||||
server vault1 VAULT_IP:VAULT_PORT ssl verify required ca-file {{ haproxy_ca_path }} crt {{ haproxy_cert_path }}
|
||||
@@ -0,0 +1,28 @@
|
||||
# Networking
|
||||
technitium_port: 53
|
||||
technitium_tls_port: 853
|
||||
technitium_admin_port: TECHNITIUM_PORT
|
||||
technitium_bind_address: "0.0.0.0"
|
||||
|
||||
# ==========================================================
|
||||
# Directory paths
|
||||
# ==========================================================
|
||||
technitium_certs_dir: "/etc/technitium/certs"
|
||||
technitium_crt_path: "{{ technitium_certs_dir }}/technitium.crt"
|
||||
technitium_key_path: "{{ technitium_certs_dir }}/technitium.key"
|
||||
technitium_ca_path: "{{ technitium_certs_dir }}/technitium_ca.crt"
|
||||
|
||||
# Install paths
|
||||
technitium_install_dir: "/opt/technitium/dns"
|
||||
technitium_data_dir: "{{ technitium_install_dir }}/data"
|
||||
|
||||
vault_agent_templates:
|
||||
- src: "technitium_cert.ctmpl"
|
||||
dest: "{{ technitium_crt_path }}"
|
||||
service: "technitium"
|
||||
- src: "technitium_key.ctmpl"
|
||||
dest: "{{ technitium_key_path }}"
|
||||
service: "technitium"
|
||||
- src: "technitium_ca.ctmpl"
|
||||
dest: "{{ technitium_ca_path }}"
|
||||
service: "technitium"
|
||||
@@ -0,0 +1,8 @@
|
||||
- name: Reload systemd
|
||||
ansible.builtin.systemd:
|
||||
daemon_reload: yes
|
||||
|
||||
- name: Restart technitium
|
||||
ansible.builtin.systemd:
|
||||
name: technitium
|
||||
state: restarted
|
||||
@@ -0,0 +1,125 @@
|
||||
---
|
||||
# ==========================================================
|
||||
# Install and configure Technitium DNS Server
|
||||
# ==========================================================
|
||||
|
||||
- name: Ensure Technitium install directory exists
|
||||
ansible.builtin.file:
|
||||
path: "{{ technitium_install_dir }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0755"
|
||||
|
||||
- name: Ensure Technitium data directory exists
|
||||
ansible.builtin.file:
|
||||
path: "{{ technitium_data_dir }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0755"
|
||||
|
||||
- name: Ensure Technitium TLS directory exists
|
||||
ansible.builtin.file:
|
||||
path: "{{ technitium_certs_dir }}"
|
||||
state: directory
|
||||
owner: vault
|
||||
group: vault
|
||||
mode: "0700"
|
||||
|
||||
# ==========================================================
|
||||
# Install Technitium if not already installed
|
||||
# ==========================================================
|
||||
- name: Install Technitium DNS Server
|
||||
ansible.builtin.command: bash install.sh
|
||||
args:
|
||||
chdir: /tmp
|
||||
creates: "{{ technitium_install_dir }}/start.sh"
|
||||
environment:
|
||||
INSTALL_URL: "https://download.technitium.com/dns/install.sh"
|
||||
register: technitium_install_result
|
||||
ignore_errors: true
|
||||
changed_when: technitium_install_result.rc == 0
|
||||
|
||||
# ==========================================================
|
||||
# SELinux setup (idempotent)
|
||||
# ==========================================================
|
||||
- name: Apply SELinux context for Technitium certs
|
||||
ansible.builtin.command: semanage fcontext -a -t etc_t '{{ technitium_certs_dir }}(/.*)?'
|
||||
register: selinux_ctx
|
||||
changed_when: selinux_ctx.rc == 0
|
||||
ignore_errors: true
|
||||
|
||||
- name: Restore SELinux context for Technitium certs
|
||||
ansible.builtin.command: restorecon -Rv "{{ technitium_certs_dir }}"
|
||||
changed_when: false
|
||||
|
||||
# ==========================================================
|
||||
# Firewalld setup
|
||||
# ==========================================================
|
||||
- name: Ensure firewalld is running
|
||||
ansible.builtin.systemd:
|
||||
name: firewalld
|
||||
enabled: true
|
||||
state: started
|
||||
|
||||
- name: Open Technitium DNS and admin ports
|
||||
ansible.posix.firewalld:
|
||||
port: "{{ item.port }}/{{ item.proto }}"
|
||||
permanent: true
|
||||
state: enabled
|
||||
immediate: true
|
||||
loop:
|
||||
- { port: 53, proto: "udp" }
|
||||
- { port: 53, proto: "tcp" }
|
||||
- { port: 853, proto: "tcp" }
|
||||
- { port: 443, proto: "tcp" }
|
||||
- { port: 5380, proto: "tcp" }
|
||||
|
||||
# ==========================================================
|
||||
# Systemd service deployment
|
||||
# ==========================================================
|
||||
- name: Deploy Technitium systemd unit
|
||||
ansible.builtin.template:
|
||||
src: "technitium.service.j2"
|
||||
dest: "/etc/systemd/system/technitium.service"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
notify:
|
||||
- Reload systemd
|
||||
- Restart technitium
|
||||
|
||||
- name: Wait for Vault-Agent to render certificates
|
||||
ansible.builtin.wait_for:
|
||||
path: "{{ cert_path }}"
|
||||
state: present
|
||||
timeout: 60
|
||||
loop:
|
||||
- "{{ technitium_crt_path }}"
|
||||
- "{{ technitium_key_path }}"
|
||||
- "{{ technitium_ca_path }}"
|
||||
loop_control:
|
||||
loop_var: cert_path
|
||||
|
||||
- name: Fix ownership and permissions for Technitium certs
|
||||
ansible.builtin.file:
|
||||
path: "{{ cert.path }}"
|
||||
owner: vault
|
||||
group: vault
|
||||
mode: "{{ cert.mode }}"
|
||||
loop:
|
||||
- { path: "{{ technitium_crt_path }}", mode: "0644" }
|
||||
- { path: "{{ technitium_key_path }}", mode: "0600" }
|
||||
- { path: "{{ technitium_ca_path }}", mode: "0644" }
|
||||
loop_control:
|
||||
loop_var: cert
|
||||
|
||||
# ==========================================================
|
||||
# Start and enable service
|
||||
# ==========================================================
|
||||
- name: Ensure Technitium DNS service is running
|
||||
ansible.builtin.systemd:
|
||||
name: technitium
|
||||
enabled: true
|
||||
state: started
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=Technitium DNS Server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory={{ technitium_install_dir }}
|
||||
#ExecStart={{ technitium_install_dir }}/start.sh
|
||||
ExecStart={{ technitium_install_dir }}/start.sh --tls-cert /etc/technitium/certs/technitium.crt --tls-key /etc/technitium/certs/technitium.key
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
User=root
|
||||
Group=root
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,4 @@
|
||||
technitium_service_name: "technitium"
|
||||
technitium_binary_url: "https://download.technitium.com/dns/DnsServerPortable.tar.gz"
|
||||
technitium_data_dir: "{{ technitium_install_dir }}/data"
|
||||
technitium_conf_file: "{{ technitium_install_dir }}/Technitium.Dns.Server.json"
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
vault_addr: "http://VAULT_IP:VAULT_PORT"
|
||||
|
||||
vault_agent_config_path: "/etc/vault-agent-config.hcl"
|
||||
vault_agent_pid_file: "/var/run/vault-agent.pid"
|
||||
vault_agent_user: "root"
|
||||
vault_agent_service: "vault-agent"
|
||||
vault_agent_systemd_unit: "/etc/systemd/system/vault-agent.service"
|
||||
|
||||
# Paths to role_id / secret_id files (written by bootstrap process)
|
||||
vault_role_id_file: "/etc/vault-agent/role_id"
|
||||
vault_secret_id_file: "/etc/vault-agent/secret_id"
|
||||
|
||||
# Templates
|
||||
vault_templates_dir: "/etc/vault-agent-templates"
|
||||
|
||||
vault_agent_templates:
|
||||
# HAProxy
|
||||
- src: "haproxy.pem.ctmpl"
|
||||
dest: "/etc/haproxy/certs/haproxy.pem"
|
||||
service: haproxy
|
||||
- src: "haproxy_ca.ctmpl"
|
||||
dest: "/etc/haproxy/certs/haproxy_ca.crt"
|
||||
service: haproxy
|
||||
- src: "thesabear-client.ctmpl"
|
||||
dest: "/etc/haproxy/certs/clients/thesabear-client.pem"
|
||||
service: "haproxy"
|
||||
|
||||
# Technitium
|
||||
- src: "technitium_cert.ctmpl"
|
||||
dest: "/etc/technitium/certs/technitium.crt"
|
||||
service: technitium
|
||||
- src: "technitium_key.ctmpl"
|
||||
dest: "/etc/technitium/certs/technitium.key"
|
||||
service: technitium
|
||||
- src: "technitium_ca.ctmpl"
|
||||
dest: "/etc/technitium/certs/technitium_ca.crt"
|
||||
service: technitium
|
||||
|
||||
# Default Vault PKI options (can remain)
|
||||
pki_mount_path: "pki"
|
||||
@@ -0,0 +1,3 @@
|
||||
{{- with secret "pki/cert/ca" -}}
|
||||
{{ trim .Data.certificate "\n" }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,7 @@
|
||||
{% raw %}
|
||||
{{- with secret "pki/issue/{{ wildcard_role_name }}" "common_name={{ common_name }}" -}}
|
||||
{{ .Data.certificate }}
|
||||
{{ .Data.private_key }}
|
||||
{{ .Data.issuing_ca }}
|
||||
{{- end }}
|
||||
{% endraw %}
|
||||
@@ -0,0 +1,6 @@
|
||||
{{ with secret "pki/issue/securevault-wildcard" "common_name=*.local.DOMAIN_PLACEHOLDER" "ttl=8760h" }}
|
||||
{{ .Data.certificate }}
|
||||
{{ .Data.issuing_ca }}
|
||||
{{ .Data.private_key }}
|
||||
{{ end }}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{{- with secret "pki/issue/securevault-wildcard" "common_name=*.local.DOMAIN_PLACEHOLDER" -}}
|
||||
{{ .Data.issuing_ca }}
|
||||
{{- end }}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{{- with secret "pki_int/issue/securevault-wildcard" "common_name=technitium.local.DOMAIN_PLACEHOLDER" -}}
|
||||
{{ .Data.issuing_ca }}
|
||||
{{- end }}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{{- with secret "pki_int/issue/securevault-wildcard" "common_name=technitium.local.DOMAIN_PLACEHOLDER" -}}
|
||||
{{ .Data.certificate }}
|
||||
{{- end }}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{{- with secret "pki_int/issue/securevault-wildcard" "common_name=technitium.local.DOMAIN_PLACEHOLDER" -}}
|
||||
{{ .Data.private_key }}
|
||||
{{- end }}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{{ with secret "pki_int/issue/mtls-client-cert" "common_name=clientname.local.DOMAIN_PLACEHOLDER" "ttl=8760h" }}
|
||||
{{ .Data.certificate }}
|
||||
{{ .Data.private_key }}
|
||||
{{ .Data.issuing_ca }}
|
||||
{{ end }}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
---
|
||||
- name: Reload systemd
|
||||
command: systemctl daemon-reload
|
||||
@@ -0,0 +1,230 @@
|
||||
---
|
||||
# ==========================================================
|
||||
# 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"
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
pid_file = "{{ vault_agent_pid_file }}"
|
||||
|
||||
auto_auth {
|
||||
method {
|
||||
type = "approle"
|
||||
config = {
|
||||
role_id_file_path = "{{ vault_role_id_file }}"
|
||||
secret_id_file_path = "{{ vault_secret_id_file }}"
|
||||
remove_secret_id_file_after_reading = false
|
||||
}
|
||||
}
|
||||
sink {
|
||||
type = "file"
|
||||
config = {
|
||||
path = "/etc/vault-token"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{% for tpl in vault_agent_templates if tpl.service == hostvars[inventory_hostname].service %}
|
||||
template {
|
||||
source = "{{ vault_templates_dir }}/{{ tpl.src }}"
|
||||
destination = "{{ tpl.dest }}"
|
||||
perms = "0644"
|
||||
}
|
||||
{% endfor %}
|
||||
|
||||
vault {
|
||||
address = "{{ vault_addr }}"
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=Vault Agent
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/vault agent -config={{ vault_agent_config_path }}
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
User={{ vault_agent_user }}
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in new issue
Block a user