--- - name: Set up Fleet hosts: localhost become: yes gather_facts: no vars: headers: kbn-version: "8.15.3" kbn-xsrf: "kibana" Content-Type: "application/json" max_retries: 60 delay_seconds: 10 debug_mode: false installed_file: "/opt/lme/FLEET_SETUP_FINISHED" tasks: - name: Check if INSTALLED file exists stat: path: "{{ installed_file }}" register: installed_file_check - name: Exit cleanly if INSTALLED file exists debug: msg: "The INSTALLED file exists. Exiting the play cleanly." when: installed_file_check.stat.exists - name: End play if INSTALLED file exists meta: end_play when: installed_file_check.stat.exists #SETUP - name: Read lme-environment.env file ansible.builtin.slurp: src: /opt/lme/lme-environment.env register: lme_env_content - name: Set environment variables ansible.builtin.set_fact: env_dict: "{{ env_dict | default({}) | combine({ item.split('=', 1)[0]: item.split('=', 1)[1] }) }}" loop: "{{ (lme_env_content['content'] | b64decode).split('\n') }}" when: item != '' and not item.startswith('#') - name: Display set environment variables debug: msg: "Set {{ item.key }}" loop: "{{ env_dict | dict2items }}" when: item.value | length > 0 and (not debug_mode) - name: Source extract_secrets ansible.builtin.shell: | set -a . {{ playbook_dir }}/../scripts/extract_secrets.sh -q echo "elastic=$elastic" echo "wazuh=$wazuh" echo "kibana_system=$kibana_system" echo "wazuh_api=$wazuh_api" args: executable: /bin/bash register: extract_secrets_vars no_log: "{{ not debug_mode }}" - name: Set secret variables ansible.builtin.set_fact: env_dict: "{{ env_dict | combine({ item.split('=', 1)[0]: item.split('=', 1)[1] }) }}" loop: "{{ extract_secrets_vars.stdout_lines }}" no_log: "{{ not debug_mode }}" - name: Set playbook variables ansible.builtin.set_fact: ipvar: "{{ env_dict.IPVAR | default('') }}" local_kbn_url: "{{ env_dict.LOCAL_KBN_URL | default('') }}" local_es_url: "{{ env_dict.LOCAL_ES_URL | default('') }}" stack_version: "{{ env_dict.STACK_VERSION | default('') }}" cluster_name: "{{ env_dict.CLUSTER_NAME | default('') }}" elastic_username: "{{ env_dict.ELASTIC_USERNAME | default('') }}" elasticsearch_username: "{{ env_dict.ELASTICSEARCH_USERNAME | default('') }}" kibana_fleet_username: "{{ env_dict.KIBANA_FLEET_USERNAME | default('') }}" indexer_username: "{{ env_dict.INDEXER_USERNAME | default('') }}" api_username: "{{ env_dict.API_USERNAME | default('') }}" license: "{{ env_dict.LICENSE | default('') }}" es_port: "{{ env_dict.ES_PORT | default('') }}" kibana_port: "{{ env_dict.KIBANA_PORT | default('') }}" fleet_port: "{{ env_dict.FLEET_PORT | default('') }}" mem_limit: "{{ env_dict.MEM_LIMIT | default('') }}" elastic_password: "{{ env_dict.elastic | default('') }}" wazuh_password: "{{ env_dict.wazuh | default('') }}" kibana_system_password: "{{ env_dict.kibana_system | default('') }}" wazuh_api_password: "{{ env_dict.wazuh_api | default('') }}" - name: Debug - Display set variables (sensitive information redacted) debug: msg: - "ipvar: {{ ipvar }}" - "local_kbn_url: {{ local_kbn_url }}" - "local_es_url: {{ local_es_url }}" - "elastic_username: {{ elastic_username }}" - "stack_version: {{ stack_version }}" - "cluster_name: {{ cluster_name }}" - "elasticsearch_username: {{ elasticsearch_username }}" - "kibana_fleet_username: {{ kibana_fleet_username }}" - "indexer_username: {{ indexer_username }}" - "api_username: {{ api_username }}" - "license: {{ license }}" - "es_port: {{ es_port }}" - "kibana_port: {{ kibana_port }}" - "fleet_port: {{ fleet_port }}" - "mem_limit: {{ mem_limit }}" - "elastic password is set: {{ elastic_password | length > 0 }}" - "wazuh password is set: {{ wazuh_password | length > 0 }}" - "kibana_system password is set: {{ kibana_system_password | length > 0 }}" - "wazuh_api password is set: {{ wazuh_api_password | length > 0 }}" when: debug_mode | bool #SETUP - name: Wait for Kibana port to be available wait_for: host: "{{ ipvar }}" port: "{{ kibana_port | int }}" timeout: 120 # 2 minutes sleep: 60 # Check every minute msg: "Timeout waiting for Kibana port {{ kibana_port }} to become available" register: kibana_port_check until: kibana_port_check.state is defined and kibana_port_check.state == "started" retries: 15 delay: 0 ignore_errors: no - name: Debug wait_for results debug: msg: - "State: {{ kibana_port_check.state }}" - "Full result: {{ kibana_port_check }}" when: debug_mode | bool - name: Wait for Fleet API to be ready ansible.builtin.shell: | attempt=0 max_attempts=30 delay=10 while [ $attempt -lt $max_attempts ]; do response=$(curl -s -o /dev/null -w "%{http_code}" -k -u elastic:{{ elastic_password }} {{ local_kbn_url }}/api/fleet/agents/setup) if [ "$response" = "200" ]; then echo "Fleet API is ready. Proceeding with configuration..." exit 0 fi echo "Waiting for Fleet API to be ready..." sleep $delay attempt=$((attempt+1)) done echo "Fleet API did not become ready within the expected time." exit 1 args: executable: /bin/bash register: fleet_api_check changed_when: false no_log: "{{ not debug_mode }}" - name: Display Fleet API check result debug: var: fleet_api_check.stdout_lines - name: Confirm Fleet API is ready debug: msg: "Fleet API is ready" when: "'Fleet API is ready' in fleet_api_check.stdout" - name: Fail if Fleet API is not ready fail: msg: "Fleet API did not become ready within the expected time." when: "'Fleet API is ready' not in fleet_api_check.stdout" - name: Get CA fingerprint ansible.builtin.shell: | sudo bash -c ' set -a . {{ playbook_dir }}/../scripts/extract_secrets.sh -q set +a /nix/var/nix/profiles/default/bin/podman exec -w /usr/share/elasticsearch/config/certs/ca lme-elasticsearch cat ca.crt | openssl x509 -noout -fingerprint -sha256 | cut -d "=" -f 2 | tr -d : | head -n1 ' register: ca_fingerprint changed_when: false become: yes become_method: sudo no_log: "{{ not debug_mode }}" - name: Display CA fingerprint debug: var: ca_fingerprint.stdout when: - ca_fingerprint is defined - ca_fingerprint.stdout is defined - debug_mode | bool - name: Set Fleet server hosts uri: url: "{{ local_kbn_url }}/api/fleet/settings" method: PUT user: "{{ elastic_username }}" password: "{{ elastic_password }}" force_basic_auth: yes validate_certs: no headers: "{{ headers }}" body_format: json body: fleet_server_hosts: ["https://{{ ipvar }}:{{ fleet_port }}"] register: fleet_server_hosts_result no_log: "{{ not debug_mode }}" ignore_errors: yes - name: Debug Fleet server hosts result debug: var: fleet_server_hosts_result when: fleet_server_hosts_result is defined and debug_mode | bool - name: Set Fleet default output hosts uri: url: "{{ local_kbn_url }}/api/fleet/outputs/fleet-default-output" method: PUT user: "{{ elastic_username }}" password: "{{ elastic_password }}" force_basic_auth: yes validate_certs: no headers: "{{ headers }}" body_format: json body: hosts: ["https://{{ ipvar }}:9200"] register: fleet_output_hosts_result until: fleet_output_hosts_result.status == 200 retries: 12 delay: 30 no_log: "{{ not debug_mode }}" ignore_errors: yes - name: Debug Fleet default output hosts result debug: var: fleet_output_hosts_result when: fleet_output_hosts_result is defined - name: Set Fleet default output CA trusted fingerprint uri: url: "{{ local_kbn_url }}/api/fleet/outputs/fleet-default-output" method: PUT user: "{{ elastic_username }}" password: "{{ elastic_password }}" force_basic_auth: yes validate_certs: no headers: "{{ headers }}" body_format: json body: ca_trusted_fingerprint: "{{ ca_fingerprint.stdout }}" register: fleet_output_fingerprint_result until: fleet_output_fingerprint_result.status == 200 retries: 12 delay: 30 no_log: "{{ not debug_mode }}" - name: Set Fleet default output SSL verification mode uri: url: "{{ local_kbn_url }}/api/fleet/outputs/fleet-default-output" method: PUT user: "{{ elastic_username }}" password: "{{ elastic_password }}" force_basic_auth: yes validate_certs: no headers: "{{ headers }}" body_format: json body: config_yaml: "ssl.verification_mode: certificate" register: fleet_output_ssl_result no_log: "{{ not debug_mode }}" - name: Wait for Kibana to be fully ready uri: url: "{{ local_kbn_url }}/api/status" method: GET user: "{{ elastic_username }}" password: "{{ elastic_password }}" force_basic_auth: yes validate_certs: no status_code: 200 register: kibana_status until: kibana_status.status == 200 and kibana_status.json.status.overall.level == "available" retries: 36 # With a 10 second delay, this gives us 6 minutes total delay: 10 no_log: "{{ not debug_mode }}" - name: Debug Kibana status debug: var: kibana_status when: debug_mode | bool - name: Fail if Kibana is not ready fail: msg: "Kibana did not become ready within the expected time. Status: {{ kibana_status | default('unknown') }}" when: kibana_status.status is not defined or kibana_status.status != 200 - name: Wait for Fleet API to be ready ansible.builtin.shell: | attempt=0 max_attempts=30 delay=10 while [ $attempt -lt $max_attempts ]; do response=$(curl -s -o /dev/null -w "%{http_code}" -k -u elastic:{{ elastic_password }} {{ local_kbn_url }}/api/fleet/agents/setup) if [ "$response" = "200" ]; then echo "Fleet API is ready. Proceeding with configuration..." exit 0 fi echo "Waiting for Fleet API to be ready..." sleep $delay attempt=$((attempt+1)) done echo "Fleet API did not become ready within the expected time." exit 1 register: fleet_api_check changed_when: false no_log: "{{ not debug_mode }}" - name: Display Fleet API check result debug: var: fleet_api_check.stdout_lines - name: Confirm Fleet API is ready debug: msg: "Fleet API is ready" when: "'Fleet API is ready' in fleet_api_check.stdout" - name: Fail if Fleet API is not ready fail: msg: "Fleet API did not become ready within the expected time." when: "'Fleet API is ready' not in fleet_api_check.stdout" - name: Create Endpoint Policy uri: url: "{{ local_kbn_url }}/api/fleet/agent_policies?sys_monitoring=true" method: POST user: "{{ elastic_username }}" password: "{{ elastic_password }}" force_basic_auth: yes validate_certs: no headers: "{{ headers }}" body_format: json body: name: "Endpoint Policy" description: "" namespace: "default" monitoring_enabled: ["logs", "metrics"] inactivity_timeout: 1209600 timeout: 600 status_code: [200, 409] register: endpoint_policy_result until: endpoint_policy_result.status in [200, 409] retries: 12 delay: 30 no_log: "{{ not debug_mode }}" - name: Debug endpoint_policy_result debug: var: endpoint_policy_result - name: Set policy ID fact for new policy set_fact: policy_id: "{{ endpoint_policy_result.json.item.id }}" when: endpoint_policy_result.status == 200 - name: Get existing policy ID if creation failed uri: url: "{{ local_kbn_url }}/api/fleet/agent_policies" method: GET user: "{{ elastic_username }}" password: "{{ elastic_password }}" force_basic_auth: yes validate_certs: no headers: "{{ headers }}" register: existing_policies when: endpoint_policy_result.status == 409 no_log: "{{ not debug_mode }}" - name: Debug existing_policies debug: var: existing_policies - name: Set policy ID fact for existing policy set_fact: policy_id: "{{ item.id }}" when: - endpoint_policy_result.status == 409 - item.name == 'Endpoint Policy' loop: "{{ existing_policies.json['items'] | list }}" - name: Debug policy ID debug: var: policy_id when: debug_mode | bool - name: Fail if policy ID is not set fail: msg: "Failed to get policy ID. Neither creation nor lookup of existing policy succeeded." when: policy_id is not defined - name: Get Endpoint package version uri: url: "{{ local_kbn_url }}/api/fleet/epm/packages/endpoint" method: GET user: "{{ elastic_username }}" password: "{{ elastic_password }}" force_basic_auth: yes validate_certs: no headers: "{{ headers }}" register: endpoint_package_result no_log: "{{ not debug_mode }}" - name: Create Elastic Defend package policy uri: url: "{{ local_kbn_url }}/api/fleet/package_policies" method: POST user: "{{ elastic_username }}" password: "{{ elastic_password }}" force_basic_auth: yes validate_certs: no headers: "{{ headers }}" body_format: json timeout: 600 status_code: [200, 409] body: name: "Elastic Defend" description: "" namespace: "default" policy_id: "{{ policy_id }}" enabled: true inputs: - enabled: true streams: [] type: "ENDPOINT_INTEGRATION_CONFIG" config: _config: value: type: "endpoint" endpointConfig: preset: "EDRComplete" package: name: "endpoint" title: "Elastic Defend" version: "{{ endpoint_package_result.json.item.version }}" register: elastic_defend_policy_result until: elastic_defend_policy_result.status in [200, 409] retries: 12 delay: 30 no_log: "{{ not debug_mode }}" ignore_errors: yes - name: Display results debug: var: "{{ item }}" loop: - fleet_server_hosts_result - fleet_output_hosts_result - fleet_output_fingerprint_result - fleet_output_ssl_result - endpoint_policy_result - elastic_defend_policy_result - name: Create INSTALLED file file: path: "{{ installed_file }}" state: touch when: not installed_file_check.stat.exists - name: Wait for Fleet to be fully initialized uri: url: "{{ local_kbn_url }}/api/fleet/agents/setup" method: GET user: "{{ elastic_username }}" password: "{{ elastic_password }}" force_basic_auth: yes validate_certs: no status_code: 200 register: fleet_status until: fleet_status.status == 200 retries: 36 # With 10 second delay, this gives us 6 minutes total delay: 10 no_log: "{{ not debug_mode }}" - name: Debug Fleet status debug: var: fleet_status when: debug_mode | bool - name: Fail if Fleet is not ready fail: msg: "Fleet did not become ready within the expected time. Status: {{ fleet_status | default('unknown') }}" when: fleet_status.status is not defined or fleet_status.status != 200 - name: Install LME Dashboards hosts: localhost become: yes gather_facts: no vars: max_retries: 60 delay_seconds: 10 debug_mode: false clone_directory: "{{ clone_dir | default('~/LME') }}" dashboards_path: "/opt/lme/dashboards/elastic/*.ndjson" kibana_url: "https://127.0.0.1:5601/api/saved_objects/_import?overwrite=true" install_user: "root" installed_file: "/opt/lme/dashboards/elastic/INSTALLED" #TODO: have a task that creates dashboard_update user for later dashboard runs tasks: - name: Check if INSTALLED file exists stat: path: "{{ installed_file }}" register: installed_file_check - name: Exit cleanly if INSTALLED file exists debug: msg: "The INSTALLED file exists. Exiting the play cleanly." when: installed_file_check.stat.exists - name: End play if INSTALLED file exists meta: end_play when: installed_file_check.stat.exists #SETUP - name: Read lme-environment.env file ansible.builtin.slurp: src: /opt/lme/lme-environment.env register: lme_env_content - name: Set environment variables ansible.builtin.set_fact: env_dict: "{{ env_dict | default({}) | combine({ item.split('=', 1)[0]: item.split('=', 1)[1] }) }}" loop: "{{ (lme_env_content['content'] | b64decode).split('\n') }}" when: item != '' and not item.startswith('#') - name: Display set environment variables debug: msg: "Set {{ item.key }}" loop: "{{ env_dict | dict2items }}" when: item.value | length > 0 and (not debug_mode) - name: Source extract_secrets ansible.builtin.shell: | set -a . {{ playbook_dir }}/../scripts/extract_secrets.sh -q echo "elastic=$elastic" echo "wazuh=$wazuh" echo "kibana_system=$kibana_system" echo "wazuh_api=$wazuh_api" args: executable: /bin/bash register: extract_secrets_vars no_log: "{{ not debug_mode }}" - name: Set secret variables ansible.builtin.set_fact: env_dict: "{{ env_dict | combine({ item.split('=', 1)[0]: item.split('=', 1)[1] }) }}" loop: "{{ extract_secrets_vars.stdout_lines }}" no_log: "{{ not debug_mode }}" - name: Set playbook variables ansible.builtin.set_fact: ipvar: "{{ env_dict.IPVAR | default('') }}" local_kbn_url: "{{ env_dict.LOCAL_KBN_URL | default('') }}" local_es_url: "{{ env_dict.LOCAL_ES_URL | default('') }}" stack_version: "{{ env_dict.STACK_VERSION | default('') }}" cluster_name: "{{ env_dict.CLUSTER_NAME | default('') }}" elastic_username: "{{ env_dict.ELASTIC_USERNAME | default('') }}" elasticsearch_username: "{{ env_dict.ELASTICSEARCH_USERNAME | default('') }}" kibana_fleet_username: "{{ env_dict.KIBANA_FLEET_USERNAME | default('') }}" indexer_username: "{{ env_dict.INDEXER_USERNAME | default('') }}" api_username: "{{ env_dict.API_USERNAME | default('') }}" license: "{{ env_dict.LICENSE | default('') }}" es_port: "{{ env_dict.ES_PORT | default('') }}" kibana_port: "{{ env_dict.KIBANA_PORT | default('') }}" fleet_port: "{{ env_dict.FLEET_PORT | default('') }}" mem_limit: "{{ env_dict.MEM_LIMIT | default('') }}" elastic_password: "{{ env_dict.elastic | default('') }}" wazuh_password: "{{ env_dict.wazuh | default('') }}" kibana_system_password: "{{ env_dict.kibana_system | default('') }}" wazuh_api_password: "{{ env_dict.wazuh_api | default('') }}" - name: Debug - Display set variables (sensitive information redacted) debug: msg: - "ipvar: {{ ipvar }}" - "local_kbn_url: {{ local_kbn_url }}" - "local_es_url: {{ local_es_url }}" - "elastic_username: {{ elastic_username }}" - "stack_version: {{ stack_version }}" - "cluster_name: {{ cluster_name }}" - "elasticsearch_username: {{ elasticsearch_username }}" - "kibana_fleet_username: {{ kibana_fleet_username }}" - "indexer_username: {{ indexer_username }}" - "api_username: {{ api_username }}" - "license: {{ license }}" - "es_port: {{ es_port }}" - "kibana_port: {{ kibana_port }}" - "fleet_port: {{ fleet_port }}" - "mem_limit: {{ mem_limit }}" - "elastic password is set: {{ elastic_password | length > 0 }}" - "wazuh password is set: {{ wazuh_password | length > 0 }}" - "kibana_system password is set: {{ kibana_system_password | length > 0 }}" - "wazuh_api password is set: {{ wazuh_api_password | length > 0 }}" when: debug_mode | bool #SETUP - name: Expand clone directory path set_fact: absolute_clone_dir: "{{ clone_directory | expanduser }}" - name: Check if source dashboards directory exists stat: path: "{{ absolute_clone_dir }}/dashboards" register: source_dashboard_dir - name: Fail if source directory doesn't exist fail: msg: "Source dashboards directory {{ source_dashboard_dir.stat.path }} doesn't exist" when: not source_dashboard_dir.stat.exists - name: Copy dashboards files to /opt/lme/dashboards copy: src: "{{ source_dashboard_dir.stat.path }}/" dest: /opt/lme/dashboards/ owner: "{{ install_user }}" group: "{{ install_user }}" mode: '0644' become: yes - name: Get list of dashboards find: paths: "{{ dashboards_path | dirname }}" patterns: "*.ndjson" register: dashboards - name: Upload dashboards to Kibana shell: 'curl -X POST -kL --user "{{ elastic_username }}":"{{ elastic_password }}" -H "kbn-xsrf: true" -F file=@"{{ item }}" "{{ kibana_url }}"' loop: "{{ dashboards.files | map(attribute='path') | list }}" - name: Create INSTALLED file file: path: "{{ installed_file }}" state: touch when: not installed_file_check.stat.exists - name: Install Wazuh Dashboards hosts: localhost become: yes gather_facts: no vars: max_retries: 60 delay_seconds: 10 debug_mode: false clone_directory: "{{ clone_dir | default('~/LME') }}" dashboards_path: "/opt/lme/dashboards/wazuh/*.ndjson" check_path: "/opt/lme/dashboards/wazuh/" kibana_url: "https://127.0.0.1:5601/api/saved_objects/_import?overwrite=true" install_user: "root" installed_file: "/opt/lme/dashboards/wazuh/INSTALLED" tasks: - name: Check if INSTALLED file exists stat: path: "{{ installed_file }}" register: installed_file_check - name: Exit cleanly if INSTALLED file exists debug: msg: "The INSTALLED file exists. Exiting the playbook cleanly." when: installed_file_check.stat.exists - name: End play if INSTALLED file exists meta: end_play when: installed_file_check.stat.exists #SETUP - name: Read lme-environment.env file ansible.builtin.slurp: src: /opt/lme/lme-environment.env register: lme_env_content - name: Set environment variables ansible.builtin.set_fact: env_dict: "{{ env_dict | default({}) | combine({ item.split('=', 1)[0]: item.split('=', 1)[1] }) }}" loop: "{{ (lme_env_content['content'] | b64decode).split('\n') }}" when: item != '' and not item.startswith('#') - name: Display set environment variables debug: msg: "Set {{ item.key }}" loop: "{{ env_dict | dict2items }}" when: item.value | length > 0 and ( not debug_mode ) - name: Source extract_secrets ansible.builtin.shell: | set -a . {{ playbook_dir }}/../scripts/extract_secrets.sh -q echo "elastic=$elastic" echo "wazuh=$wazuh" echo "kibana_system=$kibana_system" echo "wazuh_api=$wazuh_api" args: executable: /bin/bash register: extract_secrets_vars no_log: "{{ not debug_mode }}" - name: Set secret variables ansible.builtin.set_fact: env_dict: "{{ env_dict | combine({ item.split('=', 1)[0]: item.split('=', 1)[1] }) }}" loop: "{{ extract_secrets_vars.stdout_lines }}" no_log: "{{ not debug_mode }}" - name: Set playbook variables ansible.builtin.set_fact: ipvar: "{{ env_dict.IPVAR | default('') }}" local_kbn_url: "{{ env_dict.LOCAL_KBN_URL | default('') }}" local_es_url: "{{ env_dict.LOCAL_ES_URL | default('') }}" stack_version: "{{ env_dict.STACK_VERSION | default('') }}" cluster_name: "{{ env_dict.CLUSTER_NAME | default('') }}" elastic_username: "{{ env_dict.ELASTIC_USERNAME | default('') }}" elasticsearch_username: "{{ env_dict.ELASTICSEARCH_USERNAME | default('') }}" kibana_fleet_username: "{{ env_dict.KIBANA_FLEET_USERNAME | default('') }}" indexer_username: "{{ env_dict.INDEXER_USERNAME | default('') }}" api_username: "{{ env_dict.API_USERNAME | default('') }}" license: "{{ env_dict.LICENSE | default('') }}" es_port: "{{ env_dict.ES_PORT | default('') }}" kibana_port: "{{ env_dict.KIBANA_PORT | default('') }}" fleet_port: "{{ env_dict.FLEET_PORT | default('') }}" mem_limit: "{{ env_dict.MEM_LIMIT | default('') }}" elastic_password: "{{ env_dict.elastic | default('') }}" wazuh_password: "{{ env_dict.wazuh | default('') }}" kibana_system_password: "{{ env_dict.kibana_system | default('') }}" wazuh_api_password: "{{ env_dict.wazuh_api | default('') }}" - name: Debug - Display set variables (sensitive information redacted) debug: msg: - "ipvar: {{ ipvar }}" - "local_kbn_url: {{ local_kbn_url }}" - "local_es_url: {{ local_es_url }}" - "elastic_username: {{ elastic_username }}" - "stack_version: {{ stack_version }}" - "cluster_name: {{ cluster_name }}" - "elasticsearch_username: {{ elasticsearch_username }}" - "kibana_fleet_username: {{ kibana_fleet_username }}" - "indexer_username: {{ indexer_username }}" - "api_username: {{ api_username }}" - "license: {{ license }}" - "es_port: {{ es_port }}" - "kibana_port: {{ kibana_port }}" - "fleet_port: {{ fleet_port }}" - "mem_limit: {{ mem_limit }}" - "elastic password is set: {{ elastic_password | length > 0 }}" - "wazuh password is set: {{ wazuh_password | length > 0 }}" - "kibana_system password is set: {{ kibana_system_password | length > 0 }}" - "wazuh_api password is set: {{ wazuh_api_password | length > 0 }}" when: debug_mode | bool #SETUP - name: Check if dashboards_path exists stat: path: "{{ check_path }}" register: path - name: Fail if dashboards_path doesn't exist fail: msg: "Dashboards path {{ check_path }} doesn't exist, theres been an error" when: - not path.stat.exists - name: Get list of dashboards find: paths: "{{ dashboards_path | dirname }}" patterns: "*.ndjson" register: dashboards - name: Upload dashboards to Kibana shell: 'curl -X POST -kL --user "{{ elastic_username }}":"{{ elastic_password }}" -H "kbn-xsrf: true" -F file=@"{{ item }}" "{{ kibana_url }}"' loop: "{{ dashboards.files | map(attribute='path') | list }}" - name: Create INSTALLED file file: path: "{{ installed_file }}" state: touch when: not installed_file_check.stat.exists - name: Fix Wazuh Post Install Issues hosts: localhost become: yes gather_facts: no vars: max_retries: 60 delay_seconds: 10 debug_mode: false clone_directory: "{{ clone_dir | default('~/LME') }}" install_user: "{{ ansible_user_id }}" tasks: #SETUP - name: Read lme-environment.env file ansible.builtin.slurp: src: /opt/lme/lme-environment.env register: lme_env_content - name: Set environment variables ansible.builtin.set_fact: env_dict: "{{ env_dict | default({}) | combine({ item.split('=', 1)[0]: item.split('=', 1)[1] }) }}" loop: "{{ (lme_env_content['content'] | b64decode).split('\n') }}" when: item != '' and not item.startswith('#') - name: Display set environment variables debug: msg: "Set {{ item.key }}" loop: "{{ env_dict | dict2items }}" when: item.value | length > 0 and (not debug_mode) - name: Source extract_secrets ansible.builtin.shell: | set -a . {{ playbook_dir }}/../scripts/extract_secrets.sh -q echo "elastic=$elastic" echo "wazuh=$wazuh" echo "kibana_system=$kibana_system" echo "wazuh_api=$wazuh_api" args: executable: /bin/bash register: extract_secrets_vars no_log: "{{ not debug_mode }}" - name: Set secret variables ansible.builtin.set_fact: env_dict: "{{ env_dict | combine({ item.split('=', 1)[0]: item.split('=', 1)[1] }) }}" loop: "{{ extract_secrets_vars.stdout_lines }}" no_log: "{{ not debug_mode }}" - name: Set playbook variables ansible.builtin.set_fact: ipvar: "{{ env_dict.IPVAR | default('') }}" local_kbn_url: "{{ env_dict.LOCAL_KBN_URL | default('') }}" local_es_url: "{{ env_dict.LOCAL_ES_URL | default('') }}" stack_version: "{{ env_dict.STACK_VERSION | default('') }}" cluster_name: "{{ env_dict.CLUSTER_NAME | default('') }}" elastic_username: "{{ env_dict.ELASTIC_USERNAME | default('') }}" elasticsearch_username: "{{ env_dict.ELASTICSEARCH_USERNAME | default('') }}" kibana_fleet_username: "{{ env_dict.KIBANA_FLEET_USERNAME | default('') }}" indexer_username: "{{ env_dict.INDEXER_USERNAME | default('') }}" api_username: "{{ env_dict.API_USERNAME | default('') }}" license: "{{ env_dict.LICENSE | default('') }}" es_port: "{{ env_dict.ES_PORT | default('') }}" kibana_port: "{{ env_dict.KIBANA_PORT | default('') }}" fleet_port: "{{ env_dict.FLEET_PORT | default('') }}" mem_limit: "{{ env_dict.MEM_LIMIT | default('') }}" elastic_password: "{{ env_dict.elastic | default('') }}" wazuh_password: "{{ env_dict.wazuh | default('') }}" kibana_system_password: "{{ env_dict.kibana_system | default('') }}" wazuh_api_password: "{{ env_dict.wazuh_api | default('') }}" - name: Debug - Display set variables (sensitive information redacted) debug: msg: - "ipvar: {{ ipvar }}" - "local_kbn_url: {{ local_kbn_url }}" - "local_es_url: {{ local_es_url }}" - "elastic_username: {{ elastic_username }}" - "stack_version: {{ stack_version }}" - "cluster_name: {{ cluster_name }}" - "elasticsearch_username: {{ elasticsearch_username }}" - "kibana_fleet_username: {{ kibana_fleet_username }}" - "indexer_username: {{ indexer_username }}" - "api_username: {{ api_username }}" - "license: {{ license }}" - "es_port: {{ es_port }}" - "kibana_port: {{ kibana_port }}" - "fleet_port: {{ fleet_port }}" - "mem_limit: {{ mem_limit }}" - "elastic password is set: {{ elastic_password | length > 0 }}" - "wazuh password is set: {{ wazuh_password | length > 0 }}" - "kibana_system password is set: {{ kibana_system_password | length > 0 }}" - "wazuh_api password is set: {{ wazuh_api_password | length > 0 }}" when: debug_mode | bool #SETUP # - name: expand path set_fact: clone_directory: "{{clone_directory | expanduser }}" - name: fix wazuh password # TODO: This might need to check if the container is running. It has failed before. ansible.builtin.expect: #source + podman exec command: "{{ clone_directory }}/scripts/wazuh_rbac.sh" responses: ".*'wazuh'.*": - "{{ wazuh_password }}" ".*'wazuh-wui'.*": - "{{ wazuh_api_password }}" timeout: 60 become: yes - name: Create Read Only User hosts: localhost become: yes gather_facts: no vars: max_retries: 60 delay_seconds: 10 debug_mode: false clone_directory: "{{ clone_dir | default('~/LME') }}" install_user: "root" tasks: #SETUP - name: Read lme-environment.env file ansible.builtin.slurp: src: /opt/lme/lme-environment.env register: lme_env_content - name: Set environment variables ansible.builtin.set_fact: env_dict: "{{ env_dict | default({}) | combine({ item.split('=', 1)[0]: item.split('=', 1)[1] }) }}" loop: "{{ (lme_env_content['content'] | b64decode).split('\n') }}" when: item != '' and not item.startswith('#') - name: Display set environment variables debug: msg: "Set {{ item.key }}" loop: "{{ env_dict | dict2items }}" when: item.value | length > 0 and (not debug_mode) - name: Source extract_secrets ansible.builtin.shell: | set -a . {{ playbook_dir }}/../scripts/extract_secrets.sh -q echo "elastic=$elastic" echo "wazuh=$wazuh" echo "kibana_system=$kibana_system" echo "wazuh_api=$wazuh_api" args: executable: /bin/bash register: extract_secrets_vars no_log: "{{ not debug_mode }}" - name: Set secret variables ansible.builtin.set_fact: env_dict: "{{ env_dict | combine({ item.split('=', 1)[0]: item.split('=', 1)[1] }) }}" loop: "{{ extract_secrets_vars.stdout_lines }}" no_log: "{{ not debug_mode }}" - name: Set playbook variables ansible.builtin.set_fact: ipvar: "{{ env_dict.IPVAR | default('') }}" local_kbn_url: "{{ env_dict.LOCAL_KBN_URL | default('') }}" local_es_url: "{{ env_dict.LOCAL_ES_URL | default('') }}" stack_version: "{{ env_dict.STACK_VERSION | default('') }}" cluster_name: "{{ env_dict.CLUSTER_NAME | default('') }}" elastic_username: "{{ env_dict.ELASTIC_USERNAME | default('') }}" elasticsearch_username: "{{ env_dict.ELASTICSEARCH_USERNAME | default('') }}" kibana_fleet_username: "{{ env_dict.KIBANA_FLEET_USERNAME | default('') }}" indexer_username: "{{ env_dict.INDEXER_USERNAME | default('') }}" api_username: "{{ env_dict.API_USERNAME | default('') }}" license: "{{ env_dict.LICENSE | default('') }}" es_port: "{{ env_dict.ES_PORT | default('') }}" kibana_port: "{{ env_dict.KIBANA_PORT | default('') }}" fleet_port: "{{ env_dict.FLEET_PORT | default('') }}" mem_limit: "{{ env_dict.MEM_LIMIT | default('') }}" elastic_password: "{{ env_dict.elastic | default('') }}" wazuh_password: "{{ env_dict.wazuh | default('') }}" kibana_system_password: "{{ env_dict.kibana_system | default('') }}" wazuh_api_password: "{{ env_dict.wazuh_api | default('') }}" - name: Debug - Display set variables (sensitive information redacted) debug: msg: - "ipvar: {{ ipvar }}" - "local_kbn_url: {{ local_kbn_url }}" - "local_es_url: {{ local_es_url }}" - "elastic_username: {{ elastic_username }}" - "stack_version: {{ stack_version }}" - "cluster_name: {{ cluster_name }}" - "elasticsearch_username: {{ elasticsearch_username }}" - "kibana_fleet_username: {{ kibana_fleet_username }}" - "indexer_username: {{ indexer_username }}" - "api_username: {{ api_username }}" - "license: {{ license }}" - "es_port: {{ es_port }}" - "kibana_port: {{ kibana_port }}" - "fleet_port: {{ fleet_port }}" - "mem_limit: {{ mem_limit }}" - "elastic password is set: {{ elastic_password | length > 0 }}" - "wazuh password is set: {{ wazuh_password | length > 0 }}" - "kibana_system password is set: {{ kibana_system_password | length > 0 }}" - "wazuh_api password is set: {{ wazuh_api_password | length > 0 }}" when: debug_mode | bool #SETUP - name: Wait for Elasticsearch to be ready uri: url: "{{ local_es_url }}" method: GET user: "{{ elastic_username }}" password: "{{ elastic_password }}" force_basic_auth: yes validate_certs: no status_code: 200 register: result until: result.status is defined and result.status == 200 retries: 60 delay: 10 ignore_errors: yes - name: Check if Elasticsearch is ready fail: msg: "Elasticsearch is not ready after 10 minutes. Please check the LME service and Elasticsearch logs." when: result.status is not defined or result.status != 200 #TODO: --cacert "{{ ansible_env.HOME }}/.local/share/containers/storage/volumes/lme_certs/_data/ca/ca.crt" - name: Create readonly role using curl shell: > curl -X POST "{{ local_es_url }}/_security/role/readonly_role" -u "{{ elastic_username }}:{{ elastic_password }}" -k -H "Content-Type: application/json" -d '{ "indices": [ { "names": ["*"], "privileges": ["read", "view_index_metadata"] } ], "cluster": ["monitor"], "applications": [ { "application": "kibana-.kibana", "privileges": ["read"], "resources": ["*"] } ] }' register: role_creation_result when: result.status is defined and result.status == 200 - name: Display role creation result debug: msg: "Role creation output: {{ role_creation_result.stdout | default('Role creation skipped') }}" #maybe check for each in the shell script below? - name: Register a variable, ignore errors and continue shell: | source /root/.profile password=$( curl -X POST "{{ local_es_url }}/_security/user/readonly_user" -u "{{ elastic_username }}:{{ elastic_password }}" -kL -H "Content-Type: application/json" -d '{ "password": "{{ read_only_password.stdout }}", "roles": ["readonly_role"], "full_name": "Read Only User" }' args: warn: false register: user_creation_result when: result.status is defined and result.status == 200 - name: Display user creation result debug: msg: "User creation output: {{ user_creation_result.stdout | default('User creation skipped') }}" - name: DISPLAY NEW READONLY USER PASSWORD debug: msg: "LOGIN WITH readonly_user via:\n USER: readonlyuser\nPassword: {{ read_only_password.stdout }}"