From 642903d776a304bd00857f214976783246527486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Correa=20Rodr=C3=ADguez?= Date: Thu, 22 Aug 2024 09:42:05 +0200 Subject: [PATCH 1/2] Added Wazuh installation assistant without changes --- unattended_installer/Development-guide.md | 46 + unattended_installer/builder.sh | 332 +++++++ .../cert_tool/certFunctions.sh | 469 +++++++++ unattended_installer/cert_tool/certMain.sh | 261 +++++ .../cert_tool/certVariables.sh | 14 + .../common_functions/common.sh | 221 +++++ .../common_functions/commonVariables.sh | 10 + .../config/certificate/config.yml | 26 + .../config/certificate/config_aio.yml | 10 + .../config/dashboard/dashboard.yml | 15 + .../config/dashboard/dashboard_all_in_one.yml | 15 + .../config/dashboard/dashboard_unattended.yml | 15 + .../dashboard_unattended_distributed.yml | 13 + .../config/filebeat/filebeat.yml | 31 + .../config/filebeat/filebeat_all_in_one.yml | 31 + .../config/filebeat/filebeat_distributed.yml | 38 + .../filebeat/filebeat_elastic_cluster.yml | 31 + .../config/filebeat/filebeat_unattended.yml | 43 + .../config/indexer/indexer.yml | 36 + .../config/indexer/indexer_all_in_one.yml | 41 + .../indexer_unattended_distributed.yml | 41 + .../config/indexer/roles/internal_users.yml | 56 ++ .../config/indexer/roles/roles.yml | 149 +++ .../config/indexer/roles/roles_mapping.yml | 87 ++ .../install_functions/checks.sh | 495 +++++++++ .../install_functions/dashboard.sh | 226 +++++ .../install_functions/filebeat.sh | 132 +++ .../install_functions/indexer.sh | 218 ++++ .../install_functions/installCommon.sh | 938 ++++++++++++++++++ .../install_functions/installMain.sh | 425 ++++++++ .../install_functions/installVariables.sh | 68 ++ .../install_functions/manager.sh | 102 ++ .../wazuh-offline-download.sh | 171 ++++ .../wazuh-offline-installation.sh | 103 ++ .../passwords_tool/passwordsFunctions.sh | 647 ++++++++++++ .../passwords_tool/passwordsMain.sh | 285 ++++++ .../passwords_tool/passwordsVariables.sh | 10 + 37 files changed, 5851 insertions(+) create mode 100644 unattended_installer/Development-guide.md create mode 100755 unattended_installer/builder.sh create mode 100644 unattended_installer/cert_tool/certFunctions.sh create mode 100644 unattended_installer/cert_tool/certMain.sh create mode 100644 unattended_installer/cert_tool/certVariables.sh create mode 100644 unattended_installer/common_functions/common.sh create mode 100644 unattended_installer/common_functions/commonVariables.sh create mode 100644 unattended_installer/config/certificate/config.yml create mode 100644 unattended_installer/config/certificate/config_aio.yml create mode 100644 unattended_installer/config/dashboard/dashboard.yml create mode 100644 unattended_installer/config/dashboard/dashboard_all_in_one.yml create mode 100644 unattended_installer/config/dashboard/dashboard_unattended.yml create mode 100644 unattended_installer/config/dashboard/dashboard_unattended_distributed.yml create mode 100644 unattended_installer/config/filebeat/filebeat.yml create mode 100644 unattended_installer/config/filebeat/filebeat_all_in_one.yml create mode 100644 unattended_installer/config/filebeat/filebeat_distributed.yml create mode 100644 unattended_installer/config/filebeat/filebeat_elastic_cluster.yml create mode 100644 unattended_installer/config/filebeat/filebeat_unattended.yml create mode 100644 unattended_installer/config/indexer/indexer.yml create mode 100644 unattended_installer/config/indexer/indexer_all_in_one.yml create mode 100644 unattended_installer/config/indexer/indexer_unattended_distributed.yml create mode 100644 unattended_installer/config/indexer/roles/internal_users.yml create mode 100644 unattended_installer/config/indexer/roles/roles.yml create mode 100644 unattended_installer/config/indexer/roles/roles_mapping.yml create mode 100644 unattended_installer/install_functions/checks.sh create mode 100644 unattended_installer/install_functions/dashboard.sh create mode 100644 unattended_installer/install_functions/filebeat.sh create mode 100644 unattended_installer/install_functions/indexer.sh create mode 100644 unattended_installer/install_functions/installCommon.sh create mode 100755 unattended_installer/install_functions/installMain.sh create mode 100644 unattended_installer/install_functions/installVariables.sh create mode 100644 unattended_installer/install_functions/manager.sh create mode 100755 unattended_installer/install_functions/wazuh-offline-download.sh create mode 100644 unattended_installer/install_functions/wazuh-offline-installation.sh create mode 100644 unattended_installer/passwords_tool/passwordsFunctions.sh create mode 100644 unattended_installer/passwords_tool/passwordsMain.sh create mode 100644 unattended_installer/passwords_tool/passwordsVariables.sh diff --git a/unattended_installer/Development-guide.md b/unattended_installer/Development-guide.md new file mode 100644 index 0000000..aeab2a0 --- /dev/null +++ b/unattended_installer/Development-guide.md @@ -0,0 +1,46 @@ +Wazuh unattended installer - Development guide +======================================== + +[![Slack](https://img.shields.io/badge/slack-join-blue.svg)](https://wazuh.com/community/join-us-on-slack/) +[![Email](https://img.shields.io/badge/email-join-blue.svg)](https://groups.google.com/forum/#!forum/wazuh) +[![Documentation](https://img.shields.io/badge/docs-view-green.svg)](https://documentation.wazuh.com) +[![Documentation](https://img.shields.io/badge/web-view-green.svg)](https://wazuh.com) + +# Development guide + +In order to have homogenous developments, this document shows some rules to be taken into account when adding or modifying capabilities. These rules must be taken into account as much as possible. + +- Write a function with a single objective. +- Every function must have limited arguments, the less the better. +- The functions should be open for extension but closed for modifications. +- Use libraries (I.e `install_functions`) and load only the necessaries. +- Main functions will not depend on the functions themselves implementation. +- Use descriptive variable names and function names. Avoid mind-mapping, a clean code is itself commented. Use comments only in necessary cases. +- Use Read-only to declare static variables. +- Use `$(command)` instead of classic `` `command` ``. +- Use `${var}` instead of `$(var)`. +- Variables should always be quoted: `"${var}"`. +- Use logger function instead of `echo`. +- Prevent commands from failure by catching the result of a command with `$?`. +- Take control of every possible long command setting up timeouts. +- Every needed resource must be obtained (on-line and off-line). This resource must be checked if exist in the desired path (libraries). +- Use `command -v` for commands exist checking. +- Parametrize all packages versions. +- Use `| grep -q` instead of `| grep` +- Use standard `$((..))` instead of old `$[]` + +*Additional check*: Run unit [tests](/tests/unattended/unit/README) before preparing a pull request. + +## License and copyright + +Copyright (C) 2015, Wazuh Inc. + +This program is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public +License (version 2) as published by the FSF - Free Software +Foundation. + +## Useful links and acknowledgment + +- [Bash meets solid](https://codewizardly.com/bash-meets-solid/) +- [Shellcheck](https://github.com/koalaman/shellcheck#gallery-of-bad-code) diff --git a/unattended_installer/builder.sh b/unattended_installer/builder.sh new file mode 100755 index 0000000..58087ae --- /dev/null +++ b/unattended_installer/builder.sh @@ -0,0 +1,332 @@ +#!/bin/bash + +# Tool to create wazuh-install.sh, wazuh-cert-tool.sh +# and wazuh-passwords-tool.sh +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +readonly base_path_builder="$(dirname "$(readlink -f "$0")")" +readonly resources_installer="${base_path_builder}/install_functions" +readonly resources_config="${base_path_builder}/config" +readonly resources_certs="${base_path_builder}/cert_tool" +readonly resources_passwords="${base_path_builder}/passwords_tool" +readonly resources_common="${base_path_builder}/common_functions" +readonly resources_download="${base_path_builder}/downloader" +source_branch="4.10.0" + +function getHelp() { + + echo -e "" + echo -e "NAME" + echo -e " $(basename "$0") - Build unattended installation files." + echo -e "" + echo -e "SYNOPSIS" + echo -e " $(basename "$0") [-v] -i | -c | -p" + echo -e "" + echo -e "DESCRIPTION" + echo -e " -i, --installer" + echo -e " Builds the unattended installer single file wazuh-install.sh" + echo -e "" + echo -e " -c, --cert-tool" + echo -e " Builds the certificate creation tool wazuh-cert-tool.sh" + echo -e "" + echo -e " -d [pre-release|staging], --development" + echo -e " Use development repositories. By default it uses the pre-release package repository. If staging is specified, it will use that repository." + echo -e "" + echo -e " -p, --password-tool" + echo -e " Builds the password creation and modification tool wazuh-password-tool.sh" + echo -e "" + echo -e " -h, --help" + echo -e " Shows help." + exit 1 + +} + +function buildInstaller() { + + checkDistDetectURL + + output_script_path="${base_path_builder}/wazuh-install.sh" + + ## Create installer script + echo -n > "${output_script_path}" + + ## License + echo "#!/bin/bash + +# Wazuh installer +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation." >> "${output_script_path}" + echo >> "${output_script_path}" + + ## Installation variables + if [ -n "${development}" ]; then + echo 'readonly development=1' >> "${output_script_path}" + echo 'readonly repogpg="https://packages-dev.wazuh.com/key/GPG-KEY-WAZUH"' >> "${output_script_path}" + echo 'readonly repobaseurl="https://packages-dev.wazuh.com/'${devrepo}'"' >> "${output_script_path}" + echo 'readonly reporelease="unstable"' >> "${output_script_path}" + echo 'readonly filebeat_wazuh_module="${repobaseurl}/filebeat/wazuh-filebeat-0.4.tar.gz"' >> "${output_script_path}" + echo 'readonly bucket="packages-dev.wazuh.com"' >> "${output_script_path}" + echo 'readonly repository="'"${devrepo}"'"' >> "${output_script_path}" + sed -i 's|v${wazuh_version}|${wazuh_version}|g' "${resources_installer}/installVariables.sh" + else + echo 'readonly repogpg="https://packages.wazuh.com/key/GPG-KEY-WAZUH"' >> "${output_script_path}" + echo 'readonly repobaseurl="https://packages.wazuh.com/4.x"' >> "${output_script_path}" + echo 'readonly reporelease="stable"' >> "${output_script_path}" + echo 'readonly filebeat_wazuh_module="${repobaseurl}/filebeat/wazuh-filebeat-0.4.tar.gz"' >> "${output_script_path}" + echo 'readonly bucket="packages.wazuh.com"' >> "${output_script_path}" + echo 'readonly repository="4.x"' >> "${output_script_path}" + fi + echo >> "${output_script_path}" + grep -Ev '^#|^\s*$' ${resources_common}/commonVariables.sh >> "${output_script_path}" + grep -Ev '^#|^\s*$' ${resources_installer}/installVariables.sh >> "${output_script_path}" + echo >> "${output_script_path}" + + ## Configuration files as variables + configuration_files=($(find "${resources_config}" -type f)) + config_file_name=($(eval "echo "${configuration_files[@]}" | sed 's|${resources_config}||g;s|/|_|g;s|.yml||g'")) + for index in "${!config_file_name[@]}"; do + echo "config_file${config_file_name[$index]}=\"$(cat "${configuration_files[$index]}" | sed 's|\"|\\\"|g;s|\$|\\\$|g')\"" >> "${output_script_path}" + echo >> "${output_script_path}" + done + + ## Sigint trap + echo "trap installCommon_cleanExit SIGINT" >> "${output_script_path}" + + ## JAVA_HOME + echo "export JAVA_HOME=\"/usr/share/wazuh-indexer/jdk/\"" >> "${output_script_path}" + + ## Functions for all install function modules + install_modules=($(find "${resources_installer}" -type f)) + install_modules_names=($(eval "echo \"${install_modules[*]}\" | sed 's,${resources_installer}/,,g'")) + for i in "${!install_modules[@]}"; do + if [ "${install_modules_names[$i]}" != "installVariables.sh" ]; then + echo "# ------------ ${install_modules_names[$i]} ------------ " >> "${output_script_path}" + sed -n '/^function [a-zA-Z_]\(\)/,/^}/p' ${install_modules[$i]} >> "${output_script_path}" + echo >> "${output_script_path}" + fi + done + + ## dist-detect.sh + echo "function dist_detect() {" >> "${output_script_path}" + curl -s "https://raw.githubusercontent.com/wazuh/wazuh/${source_branch}/src/init/dist-detect.sh" | sed '/^#/d' >> "${output_script_path}" + echo "}" >> "${output_script_path}" + + ## Common functions + sed -n '/^function [a-zA-Z_]\(\)/,/^}/p' "${resources_common}/common.sh" >> "${output_script_path}" + + ## Certificate tool library functions + sed -n '/^function [a-zA-Z_]\(\)/,/^}/p' "${resources_certs}/certFunctions.sh" >> "${output_script_path}" + + ## Passwords tool library functions + sed -n '/^function [a-zA-Z_]\(\)/,/^}/p' "${resources_passwords}/passwordsFunctions.sh" >> "${output_script_path}" + + ## Main function and call to it + echo >> "${output_script_path}" + echo "main \"\$@\"" >> "${output_script_path}" + + checkFilebeatURL + +} + +function buildPasswordsTool() { + output_script_path="${base_path_builder}/wazuh-passwords-tool.sh" + + ## Create installer script + echo -n > "${output_script_path}" + + ## License + echo "#!/bin/bash + +# Wazuh installer +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation." >> "${output_script_path}" + + ## Common and Passwords tool variables + grep -Ev '^#|^\s*$' ${resources_common}/commonVariables.sh >> "${output_script_path}" + grep -Ev '^#|^\s*$' "${resources_passwords}/passwordsVariables.sh" >> "${output_script_path}" + echo >> "${output_script_path}" + + ## Functions for all password function modules + passwords_modules=($(find "${resources_passwords}" -type f)) + passwords_modules_names=($(eval "echo "${passwords_modules[@]}" | sed 's,${resources_passwords}/,,g'")) + for i in "${!passwords_modules[@]}"; do + if [ "${passwords_modules[$i]}" != "passwordsVariables.sh" ]; then + echo "# ------------ ${passwords_modules_names[$i]} ------------ " >> "${output_script_path}" + sed -n '/^function [a-zA-Z_]\(\)/,/^}/p' "${passwords_modules[$i]}" >> "${output_script_path}" + echo >> "${output_script_path}" + fi + done + + ## Common functions + sed -n '/^function [a-zA-Z_]\(\)/,/^}/p' "${resources_common}/common.sh" >> "${output_script_path}" + + ## Call to main function + echo >> "${output_script_path}" + echo "main \"\$@\"" >> "${output_script_path}" +} + +function buildCertsTool() { + output_script_path="${base_path_builder}/wazuh-certs-tool.sh" + + ## Create installer script + echo -n > "${output_script_path}" + + ## License + echo "#!/bin/bash + +# Wazuh installer +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation." >> "${output_script_path}" + + ## Common and Certs tool variables + grep -Ev '^#|^\s*$' ${resources_common}/commonVariables.sh >> "${output_script_path}" + grep -Ev '^#|^\s*$' "${resources_certs}/certVariables.sh" >> "${output_script_path}" + echo >> "${output_script_path}" + + ## Functions for all certs tool function modules + certs_modules=($(find "${resources_certs}" -type f)) + certs_modules_names=($(eval "echo "${certs_modules[@]}" | sed 's,${resources_certs}/,,g'")) + for i in "${!certs_modules[@]}"; do + if [ "${certs_modules[$i]}" != "certVariables.sh" ]; then + echo "# ------------ ${certs_modules_names[$i]} ------------ " >> "${output_script_path}" + sed -n '/^function [a-zA-Z_]\(\)/,/^}/p' "${certs_modules[$i]}" >> "${output_script_path}" + echo >> "${output_script_path}" + fi + done + + ## Common functions + sed -n '/^function [a-zA-Z_]\(\)/,/^}/p' "${resources_common}/common.sh" >> "${output_script_path}" + + ## Call to main function + echo >> "${output_script_path}" + echo "main \"\$@\"" >> "${output_script_path}" + +} + +function builder_main() { + + umask 066 + + while [ -n "${1}" ] + do + case "${1}" in + "-i"|"--installer") + installer=1 + shift 1 + ;; + "-c"|"--cert-tool") + certTool=1 + shift 1 + ;; + "-d"|"--development") + development=1 + if [ -n "${2}" ] && [ "${2}" = "staging" ]; then + devrepo="staging" + shift 2 + elif [ -n "${2}" ] && [ "${2}" = "pre-release" ]; then + devrepo="pre-release" + shift 2 + else + devrepo="pre-release" + shift 1 + fi + ;; + "-p"|"--password-tool") + passwordsTool=1 + shift 1 + ;; + "-h"|"--help") + getHelp + ;; + *) + echo "Unknow option: \"${1}\"" + getHelp + esac + done + + if [ -n "${installer}" ]; then + buildInstaller + chmod 500 ${output_script_path} + if [ -n "${change_filebeat_url}" ]; then + sed -i -E "s|(https.+)master(.+wazuh-template.json)|\1\\$\\{source_branch\\}\2|" "${resources_installer}/installVariables.sh" + fi + if [ -n "${development}" ]; then + sed -i 's|${wazuh_version}|v${wazuh_version}|g' "${resources_installer}/installVariables.sh" + fi + fi + + if [ -n "${passwordsTool}" ]; then + buildPasswordsTool + chmod 500 ${output_script_path} + fi + + if [ -n "${certTool}" ]; then + buildCertsTool + chmod 644 ${output_script_path} + fi +} + +function checkDistDetectURL() { + + urls=("https://raw.githubusercontent.com/wazuh/wazuh/${source_branch}/src/init/dist-detect.sh" + "https://raw.githubusercontent.com/wazuh/wazuh/v${source_branch}/src/init/dist-detect.sh" + "https://raw.githubusercontent.com/wazuh/wazuh/master/src/init/dist-detect.sh") + + for url in "${urls[@]}"; do + eval "curl -s -o /dev/null '${url}' --retry 5 --retry-delay 5 --max-time 300 --fail" + e_code="${PIPESTATUS[0]}" + + if [ "${e_code}" -eq 0 ]; then + source_branch=$(echo "${url}" | awk -F'/' '{print $(NF-3)}') + break + fi + done + + if [ "${e_code}" -ne 0 ]; then + echo -e "Error: Could not get the dist-detect file." + exit 1 + fi + +} + +function checkFilebeatURL() { + + # Import variables + eval "$(grep -E "filebeat_wazuh_template=" "${resources_installer}/installVariables.sh")" + new_filebeat_url="https://raw.githubusercontent.com/wazuh/wazuh/master/extensions/elasticsearch/7.x/wazuh-template.json" + + # Get the response of the URL and check it + response=$(curl -I --write-out '%{http_code}' --silent --output /dev/null $filebeat_wazuh_template) + if [ "${response}" != "200" ]; then + response=$(curl -I --write-out '%{http_code}' --silent --output /dev/null $new_filebeat_url) + + # Display error if both URLs do not get the resource + if [ "${response}" != "200" ]; then + echo -e "Error: Could not get the Filebeat Wazuh template. " + # If matches, replace the variable of installVariables to the new one + else + echo -e "Changing Filebeat URL..." + sed -i -E "s|filebeat_wazuh_template=.*|filebeat_wazuh_template=\"${new_filebeat_url}\"|g" "${resources_installer}/installVariables.sh" + change_filebeat_url=1 + fi + fi +} + +builder_main "$@" diff --git a/unattended_installer/cert_tool/certFunctions.sh b/unattended_installer/cert_tool/certFunctions.sh new file mode 100644 index 0000000..fc2bf51 --- /dev/null +++ b/unattended_installer/cert_tool/certFunctions.sh @@ -0,0 +1,469 @@ +# Certificate tool - Library functions +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + + +function cert_cleanFiles() { + + common_logger -d "Cleaning certificate files." + eval "rm -f ${cert_tmp_path}/*.csr ${debug}" + eval "rm -f ${cert_tmp_path}/*.srl ${debug}" + eval "rm -f ${cert_tmp_path}/*.conf ${debug}" + eval "rm -f ${cert_tmp_path}/admin-key-temp.pem ${debug}" + +} + +function cert_checkOpenSSL() { + + common_logger -d "Checking if OpenSSL is installed." + + if [ -z "$(command -v openssl)" ]; then + common_logger -e "OpenSSL not installed." + exit 1 + fi + +} + +function cert_checkRootCA() { + + common_logger -d "Checking if the root CA exists." + + if [[ -n ${rootca} || -n ${rootcakey} ]]; then + # Verify variables match keys + if [[ ${rootca} == *".key" ]]; then + ca_temp=${rootca} + rootca=${rootcakey} + rootcakey=${ca_temp} + fi + # Validate that files exist + if [[ -e ${rootca} ]]; then + eval "cp ${rootca} ${cert_tmp_path}/root-ca.pem ${debug}" + else + common_logger -e "The file ${rootca} does not exists" + cert_cleanFiles + exit 1 + fi + if [[ -e ${rootcakey} ]]; then + eval "cp ${rootcakey} ${cert_tmp_path}/root-ca.key ${debug}" + else + common_logger -e "The file ${rootcakey} does not exists" + cert_cleanFiles + exit 1 + fi + else + cert_generateRootCAcertificate + fi + +} + +# Executes and analyze the output of the command. It prints the output +# in case of an error +function cert_executeAndValidate() { + + command_output=$(eval "$@" 2>&1) + e_code="${PIPESTATUS[0]}" + + if [ "${e_code}" -ne 0 ]; then + common_logger -e "Error generating the certificates." + common_logger -d "Error executing command: $@" + common_logger -d "Error output: ${command_output}" + cert_cleanFiles + exit 1 + fi + +} + +function cert_generateAdmincertificate() { + + common_logger "Generating Admin certificates." + common_logger -d "Generating Admin private key." + cert_executeAndValidate "openssl genrsa -out ${cert_tmp_path}/admin-key-temp.pem 2048" + common_logger -d "Converting Admin private key to PKCS8 format." + cert_executeAndValidate "openssl pkcs8 -inform PEM -outform PEM -in ${cert_tmp_path}/admin-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out ${cert_tmp_path}/admin-key.pem" + common_logger -d "Generating Admin CSR." + cert_executeAndValidate "openssl req -new -key ${cert_tmp_path}/admin-key.pem -out ${cert_tmp_path}/admin.csr -batch -subj '/C=US/L=California/O=Wazuh/OU=Wazuh/CN=admin'" + common_logger -d "Creating Admin certificate." + cert_executeAndValidate "openssl x509 -days 3650 -req -in ${cert_tmp_path}/admin.csr -CA ${cert_tmp_path}/root-ca.pem -CAkey ${cert_tmp_path}/root-ca.key -CAcreateserial -sha256 -out ${cert_tmp_path}/admin.pem" + +} + +function cert_generateCertificateconfiguration() { + + common_logger -d "Generating certificate configuration." + cat > "${cert_tmp_path}/${1}.conf" <<- EOF + [ req ] + prompt = no + default_bits = 2048 + default_md = sha256 + distinguished_name = req_distinguished_name + x509_extensions = v3_req + + [req_distinguished_name] + C = US + L = California + O = Wazuh + OU = Wazuh + CN = cname + + [ v3_req ] + authorityKeyIdentifier=keyid,issuer + basicConstraints = CA:FALSE + keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment + subjectAltName = @alt_names + + [alt_names] + IP.1 = cip + EOF + + + conf="$(awk '{sub("CN = cname", "CN = '"${1}"'")}1' "${cert_tmp_path}/${1}.conf")" + echo "${conf}" > "${cert_tmp_path}/${1}.conf" + + if [ "${#@}" -gt 1 ]; then + sed -i '/IP.1/d' "${cert_tmp_path}/${1}.conf" + for (( i=2; i<=${#@}; i++ )); do + isIP=$(echo "${!i}" | grep -P "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$") + isDNS=$(echo "${!i}" | grep -P "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])\.([A-Za-z]{2,})$" ) j=$((i-1)) + if [ "${isIP}" ]; then + printf '%s\n' " IP.${j} = ${!i}" >> "${cert_tmp_path}/${1}.conf" + elif [ "${isDNS}" ]; then + printf '%s\n' " DNS.${j} = ${!i}" >> "${cert_tmp_path}/${1}.conf" + else + common_logger -e "Invalid IP or DNS ${!i}" + exit 1 + fi + done + else + common_logger -e "No IP or DNS specified" + exit 1 + fi + +} + +function cert_generateIndexercertificates() { + + if [ ${#indexer_node_names[@]} -gt 0 ]; then + common_logger "Generating Wazuh indexer certificates." + + for i in "${!indexer_node_names[@]}"; do + indexer_node_name=${indexer_node_names[$i]} + common_logger -d "Creating the certificates for ${indexer_node_name} indexer node." + cert_generateCertificateconfiguration "${indexer_node_name}" "${indexer_node_ips[i]}" + common_logger -d "Creating the Wazuh indexer tmp key pair." + cert_executeAndValidate "openssl req -new -nodes -newkey rsa:2048 -keyout ${cert_tmp_path}/${indexer_node_name}-key.pem -out ${cert_tmp_path}/${indexer_node_name}.csr -config ${cert_tmp_path}/${indexer_node_name}.conf" + common_logger -d "Creating the Wazuh indexer certificates." + cert_executeAndValidate "openssl x509 -req -in ${cert_tmp_path}/${indexer_node_name}.csr -CA ${cert_tmp_path}/root-ca.pem -CAkey ${cert_tmp_path}/root-ca.key -CAcreateserial -out ${cert_tmp_path}/${indexer_node_name}.pem -extfile ${cert_tmp_path}/${indexer_node_name}.conf -extensions v3_req -days 3650" + done + else + return 1 + fi + +} + +function cert_generateFilebeatcertificates() { + + if [ ${#server_node_names[@]} -gt 0 ]; then + common_logger "Generating Filebeat certificates." + + for i in "${!server_node_names[@]}"; do + server_name="${server_node_names[i]}" + common_logger -d "Generating the certificates for ${server_name} server node." + j=$((i+1)) + declare -a server_ips=(server_node_ip_"$j"[@]) + cert_generateCertificateconfiguration "${server_name}" "${!server_ips}" + common_logger -d "Creating the Wazuh server tmp key pair." + cert_executeAndValidate "openssl req -new -nodes -newkey rsa:2048 -keyout ${cert_tmp_path}/${server_name}-key.pem -out ${cert_tmp_path}/${server_name}.csr -config ${cert_tmp_path}/${server_name}.conf" + common_logger -d "Creating the Wazuh server certificates." + cert_executeAndValidate "openssl x509 -req -in ${cert_tmp_path}/${server_name}.csr -CA ${cert_tmp_path}/root-ca.pem -CAkey ${cert_tmp_path}/root-ca.key -CAcreateserial -out ${cert_tmp_path}/${server_name}.pem -extfile ${cert_tmp_path}/${server_name}.conf -extensions v3_req -days 3650" + done + else + return 1 + fi + +} + +function cert_generateDashboardcertificates() { + if [ ${#dashboard_node_names[@]} -gt 0 ]; then + common_logger "Generating Wazuh dashboard certificates." + + for i in "${!dashboard_node_names[@]}"; do + dashboard_node_name="${dashboard_node_names[i]}" + cert_generateCertificateconfiguration "${dashboard_node_name}" "${dashboard_node_ips[i]}" + common_logger -d "Creating the Wazuh dashboard tmp key pair." + cert_executeAndValidate "openssl req -new -nodes -newkey rsa:2048 -keyout ${cert_tmp_path}/${dashboard_node_name}-key.pem -out ${cert_tmp_path}/${dashboard_node_name}.csr -config ${cert_tmp_path}/${dashboard_node_name}.conf" + common_logger -d "Creating the Wazuh dashboard certificates." + cert_executeAndValidate "openssl x509 -req -in ${cert_tmp_path}/${dashboard_node_name}.csr -CA ${cert_tmp_path}/root-ca.pem -CAkey ${cert_tmp_path}/root-ca.key -CAcreateserial -out ${cert_tmp_path}/${dashboard_node_name}.pem -extfile ${cert_tmp_path}/${dashboard_node_name}.conf -extensions v3_req -days 3650" + done + else + return 1 + fi + +} + +function cert_generateRootCAcertificate() { + + common_logger "Generating the root certificate." + cert_executeAndValidate "openssl req -x509 -new -nodes -newkey rsa:2048 -keyout ${cert_tmp_path}/root-ca.key -out ${cert_tmp_path}/root-ca.pem -batch -subj '/OU=Wazuh/O=Wazuh/L=California/' -days 3650" + +} + +function cert_parseYaml() { + + local prefix=$2 + local separator=${3:-_} + local indexfix + # Detect awk flavor + if awk --version 2>&1 | grep -q "GNU Awk" ; then + # GNU Awk detected + indexfix=-1 + elif awk -Wv 2>&1 | grep -q "mawk" ; then + # mawk detected + indexfix=0 + fi + + local s='[[:space:]]*' sm='[ \t]*' w='[a-zA-Z0-9_]*' fs=${fs:-$(echo @|tr @ '\034')} i=${i:- } + cat $1 2>/dev/null | \ + awk -F$fs "{multi=0; + if(match(\$0,/$sm\|$sm$/)){multi=1; sub(/$sm\|$sm$/,\"\");} + if(match(\$0,/$sm>$sm$/)){multi=2; sub(/$sm>$sm$/,\"\");} + while(multi>0){ + str=\$0; gsub(/^$sm/,\"\", str); + indent=index(\$0,str); + indentstr=substr(\$0, 0, indent+$indexfix) \"$i\"; + obuf=\$0; + getline; + while(index(\$0,indentstr)){ + obuf=obuf substr(\$0, length(indentstr)+1); + if (multi==1){obuf=obuf \"\\\\n\";} + if (multi==2){ + if(match(\$0,/^$sm$/)) + obuf=obuf \"\\\\n\"; + else obuf=obuf \" \"; + } + getline; + } + sub(/$sm$/,\"\",obuf); + print obuf; + multi=0; + if(match(\$0,/$sm\|$sm$/)){multi=1; sub(/$sm\|$sm$/,\"\");} + if(match(\$0,/$sm>$sm$/)){multi=2; sub(/$sm>$sm$/,\"\");} + } + print}" | \ + sed -e "s|^\($s\)?|\1-|" \ + -ne "s|^$s#.*||;s|$s#[^\"']*$||;s|^\([^\"'#]*\)#.*|\1|;t1;t;:1;s|^$s\$||;t2;p;:2;d" | \ + sed -ne "s|,$s\]$s\$|]|" \ + -e ":1;s|^\($s\)\($w\)$s:$s\(&$w\)\?$s\[$s\(.*\)$s,$s\(.*\)$s\]|\1\2: \3[\4]\n\1$i- \5|;t1" \ + -e "s|^\($s\)\($w\)$s:$s\(&$w\)\?$s\[$s\(.*\)$s\]|\1\2: \3\n\1$i- \4|;" \ + -e ":2;s|^\($s\)-$s\[$s\(.*\)$s,$s\(.*\)$s\]|\1- [\2]\n\1$i- \3|;t2" \ + -e "s|^\($s\)-$s\[$s\(.*\)$s\]|\1-\n\1$i- \2|;p" | \ + sed -ne "s|,$s}$s\$|}|" \ + -e ":1;s|^\($s\)-$s{$s\(.*\)$s,$s\($w\)$s:$s\(.*\)$s}|\1- {\2}\n\1$i\3: \4|;t1" \ + -e "s|^\($s\)-$s{$s\(.*\)$s}|\1-\n\1$i\2|;" \ + -e ":2;s|^\($s\)\($w\)$s:$s\(&$w\)\?$s{$s\(.*\)$s,$s\($w\)$s:$s\(.*\)$s}|\1\2: \3 {\4}\n\1$i\5: \6|;t2" \ + -e "s|^\($s\)\($w\)$s:$s\(&$w\)\?$s{$s\(.*\)$s}|\1\2: \3\n\1$i\4|;p" | \ + sed -e "s|^\($s\)\($w\)$s:$s\(&$w\)\(.*\)|\1\2:\4\n\3|" \ + -e "s|^\($s\)-$s\(&$w\)\(.*\)|\1- \3\n\2|" | \ + sed -ne "s|^\($s\):|\1|" \ + -e "s|^\($s\)\(---\)\($s\)||" \ + -e "s|^\($s\)\(\.\.\.\)\($s\)||" \ + -e "s|^\($s\)-$s[\"']\(.*\)[\"']$s\$|\1$fs$fs\2|p;t" \ + -e "s|^\($s\)\($w\)$s:$s[\"']\(.*\)[\"']$s\$|\1$fs\2$fs\3|p;t" \ + -e "s|^\($s\)-$s\(.*\)$s\$|\1$fs$fs\2|" \ + -e "s|^\($s\)\($w\)$s:$s[\"']\?\(.*\)$s\$|\1$fs\2$fs\3|" \ + -e "s|^\($s\)[\"']\?\([^&][^$fs]\+\)[\"']$s\$|\1$fs$fs$fs\2|" \ + -e "s|^\($s\)[\"']\?\([^&][^$fs]\+\)$s\$|\1$fs$fs$fs\2|" \ + -e "s|$s\$||p" | \ + awk -F$fs "{ + gsub(/\t/,\" \",\$1); + gsub(\"name: \", \"\"); + if(NF>3){if(value!=\"\"){value = value \" \";}value = value \$4;} + else { + if(match(\$1,/^&/)){anchor[substr(\$1,2)]=full_vn;getline}; + indent = length(\$1)/length(\"$i\"); + vname[indent] = \$2; + value= \$3; + for (i in vname) {if (i > indent) {delete vname[i]; idx[i]=0}} + if(length(\$2)== 0){ vname[indent]= ++idx[indent] }; + vn=\"\"; for (i=0; i0)&&index(val, ref)==1){ + tmpval=assignment[val]; + sub(ref,full_vn,val); + if(match(val,\"$separator\$\")){ + gsub(ref,full_vn,tmpval); + } else if (length(tmpval) > 0) { + printf(\"%s=\\\"%s\\\"\n\", val, tmpval); + } + assignment[val]=tmpval; + } + } + } + } else if (length(value) > 0) { + printf(\"%s=\\\"%s\\\"\n\", full_vn, value); + } + }END{ + for(val in assignment){ + if(match(val,\"$separator\$\")) + printf(\"%s=\\\"%s\\\"\n\", val, assignment[val]); + } + }" + +} + +function cert_checkPrivateIp() { + + local ip=$1 + common_logger -d "Checking if ${ip} is private." + + # Check private IPv4 ranges + if [[ $ip =~ ^10\.|^192\.168\.|^172\.(1[6-9]|2[0-9]|3[0-1])\.|^(127\.) ]]; then + return 0 + fi + + # Check private IPv6 ranges (fc00::/7 prefix) + if [[ $ip =~ ^fc ]]; then + return 0 + fi + + return 1 + +} + +function cert_readConfig() { + + common_logger -d "Reading configuration file." + + if [ -f "${config_file}" ]; then + if [ ! -s "${config_file}" ]; then + common_logger -e "File ${config_file} is empty" + exit 1 + fi + eval "$(cert_convertCRLFtoLF "${config_file}")" + + eval "indexer_node_names=( $(cert_parseYaml "${config_file}" | grep -E "nodes[_]+indexer[_]+[0-9]+=" | cut -d = -f 2 ) )" + eval "server_node_names=( $(cert_parseYaml "${config_file}" | grep -E "nodes[_]+server[_]+[0-9]+=" | cut -d = -f 2 ) )" + eval "dashboard_node_names=( $(cert_parseYaml "${config_file}" | grep -E "nodes[_]+dashboard[_]+[0-9]+=" | cut -d = -f 2) )" + eval "indexer_node_ips=( $(cert_parseYaml "${config_file}" | grep -E "nodes[_]+indexer[_]+[0-9]+[_]+ip=" | cut -d = -f 2) )" + eval "server_node_ips=( $(cert_parseYaml "${config_file}" | grep -E "nodes[_]+server[_]+[0-9]+[_]+ip=" | cut -d = -f 2) )" + eval "dashboard_node_ips=( $(cert_parseYaml "${config_file}" | grep -E "nodes[_]+dashboard[_]+[0-9]+[_]+ip=" | cut -d = -f 2 ) )" + eval "server_node_types=( $(cert_parseYaml "${config_file}" | grep -E "nodes[_]+server[_]+[0-9]+[_]+node_type=" | cut -d = -f 2 ) )" + eval "number_server_ips=( $(cert_parseYaml "${config_file}" | grep -o -E 'nodes[_]+server[_]+[0-9]+[_]+ip' | sort -u | wc -l) )" + all_ips=("${indexer_node_ips[@]}" "${server_node_ips[@]}" "${dashboard_node_ips[@]}") + + for ip in "${all_ips[@]}"; do + isIP=$(echo "${ip}" | grep -P "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$") + if [[ -n "${isIP}" ]]; then + if ! cert_checkPrivateIp "$ip"; then + common_logger -e "The IP ${ip} is public." + exit 1 + fi + fi + done + + for i in $(seq 1 "${number_server_ips}"); do + nodes_server="nodes[_]+server[_]+${i}[_]+ip" + eval "server_node_ip_$i=( $( cert_parseYaml "${config_file}" | grep -E "${nodes_server}" | sed '/\./!d' | cut -d = -f 2 | sed -r 's/\s+//g') )" + done + + unique_names=($(echo "${indexer_node_names[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')) + if [ "${#unique_names[@]}" -ne "${#indexer_node_names[@]}" ]; then + common_logger -e "Duplicated indexer node names." + exit 1 + fi + + unique_ips=($(echo "${indexer_node_ips[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')) + if [ "${#unique_ips[@]}" -ne "${#indexer_node_ips[@]}" ]; then + common_logger -e "Duplicated indexer node ips." + exit 1 + fi + + unique_names=($(echo "${server_node_names[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')) + if [ "${#unique_names[@]}" -ne "${#server_node_names[@]}" ]; then + common_logger -e "Duplicated Wazuh server node names." + exit 1 + fi + + unique_ips=($(echo "${server_node_ips[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')) + if [ "${#unique_ips[@]}" -ne "${#server_node_ips[@]}" ]; then + common_logger -e "Duplicated Wazuh server node ips." + exit 1 + fi + + unique_names=($(echo "${dashboard_node_names[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')) + if [ "${#unique_names[@]}" -ne "${#dashboard_node_names[@]}" ]; then + common_logger -e "Duplicated dashboard node names." + exit 1 + fi + + unique_ips=($(echo "${dashboard_node_ips[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')) + if [ "${#unique_ips[@]}" -ne "${#dashboard_node_ips[@]}" ]; then + common_logger -e "Duplicated dashboard node ips." + exit 1 + fi + + for i in "${server_node_types[@]}"; do + if ! echo "$i" | grep -ioq master && ! echo "$i" | grep -ioq worker; then + common_logger -e "Incorrect node_type $i must be master or worker" + exit 1 + fi + done + + if [ "${#server_node_names[@]}" -le 1 ]; then + if [ "${#server_node_types[@]}" -ne 0 ]; then + common_logger -e "The tag node_type can only be used with more than one Wazuh server." + exit 1 + fi + elif [ "${#server_node_names[@]}" -gt "${#server_node_types[@]}" ]; then + common_logger -e "The tag node_type needs to be specified for all Wazuh server nodes." + exit 1 + elif [ "${#server_node_names[@]}" -lt "${#server_node_types[@]}" ]; then + common_logger -e "Found extra node_type tags." + exit 1 + elif [ "$(grep -io master <<< "${server_node_types[*]}" | wc -l)" -ne 1 ]; then + common_logger -e "Wazuh cluster needs a single master node." + exit 1 + elif [ "$(grep -io worker <<< "${server_node_types[*]}" | wc -l)" -ne $(( ${#server_node_types[@]} - 1 )) ]; then + common_logger -e "Incorrect number of workers." + exit 1 + fi + + if [ "${#dashboard_node_names[@]}" -ne "${#dashboard_node_ips[@]}" ]; then + common_logger -e "Different number of dashboard node names and IPs." + exit 1 + fi + + else + common_logger -e "No configuration file found." + exit 1 + fi + +} + +function cert_setpermisions() { + eval "chmod -R 744 ${cert_tmp_path} ${debug}" +} + +function cert_convertCRLFtoLF() { + if [[ ! -d "/tmp/wazuh-install-files" ]]; then + eval "mkdir /tmp/wazuh-install-files ${debug}" + fi + eval "chmod -R 755 /tmp/wazuh-install-files ${debug}" + eval "tr -d '\015' < $1 > /tmp/wazuh-install-files/new_config.yml" + eval "mv /tmp/wazuh-install-files/new_config.yml $1 ${debug}" +} diff --git a/unattended_installer/cert_tool/certMain.sh b/unattended_installer/cert_tool/certMain.sh new file mode 100644 index 0000000..64ba285 --- /dev/null +++ b/unattended_installer/cert_tool/certMain.sh @@ -0,0 +1,261 @@ +# Certificate tool - Main functions +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +function getHelp() { + + echo -e "" + echo -e "NAME" + echo -e " wazuh-cert-tool.sh - Manages the creation of certificates of the Wazuh components." + echo -e "" + echo -e "SYNOPSIS" + echo -e " wazuh-cert-tool.sh [OPTIONS]" + echo -e "" + echo -e "DESCRIPTION" + echo -e " -a, --admin-certificates " + echo -e " Creates the admin certificates, add root-ca.pem and root-ca.key." + echo -e "" + echo -e " -A, --all " + echo -e " Creates certificates specified in config.yml and admin certificates. Add a root-ca.pem and root-ca.key or leave it empty so a new one will be created." + echo -e "" + echo -e " -ca, --root-ca-certificates" + echo -e " Creates the root-ca certificates." + echo -e "" + echo -e " -v, --verbose" + echo -e " Enables verbose mode." + echo -e "" + echo -e " -wd, --wazuh-dashboard-certificates " + echo -e " Creates the Wazuh dashboard certificates, add root-ca.pem and root-ca.key." + echo -e "" + echo -e " -wi, --wazuh-indexer-certificates " + echo -e " Creates the Wazuh indexer certificates, add root-ca.pem and root-ca.key." + echo -e "" + echo -e " -ws, --wazuh-server-certificates " + echo -e " Creates the Wazuh server certificates, add root-ca.pem and root-ca.key." + echo -e "" + echo -e " -tmp, --cert_tmp_path " + echo -e " Modifies the default tmp directory (/tmp/wazuh-ceritificates) to the specified one." + echo -e " Must be used along with one of these options: -a, -A, -ca, -wi, -wd, -ws" + echo -e "" + + exit 1 + +} + +function main() { + + umask 177 + + cert_checkOpenSSL + + if [ -n "${1}" ]; then + while [ -n "${1}" ] + do + case "${1}" in + "-a"|"--admin-certificates") + if [[ -z "${2}" || -z "${3}" ]]; then + common_logger -e "Error on arguments. Probably missing after -a|--admin-certificates" + getHelp + exit 1 + else + cadmin=1 + rootca="${2}" + rootcakey="${3}" + shift 3 + fi + ;; + "-A"|"--all") + if [[ -n "${2}" && "${2}" != "-v" && "${2}" != "-tmp" ]]; then + # Validate that the user has entered the 2 files + if [[ -z ${3} ]]; then + if [[ ${2} == *".key" ]]; then + common_logger -e "You have not entered a root-ca.pem" + exit 1 + else + common_logger -e "You have not entered a root-ca.key" + exit 1 + fi + fi + all=1 + rootca="${2}" + rootcakey="${3}" + shift 3 + else + all=1 + shift 1 + fi + ;; + "-ca"|"--root-ca-certificate") + ca=1 + shift 1 + ;; + "-h"|"--help") + getHelp + ;; + "-v"|"--verbose") + debugEnabled=1 + shift 1 + ;; + "-wd"|"--wazuh-dashboard-certificates") + if [[ -z "${2}" || -z "${3}" ]]; then + common_logger -e "Error on arguments. Probably missing after -wd|--wazuh-dashboard-certificates" + getHelp + exit 1 + else + cdashboard=1 + rootca="${2}" + rootcakey="${3}" + shift 3 + fi + ;; + "-wi"|"--wazuh-indexer-certificates") + if [[ -z "${2}" || -z "${3}" ]]; then + common_logger -e "Error on arguments. Probably missing after -wi|--wazuh-indexer-certificates" + getHelp + exit 1 + else + cindexer=1 + rootca="${2}" + rootcakey="${3}" + shift 3 + fi + ;; + "-ws"|"--wazuh-server-certificates") + if [[ -z "${2}" || -z "${3}" ]]; then + common_logger -e "Error on arguments. Probably missing after -ws|--wazuh-server-certificates" + getHelp + exit 1 + else + cserver=1 + rootca="${2}" + rootcakey="${3}" + shift 3 + fi + ;; + "-tmp"|"--cert_tmp_path") + if [[ -n "${3}" || ( "${cadmin}" == 1 || "${all}" == 1 || "${ca}" == 1 || "${cdashboard}" == 1 || "${cindexer}" == 1 || "${cserver}" == 1 ) ]]; then + if [[ -z "${2}" || ! "${2}" == /* ]]; then + common_logger -e "Error on arguments. Probably missing or path does not start with '/'." + getHelp + exit 1 + else + cert_tmp_path="${2}" + shift 2 + fi + else + common_logger -e "Error: -tmp must be used along with one of these options: -a, -A, -ca, -wi, -wd, -ws" + getHelp + exit 1 + fi + ;; + *) + echo "Unknow option: ${1}" + getHelp + esac + done + + common_logger "Verbose logging redirected to ${logfile}" + + if [[ -d "${base_path}"/wazuh-certificates ]]; then + if [ -n "$(ls -A "${base_path}"/wazuh-certificates)" ]; then + common_logger -e "Directory wazuh-certificates already exists in the same path as the script. Please, remove the certs directory to create new certificates." + exit 1 + fi + fi + + if [[ ! -d "${cert_tmp_path}" ]]; then + mkdir -p "${cert_tmp_path}" + chmod 744 "${cert_tmp_path}" + fi + + cert_readConfig + + if [ -n "${debugEnabled}" ]; then + debug="2>&1 | tee -a ${logfile}" + fi + + if [[ -n "${cadmin}" ]]; then + cert_checkRootCA + cert_generateAdmincertificate + common_logger "Admin certificates created." + cert_cleanFiles + cert_setpermisions + eval "mv ${cert_tmp_path} ${base_path}/wazuh-certificates ${debug}" + fi + + if [[ -n "${all}" ]]; then + cert_checkRootCA + cert_generateAdmincertificate + common_logger "Admin certificates created." + if cert_generateIndexercertificates; then + common_logger "Wazuh indexer certificates created." + fi + if cert_generateFilebeatcertificates; then + common_logger "Wazuh Filebeat certificates created." + fi + if cert_generateDashboardcertificates; then + common_logger "Wazuh dashboard certificates created." + fi + cert_cleanFiles + cert_setpermisions + eval "mv ${cert_tmp_path} ${base_path}/wazuh-certificates ${debug}" + fi + + if [[ -n "${ca}" ]]; then + cert_generateRootCAcertificate + common_logger "Authority certificates created." + cert_cleanFiles + eval "mv ${cert_tmp_path} ${base_path}/wazuh-certificates ${debug}" + fi + + if [[ -n "${cindexer}" ]]; then + if [ ${#indexer_node_names[@]} -gt 0 ]; then + cert_checkRootCA + cert_generateIndexercertificates + common_logger "Wazuh indexer certificates created." + cert_cleanFiles + cert_setpermisions + eval "mv ${cert_tmp_path} ${base_path}/wazuh-certificates ${debug}" + else + common_logger -e "Indexer node not present in config.yml." + exit 1 + fi + fi + + if [[ -n "${cserver}" ]]; then + if [ ${#server_node_names[@]} -gt 0 ]; then + cert_checkRootCA + cert_generateFilebeatcertificates + common_logger "Wazuh Filebeat certificates created." + cert_cleanFiles + cert_setpermisions + eval "mv ${cert_tmp_path} ${base_path}/wazuh-certificates ${debug}" + else + common_logger -e "Server node not present in config.yml." + exit 1 + fi + fi + + if [[ -n "${cdashboard}" ]]; then + if [ ${#dashboard_node_names[@]} -gt 0 ]; then + cert_checkRootCA + cert_generateDashboardcertificates + common_logger "Wazuh dashboard certificates created." + cert_cleanFiles + cert_setpermisions + eval "mv ${cert_tmp_path} ${base_path}/wazuh-certificates ${debug}" + else + common_logger -e "Dashboard node not present in config.yml." + exit 1 + fi + fi + + else + getHelp + fi + +} \ No newline at end of file diff --git a/unattended_installer/cert_tool/certVariables.sh b/unattended_installer/cert_tool/certVariables.sh new file mode 100644 index 0000000..7d86d37 --- /dev/null +++ b/unattended_installer/cert_tool/certVariables.sh @@ -0,0 +1,14 @@ +# Certificate tool - Variables +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +readonly base_path="$(dirname "$(readlink -f "$0")")" +readonly config_file="${base_path}/config.yml" +readonly logfile="${base_path}/wazuh-certificates-tool.log" +cert_tmp_path="/tmp/wazuh-certificates" +debug=">> ${logfile} 2>&1" +readonly cert_tool_script_name=".*certs.*\.sh" \ No newline at end of file diff --git a/unattended_installer/common_functions/common.sh b/unattended_installer/common_functions/common.sh new file mode 100644 index 0000000..359624b --- /dev/null +++ b/unattended_installer/common_functions/common.sh @@ -0,0 +1,221 @@ +# Common functions for Wazuh installation assistant, +# wazuh-passwords-tool and wazuh-cert-tool +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +function common_checkAptLock() { + + attempt=0 + seconds=30 + max_attempts=10 + + while fuser "${apt_lockfile}" >/dev/null 2>&1 && [ "${attempt}" -lt "${max_attempts}" ]; do + attempt=$((attempt+1)) + common_logger "Another process is using APT. Waiting for it to release the lock. Next retry in ${seconds} seconds (${attempt}/${max_attempts})" + sleep "${seconds}" + done + +} + +function common_logger() { + + now=$(date +'%d/%m/%Y %H:%M:%S') + mtype="INFO:" + debugLogger= + nolog= + if [ -n "${1}" ]; then + while [ -n "${1}" ]; do + case ${1} in + "-e") + mtype="ERROR:" + shift 1 + ;; + "-w") + mtype="WARNING:" + shift 1 + ;; + "-d") + debugLogger=1 + mtype="DEBUG:" + shift 1 + ;; + "-nl") + nolog=1 + shift 1 + ;; + *) + message="${1}" + shift 1 + ;; + esac + done + fi + + if [ -z "${debugLogger}" ] || { [ -n "${debugLogger}" ] && [ -n "${debugEnabled}" ]; }; then + if [ -z "${nolog}" ] && { [ "$EUID" -eq 0 ] || [[ "$(basename "$0")" =~ $cert_tool_script_name ]]; }; then + printf "%s\n" "${now} ${mtype} ${message}" | tee -a ${logfile} + else + printf "%b\n" "${now} ${mtype} ${message}" + fi + fi + +} + +function common_checkRoot() { + + common_logger -d "Checking root permissions." + if [ "$EUID" -ne 0 ]; then + echo "This script must be run as root." + exit 1; + fi + + common_logger -d "Checking sudo package." + if ! command -v sudo > /dev/null; then + common_logger -e "The sudo package is not installed and it is necessary for the installation." + exit 1; + fi +} + +function common_checkInstalled() { + + common_logger -d "Checking Wazuh installation." + wazuh_installed="" + indexer_installed="" + filebeat_installed="" + dashboard_installed="" + + if [ "${sys_type}" == "yum" ]; then + eval "rpm -q wazuh-manager --quiet && wazuh_installed=1" + elif [ "${sys_type}" == "apt-get" ]; then + wazuh_installed=$(apt list --installed 2>/dev/null | grep wazuh-manager) + fi + + if [ -d "/var/ossec" ]; then + common_logger -d "There are Wazuh remaining files." + wazuh_remaining_files=1 + fi + + if [ "${sys_type}" == "yum" ]; then + eval "rpm -q wazuh-indexer --quiet && indexer_installed=1" + + elif [ "${sys_type}" == "apt-get" ]; then + indexer_installed=$(apt list --installed 2>/dev/null | grep wazuh-indexer) + fi + + if [ -d "/var/lib/wazuh-indexer/" ] || [ -d "/usr/share/wazuh-indexer" ] || [ -d "/etc/wazuh-indexer" ] || [ -f "${base_path}/search-guard-tlstool*" ]; then + common_logger -d "There are Wazuh indexer remaining files." + indexer_remaining_files=1 + fi + + if [ "${sys_type}" == "yum" ]; then + eval "rpm -q filebeat --quiet && filebeat_installed=1" + elif [ "${sys_type}" == "apt-get" ]; then + filebeat_installed=$(apt list --installed 2>/dev/null | grep filebeat) + fi + + if [ -d "/var/lib/filebeat/" ] || [ -d "/usr/share/filebeat" ] || [ -d "/etc/filebeat" ]; then + common_logger -d "There are Filebeat remaining files." + filebeat_remaining_files=1 + fi + + if [ "${sys_type}" == "yum" ]; then + eval "rpm -q wazuh-dashboard --quiet && dashboard_installed=1" + elif [ "${sys_type}" == "apt-get" ]; then + dashboard_installed=$(apt list --installed 2>/dev/null | grep wazuh-dashboard) + fi + + if [ -d "/var/lib/wazuh-dashboard/" ] || [ -d "/usr/share/wazuh-dashboard" ] || [ -d "/etc/wazuh-dashboard" ] || [ -d "/run/wazuh-dashboard/" ]; then + common_logger -d "There are Wazuh dashboard remaining files." + dashboard_remaining_files=1 + fi + +} + +function common_checkSystem() { + + if [ -n "$(command -v yum)" ]; then + sys_type="yum" + sep="-" + common_logger -d "YUM package manager will be used." + elif [ -n "$(command -v apt-get)" ]; then + sys_type="apt-get" + sep="=" + common_logger -d "APT package manager will be used." + else + common_logger -e "Couldn't find YUM or APT package manager. Try installing the one corresponding to your operating system and then, launch the installation assistant again." + exit 1 + fi + +} + +function common_checkWazuhConfigYaml() { + + common_logger -d "Checking Wazuh YAML configuration file." + filecorrect=$(cert_parseYaml "${config_file}" | grep -Ev '^#|^\s*$' | grep -Pzc "\A(\s*(nodes_indexer__name|nodes_indexer__ip|nodes_server__name|nodes_server__ip|nodes_server__node_type|nodes_dashboard__name|nodes_dashboard__ip)=.*?)+\Z") + if [[ "${filecorrect}" -ne 1 ]]; then + common_logger -e "The configuration file ${config_file} does not have a correct format." + exit 1 + fi + +} + +# Retries even if the --retry-connrefused is not available +function common_curl() { + + if [ -n "${curl_has_connrefused}" ]; then + eval "curl $@ --retry-connrefused" + e_code="${PIPESTATUS[0]}" + else + retries=0 + eval "curl $@" + e_code="${PIPESTATUS[0]}" + while [ "${e_code}" -eq 7 ] && [ "${retries}" -ne 12 ]; do + retries=$((retries+1)) + sleep 5 + eval "curl $@" + e_code="${PIPESTATUS[0]}" + done + fi + return "${e_code}" + +} + +function common_remove_gpg_key() { + + common_logger -d "Removing GPG key from system." + if [ "${sys_type}" == "yum" ]; then + if { rpm -q gpg-pubkey --qf '%{NAME}-%{VERSION}-%{RELEASE}\t%{SUMMARY}\n' | grep "Wazuh"; } >/dev/null ; then + key=$(rpm -q gpg-pubkey --qf '%{NAME}-%{VERSION}-%{RELEASE}\t%{SUMMARY}\n' | grep "Wazuh Signing Key" | awk '{print $1}' ) + rpm -e "${key}" + else + common_logger "Wazuh GPG key not found in the system" + return 1 + fi + elif [ "${sys_type}" == "apt-get" ]; then + if [ -f "/usr/share/keyrings/wazuh.gpg" ]; then + rm -rf "/usr/share/keyrings/wazuh.gpg" "${debug}" + else + common_logger "Wazuh GPG key not found in the system" + return 1 + fi + fi + +} + +function common_checkYumLock() { + + attempt=0 + seconds=30 + max_attempts=10 + + while [ -f "${yum_lockfile}" ] && [ "${attempt}" -lt "${max_attempts}" ]; do + attempt=$((attempt+1)) + common_logger "Another process is using YUM. Waiting for it to release the lock. Next retry in ${seconds} seconds (${attempt}/${max_attempts})" + sleep "${seconds}" + done + +} diff --git a/unattended_installer/common_functions/commonVariables.sh b/unattended_installer/common_functions/commonVariables.sh new file mode 100644 index 0000000..d43ffa8 --- /dev/null +++ b/unattended_installer/common_functions/commonVariables.sh @@ -0,0 +1,10 @@ +# Common variables +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +adminpem="/etc/wazuh-indexer/certs/admin.pem" +adminkey="/etc/wazuh-indexer/certs/admin-key.pem" diff --git a/unattended_installer/config/certificate/config.yml b/unattended_installer/config/certificate/config.yml new file mode 100644 index 0000000..c61a756 --- /dev/null +++ b/unattended_installer/config/certificate/config.yml @@ -0,0 +1,26 @@ +nodes: + # Wazuh indexer nodes + indexer: + - name: indexer-1 + ip: "" + - name: indexer-2 + ip: "" + - name: indexer-3 + ip: "" + server: + - name: server-1 + ip: "" + node_type: master + - name: server-2 + ip: "" + node_type: worker + - name: server-3 + ip: "" + node_type: worker + dashboard: + - name: dashboard-1 + ip: "" + - name: dashboard-2 + ip: "" + - name: dashboard-3 + ip: "" diff --git a/unattended_installer/config/certificate/config_aio.yml b/unattended_installer/config/certificate/config_aio.yml new file mode 100644 index 0000000..8f73564 --- /dev/null +++ b/unattended_installer/config/certificate/config_aio.yml @@ -0,0 +1,10 @@ +nodes: + indexer: + - name: wazuh-indexer + ip: 127.0.0.1 + server: + - name: wazuh-server + ip: 127.0.0.1 + dashboard: + - name: wazuh-dashboard + ip: 127.0.0.1 diff --git a/unattended_installer/config/dashboard/dashboard.yml b/unattended_installer/config/dashboard/dashboard.yml new file mode 100644 index 0000000..8123ca9 --- /dev/null +++ b/unattended_installer/config/dashboard/dashboard.yml @@ -0,0 +1,15 @@ +server.host: "" +opensearch.hosts: https://:9200 +server.port: 443 +opensearch.ssl.verificationMode: certificate +# opensearch.username: kibanaserver +# opensearch.password: kibanaserver +opensearch.requestHeadersAllowlist: ["securitytenant","Authorization"] +opensearch_security.multitenancy.enabled: false +opensearch_security.readonly_mode.roles: ["kibana_read_only"] +server.ssl.enabled: true +server.ssl.key: "/etc/wazuh-dashboard/certs/kibana-key.pem" +server.ssl.certificate: "/etc/wazuh-dashboard/certs/kibana.pem" +opensearch.ssl.certificateAuthorities: ["/etc/wazuh-dashboard/certs/root-ca.pem"] +server.defaultRoute: /app/wz-home +opensearch_security.cookie.secure: true diff --git a/unattended_installer/config/dashboard/dashboard_all_in_one.yml b/unattended_installer/config/dashboard/dashboard_all_in_one.yml new file mode 100644 index 0000000..7d48482 --- /dev/null +++ b/unattended_installer/config/dashboard/dashboard_all_in_one.yml @@ -0,0 +1,15 @@ +server.host: 0.0.0.0 +server.port: 443 +opensearch.hosts: https://localhost:9200 +opensearch.ssl.verificationMode: certificate +# opensearch.username: kibanaserver +# opensearch.password: kibanaserver +opensearch.requestHeadersAllowlist: ["securitytenant","Authorization"] +opensearch_security.multitenancy.enabled: false +opensearch_security.readonly_mode.roles: ["kibana_read_only"] +server.ssl.enabled: true +server.ssl.key: "/etc/wazuh-dashboard/certs/kibana-key.pem" +server.ssl.certificate: "/etc/wazuh-dashboard/certs/kibana.pem" +opensearch.ssl.certificateAuthorities: ["/etc/wazuh-dashboard/certs/root-ca.pem"] +uiSettings.overrides.defaultRoute: /app/wz-home +opensearch_security.cookie.secure: true diff --git a/unattended_installer/config/dashboard/dashboard_unattended.yml b/unattended_installer/config/dashboard/dashboard_unattended.yml new file mode 100644 index 0000000..1a48157 --- /dev/null +++ b/unattended_installer/config/dashboard/dashboard_unattended.yml @@ -0,0 +1,15 @@ +server.host: 0.0.0.0 +opensearch.hosts: https://127.0.0.1:9200 +server.port: 443 +opensearch.ssl.verificationMode: certificate +# opensearch.username: kibanaserver +# opensearch.password: kibanaserver +opensearch.requestHeadersAllowlist: ["securitytenant","Authorization"] +opensearch_security.multitenancy.enabled: false +opensearch_security.readonly_mode.roles: ["kibana_read_only"] +server.ssl.enabled: true +server.ssl.key: "/etc/wazuh-dashboard/certs/dashboard-key.pem" +server.ssl.certificate: "/etc/wazuh-dashboard/certs/dashboard.pem" +opensearch.ssl.certificateAuthorities: ["/etc/wazuh-dashboard/certs/root-ca.pem"] +uiSettings.overrides.defaultRoute: /app/wz-home +opensearch_security.cookie.secure: true diff --git a/unattended_installer/config/dashboard/dashboard_unattended_distributed.yml b/unattended_installer/config/dashboard/dashboard_unattended_distributed.yml new file mode 100644 index 0000000..50dbb8a --- /dev/null +++ b/unattended_installer/config/dashboard/dashboard_unattended_distributed.yml @@ -0,0 +1,13 @@ +server.port: 443 +opensearch.ssl.verificationMode: certificate +# opensearch.username: kibanaserver +# opensearch.password: kibanaserver +opensearch.requestHeadersAllowlist: ["securitytenant","Authorization"] +opensearch_security.multitenancy.enabled: false +opensearch_security.readonly_mode.roles: ["kibana_read_only"] +server.ssl.enabled: true +server.ssl.key: "/etc/wazuh-dashboard/certs/dashboard-key.pem" +server.ssl.certificate: "/etc/wazuh-dashboard/certs/dashboard.pem" +opensearch.ssl.certificateAuthorities: ["/etc/wazuh-dashboard/certs/root-ca.pem"] +uiSettings.overrides.defaultRoute: /app/wz-home +opensearch_security.cookie.secure: true diff --git a/unattended_installer/config/filebeat/filebeat.yml b/unattended_installer/config/filebeat/filebeat.yml new file mode 100644 index 0000000..000afd2 --- /dev/null +++ b/unattended_installer/config/filebeat/filebeat.yml @@ -0,0 +1,31 @@ +# Wazuh - Filebeat configuration file +output.elasticsearch: + hosts: [":9200"] + protocol: https + username: ${username} + password: ${password} + ssl.certificate_authorities: + - /etc/filebeat/certs/root-ca.pem + ssl.certificate: "/etc/filebeat/certs/filebeat.pem" + ssl.key: "/etc/filebeat/certs/filebeat-key.pem" +setup.template.json.enabled: true +setup.template.json.path: '/etc/filebeat/wazuh-template.json' +setup.template.json.name: 'wazuh' +setup.ilm.overwrite: true +setup.ilm.enabled: false + +filebeat.modules: + - module: wazuh + alerts: + enabled: true + archives: + enabled: false + +logging.metrics.enabled: false + +seccomp: + default_action: allow + syscalls: + - action: allow + names: + - rseq diff --git a/unattended_installer/config/filebeat/filebeat_all_in_one.yml b/unattended_installer/config/filebeat/filebeat_all_in_one.yml new file mode 100644 index 0000000..34ad970 --- /dev/null +++ b/unattended_installer/config/filebeat/filebeat_all_in_one.yml @@ -0,0 +1,31 @@ +# Wazuh - Filebeat configuration file +output.elasticsearch: + hosts: ["127.0.0.1:9200"] + protocol: https + username: ${username} + password: ${password} + ssl.certificate_authorities: + - /etc/filebeat/certs/root-ca.pem + ssl.certificate: "/etc/filebeat/certs/filebeat.pem" + ssl.key: "/etc/filebeat/certs/filebeat-key.pem" +setup.template.json.enabled: true +setup.template.json.path: '/etc/filebeat/wazuh-template.json' +setup.template.json.name: 'wazuh' +setup.ilm.overwrite: true +setup.ilm.enabled: false + +filebeat.modules: + - module: wazuh + alerts: + enabled: true + archives: + enabled: false + +logging.metrics.enabled: false + +seccomp: + default_action: allow + syscalls: + - action: allow + names: + - rseq diff --git a/unattended_installer/config/filebeat/filebeat_distributed.yml b/unattended_installer/config/filebeat/filebeat_distributed.yml new file mode 100644 index 0000000..e6f122f --- /dev/null +++ b/unattended_installer/config/filebeat/filebeat_distributed.yml @@ -0,0 +1,38 @@ +# Wazuh - Filebeat configuration file +output.elasticsearch: + protocol: https + username: ${username} + password: ${password} + ssl.certificate_authorities: + - /etc/filebeat/certs/root-ca.pem + ssl.certificate: "/etc/filebeat/certs/filebeat.pem" + ssl.key: "/etc/filebeat/certs/filebeat-key.pem" +setup.template.json.enabled: true +setup.template.json.path: '/etc/filebeat/wazuh-template.json' +setup.template.json.name: 'wazuh' +setup.ilm.overwrite: true +setup.ilm.enabled: false + +filebeat.modules: + - module: wazuh + alerts: + enabled: true + archives: + enabled: false + +logging.level: info +logging.to_files: true +logging.files: + path: /var/log/filebeat + name: filebeat + keepfiles: 7 + permissions: 0644 + +logging.metrics.enabled: false + +seccomp: + default_action: allow + syscalls: + - action: allow + names: + - rseq diff --git a/unattended_installer/config/filebeat/filebeat_elastic_cluster.yml b/unattended_installer/config/filebeat/filebeat_elastic_cluster.yml new file mode 100644 index 0000000..459ec99 --- /dev/null +++ b/unattended_installer/config/filebeat/filebeat_elastic_cluster.yml @@ -0,0 +1,31 @@ +# Wazuh - Filebeat configuration file +output.elasticsearch: + hosts: [":9200", ":9200", ":9200"] + protocol: https + username: ${username} + password: ${password} + ssl.certificate_authorities: + - /etc/filebeat/certs/root-ca.pem + ssl.certificate: "/etc/filebeat/certs/filebeat.pem" + ssl.key: "/etc/filebeat/certs/filebeat-key.pem" +setup.template.json.enabled: true +setup.template.json.path: '/etc/filebeat/wazuh-template.json' +setup.template.json.name: 'wazuh' +setup.ilm.overwrite: true +setup.ilm.enabled: false + +filebeat.modules: + - module: wazuh + alerts: + enabled: true + archives: + enabled: false + +logging.metrics.enabled: false + +seccomp: + default_action: allow + syscalls: + - action: allow + names: + - rseq diff --git a/unattended_installer/config/filebeat/filebeat_unattended.yml b/unattended_installer/config/filebeat/filebeat_unattended.yml new file mode 100644 index 0000000..81a8ddf --- /dev/null +++ b/unattended_installer/config/filebeat/filebeat_unattended.yml @@ -0,0 +1,43 @@ +# Wazuh - Filebeat configuration file +output.elasticsearch.hosts: + - 127.0.0.1:9200 +# - :9200 +# - :9200 + +output.elasticsearch: + protocol: https + username: ${username} + password: ${password} + ssl.certificate_authorities: + - /etc/filebeat/certs/root-ca.pem + ssl.certificate: "/etc/filebeat/certs/filebeat.pem" + ssl.key: "/etc/filebeat/certs/filebeat-key.pem" +setup.template.json.enabled: true +setup.template.json.path: '/etc/filebeat/wazuh-template.json' +setup.template.json.name: 'wazuh' +setup.ilm.overwrite: true +setup.ilm.enabled: false + +filebeat.modules: + - module: wazuh + alerts: + enabled: true + archives: + enabled: false + +logging.level: info +logging.to_files: true +logging.files: + path: /var/log/filebeat + name: filebeat + keepfiles: 7 + permissions: 0644 + +logging.metrics.enabled: false + +seccomp: + default_action: allow + syscalls: + - action: allow + names: + - rseq diff --git a/unattended_installer/config/indexer/indexer.yml b/unattended_installer/config/indexer/indexer.yml new file mode 100644 index 0000000..11b14fc --- /dev/null +++ b/unattended_installer/config/indexer/indexer.yml @@ -0,0 +1,36 @@ +network.host: 0.0.0.0 +node.name: node-1 +cluster.initial_master_nodes: node-1 + +plugins.security.ssl.transport.pemcert_filepath: /etc/wazuh-indexer/certs/indexer.pem +plugins.security.ssl.transport.pemkey_filepath: /etc/wazuh-indexer/certs/indexer-key.pem +plugins.security.ssl.transport.pemtrustedcas_filepath: /etc/wazuh-indexer/certs/root-ca.pem +plugins.security.ssl.transport.enforce_hostname_verification: false +plugins.security.ssl.transport.resolve_hostname: false +plugins.security.ssl.http.enabled: true +plugins.security.ssl.http.pemcert_filepath: /etc/wazuh-indexer/certs/indexer.pem +plugins.security.ssl.http.pemkey_filepath: /etc/wazuh-indexer/certs/indexer-key.pem +plugins.security.ssl.http.pemtrustedcas_filepath: /etc/wazuh-indexer/certs/root-ca.pem +plugins.security.ssl.http.enabled_ciphers: + - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" + - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" + - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" + - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" +plugins.security.ssl.http.enabled_protocols: + - "TLSv1.2" +plugins.security.nodes_dn: +- CN=node-1,OU=Wazuh,O=Wazuh,L=California,C=US +plugins.security.authcz.admin_dn: +- CN=admin,OU=Wazuh,O=Wazuh,L=California,C=US + +plugins.security.enable_snapshot_restore_privilege: true +plugins.security.check_snapshot_restore_write_privileges: true +plugins.security.restapi.roles_enabled: ["all_access", "security_rest_api_access"] +cluster.routing.allocation.disk.threshold_enabled: false +node.max_local_storage_nodes: 3 + +path.data: /var/lib/elasticsearch +path.logs: /var/log/elasticsearch + +### Option to allow Filebeat-oss 7.10.2 to work ### +compatibility.override_main_response_version: true \ No newline at end of file diff --git a/unattended_installer/config/indexer/indexer_all_in_one.yml b/unattended_installer/config/indexer/indexer_all_in_one.yml new file mode 100644 index 0000000..0ae85fe --- /dev/null +++ b/unattended_installer/config/indexer/indexer_all_in_one.yml @@ -0,0 +1,41 @@ +network.host: "127.0.0.1" +node.name: "node-1" +cluster.initial_master_nodes: +- "node-1" +cluster.name: "wazuh-cluster" + +node.max_local_storage_nodes: "3" +path.data: /var/lib/wazuh-indexer +path.logs: /var/log/wazuh-indexer + +plugins.security.ssl.http.pemcert_filepath: /etc/wazuh-indexer/certs/indexer.pem +plugins.security.ssl.http.pemkey_filepath: /etc/wazuh-indexer/certs/indexer-key.pem +plugins.security.ssl.http.pemtrustedcas_filepath: /etc/wazuh-indexer/certs/root-ca.pem +plugins.security.ssl.transport.pemcert_filepath: /etc/wazuh-indexer/certs/indexer.pem +plugins.security.ssl.transport.pemkey_filepath: /etc/wazuh-indexer/certs/indexer-key.pem +plugins.security.ssl.transport.pemtrustedcas_filepath: /etc/wazuh-indexer/certs/root-ca.pem +plugins.security.ssl.http.enabled: true +plugins.security.ssl.transport.enforce_hostname_verification: false +plugins.security.ssl.transport.resolve_hostname: false +plugins.security.ssl.http.enabled_ciphers: + - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" + - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" + - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" + - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" +plugins.security.ssl.http.enabled_protocols: + - "TLSv1.2" +plugins.security.authcz.admin_dn: +- "CN=admin,OU=Wazuh,O=Wazuh,L=California,C=US" +plugins.security.check_snapshot_restore_write_privileges: true +plugins.security.enable_snapshot_restore_privilege: true +plugins.security.nodes_dn: +- "CN=indexer,OU=Wazuh,O=Wazuh,L=California,C=US" +plugins.security.restapi.roles_enabled: +- "all_access" +- "security_rest_api_access" + +plugins.security.system_indices.enabled: true +plugins.security.system_indices.indices: [".opendistro-alerting-config", ".opendistro-alerting-alert*", ".opendistro-anomaly-results*", ".opendistro-anomaly-detector*", ".opendistro-anomaly-checkpoints", ".opendistro-anomaly-detection-state", ".opendistro-reports-*", ".opendistro-notifications-*", ".opendistro-notebooks", ".opensearch-observability", ".opendistro-asynchronous-search-response*", ".replication-metadata-store"] + +### Option to allow Filebeat-oss 7.10.2 to work ### +compatibility.override_main_response_version: true diff --git a/unattended_installer/config/indexer/indexer_unattended_distributed.yml b/unattended_installer/config/indexer/indexer_unattended_distributed.yml new file mode 100644 index 0000000..cd63d2e --- /dev/null +++ b/unattended_installer/config/indexer/indexer_unattended_distributed.yml @@ -0,0 +1,41 @@ +node.master: true +node.data: true +node.ingest: true + +cluster.name: wazuh-indexer-cluster +cluster.routing.allocation.disk.threshold_enabled: false + +node.max_local_storage_nodes: "3" +path.data: /var/lib/wazuh-indexer +path.logs: /var/log/wazuh-indexer + + +plugins.security.ssl.http.pemcert_filepath: /etc/wazuh-indexer/certs/indexer.pem +plugins.security.ssl.http.pemkey_filepath: /etc/wazuh-indexer/certs/indexer-key.pem +plugins.security.ssl.http.pemtrustedcas_filepath: /etc/wazuh-indexer/certs/root-ca.pem +plugins.security.ssl.transport.pemcert_filepath: /etc/wazuh-indexer/certs/indexer.pem +plugins.security.ssl.transport.pemkey_filepath: /etc/wazuh-indexer/certs/indexer-key.pem +plugins.security.ssl.transport.pemtrustedcas_filepath: /etc/wazuh-indexer/certs/root-ca.pem +plugins.security.ssl.http.enabled: true +plugins.security.ssl.transport.enforce_hostname_verification: false +plugins.security.ssl.transport.resolve_hostname: false +plugins.security.ssl.http.enabled_ciphers: + - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" + - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" + - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" + - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" +plugins.security.ssl.http.enabled_protocols: + - "TLSv1.2" +plugins.security.authcz.admin_dn: +- "CN=admin,OU=Wazuh,O=Wazuh,L=California,C=US" +plugins.security.check_snapshot_restore_write_privileges: true +plugins.security.enable_snapshot_restore_privilege: true +plugins.security.restapi.roles_enabled: +- "all_access" +- "security_rest_api_access" + +plugins.security.system_indices.enabled: true +plugins.security.system_indices.indices: [".opendistro-alerting-config", ".opendistro-alerting-alert*", ".opendistro-anomaly-results*", ".opendistro-anomaly-detector*", ".opendistro-anomaly-checkpoints", ".opendistro-anomaly-detection-state", ".opendistro-reports-*", ".opendistro-notifications-*", ".opendistro-notebooks", ".opensearch-observability", ".opendistro-asynchronous-search-response*", ".replication-metadata-store"] + +### Option to allow Filebeat-oss 7.10.2 to work ### +compatibility.override_main_response_version: true diff --git a/unattended_installer/config/indexer/roles/internal_users.yml b/unattended_installer/config/indexer/roles/internal_users.yml new file mode 100644 index 0000000..1ff2c8c --- /dev/null +++ b/unattended_installer/config/indexer/roles/internal_users.yml @@ -0,0 +1,56 @@ +--- +# This is the internal user database +# The hash value is a bcrypt hash and can be generated with plugin/tools/hash.sh + +_meta: + type: "internalusers" + config_version: 2 + +# Define your internal users here + +## Demo users + +admin: + hash: "$2a$12$VcCDgh2NDk07JGN0rjGbM.Ad41qVR/YFJcgHp0UGns5JDymv..TOG" + reserved: true + backend_roles: + - "admin" + description: "Demo admin user" + +kibanaserver: + hash: "$2a$12$4AcgAt3xwOWadA5s5blL6ev39OXDNhmOesEoo33eZtrq2N0YrU3H." + reserved: true + description: "Demo kibanaserver user" + +kibanaro: + hash: "$2a$12$JJSXNfTowz7Uu5ttXfeYpeYE0arACvcwlPBStB1F.MI7f0U9Z4DGC" + reserved: false + backend_roles: + - "kibanauser" + - "readall" + attributes: + attribute1: "value1" + attribute2: "value2" + attribute3: "value3" + description: "Demo kibanaro user" + +logstash: + hash: "$2a$12$u1ShR4l4uBS3Uv59Pa2y5.1uQuZBrZtmNfqB3iM/.jL0XoV9sghS2" + reserved: false + backend_roles: + - "logstash" + description: "Demo logstash user" + +readall: + hash: "$2a$12$ae4ycwzwvLtZxwZ82RmiEunBbIPiAmGZduBAjKN0TXdwQFtCwARz2" + reserved: false + backend_roles: + - "readall" + description: "Demo readall user" + +snapshotrestore: + hash: "$2y$12$DpwmetHKwgYnorbgdvORCenv4NAK8cPUg8AI6pxLCuWf/ALc0.v7W" + reserved: false + backend_roles: + - "snapshotrestore" + description: "Demo snapshotrestore user" diff --git a/unattended_installer/config/indexer/roles/roles.yml b/unattended_installer/config/indexer/roles/roles.yml new file mode 100644 index 0000000..860ae00 --- /dev/null +++ b/unattended_installer/config/indexer/roles/roles.yml @@ -0,0 +1,149 @@ +_meta: + type: "roles" + config_version: 2 + +# Restrict users so they can only view visualization and dashboard on kibana +kibana_read_only: + reserved: true + +# The security REST API access role is used to assign specific users access to change the security settings through the REST API. +security_rest_api_access: + reserved: true + +# Allows users to view monitors, destinations and alerts +alerting_read_access: + reserved: true + cluster_permissions: + - 'cluster:admin/opendistro/alerting/alerts/get' + - 'cluster:admin/opendistro/alerting/destination/get' + - 'cluster:admin/opendistro/alerting/monitor/get' + - 'cluster:admin/opendistro/alerting/monitor/search' + +# Allows users to view and acknowledge alerts +alerting_ack_alerts: + reserved: true + cluster_permissions: + - 'cluster:admin/opendistro/alerting/alerts/*' + +# Allows users to use all alerting functionality +alerting_full_access: + reserved: true + cluster_permissions: + - 'cluster_monitor' + - 'cluster:admin/opendistro/alerting/*' + index_permissions: + - index_patterns: + - '*' + allowed_actions: + - 'indices_monitor' + - 'indices:admin/aliases/get' + - 'indices:admin/mappings/get' + +# Allow users to read Anomaly Detection detectors and results +anomaly_read_access: + reserved: true + cluster_permissions: + - 'cluster:admin/opendistro/ad/detector/info' + - 'cluster:admin/opendistro/ad/detector/search' + - 'cluster:admin/opendistro/ad/detectors/get' + - 'cluster:admin/opendistro/ad/result/search' + - 'cluster:admin/opendistro/ad/tasks/search' + +# Allows users to use all Anomaly Detection functionality +anomaly_full_access: + reserved: true + cluster_permissions: + - 'cluster_monitor' + - 'cluster:admin/opendistro/ad/*' + index_permissions: + - index_patterns: + - '*' + allowed_actions: + - 'indices_monitor' + - 'indices:admin/aliases/get' + - 'indices:admin/mappings/get' + +# Allows users to read Notebooks +notebooks_read_access: + reserved: true + cluster_permissions: + - 'cluster:admin/opendistro/notebooks/list' + - 'cluster:admin/opendistro/notebooks/get' + +# Allows users to all Notebooks functionality +notebooks_full_access: + reserved: true + cluster_permissions: + - 'cluster:admin/opendistro/notebooks/create' + - 'cluster:admin/opendistro/notebooks/update' + - 'cluster:admin/opendistro/notebooks/delete' + - 'cluster:admin/opendistro/notebooks/get' + - 'cluster:admin/opendistro/notebooks/list' + +# Allows users to read and download Reports +reports_instances_read_access: + reserved: true + cluster_permissions: + - 'cluster:admin/opendistro/reports/instance/list' + - 'cluster:admin/opendistro/reports/instance/get' + - 'cluster:admin/opendistro/reports/menu/download' + +# Allows users to read and download Reports and Report-definitions +reports_read_access: + reserved: true + cluster_permissions: + - 'cluster:admin/opendistro/reports/definition/get' + - 'cluster:admin/opendistro/reports/definition/list' + - 'cluster:admin/opendistro/reports/instance/list' + - 'cluster:admin/opendistro/reports/instance/get' + - 'cluster:admin/opendistro/reports/menu/download' + +# Allows users to all Reports functionality +reports_full_access: + reserved: true + cluster_permissions: + - 'cluster:admin/opendistro/reports/definition/create' + - 'cluster:admin/opendistro/reports/definition/update' + - 'cluster:admin/opendistro/reports/definition/on_demand' + - 'cluster:admin/opendistro/reports/definition/delete' + - 'cluster:admin/opendistro/reports/definition/get' + - 'cluster:admin/opendistro/reports/definition/list' + - 'cluster:admin/opendistro/reports/instance/list' + - 'cluster:admin/opendistro/reports/instance/get' + - 'cluster:admin/opendistro/reports/menu/download' + +# Allows users to use all asynchronous-search functionality +asynchronous_search_full_access: + reserved: true + cluster_permissions: + - 'cluster:admin/opendistro/asynchronous_search/*' + index_permissions: + - index_patterns: + - '*' + allowed_actions: + - 'indices:data/read/search*' + +# Allows users to read stored asynchronous-search results +asynchronous_search_read_access: + reserved: true + cluster_permissions: + - 'cluster:admin/opendistro/asynchronous_search/get' + +# Wazuh monitoring and statistics index permissions +manage_wazuh_index: + reserved: true + hidden: false + cluster_permissions: [] + index_permissions: + - index_patterns: + - "wazuh-*" + dls: "" + fls: [] + masked_fields: [] + allowed_actions: + - "read" + - "delete" + - "manage" + - "index" + tenant_permissions: [] + static: false diff --git a/unattended_installer/config/indexer/roles/roles_mapping.yml b/unattended_installer/config/indexer/roles/roles_mapping.yml new file mode 100644 index 0000000..4c28846 --- /dev/null +++ b/unattended_installer/config/indexer/roles/roles_mapping.yml @@ -0,0 +1,87 @@ +--- +# In this file users, backendroles and hosts can be mapped to Open Distro Security roles. +# Permissions for Opendistro roles are configured in roles.yml + +_meta: + type: "rolesmapping" + config_version: 2 + +# Define your roles mapping here + +## Default roles mapping + +all_access: + reserved: true + hidden: false + backend_roles: + - "admin" + hosts: [] + users: [] + and_backend_roles: [] + description: "Maps admin to all_access" + +own_index: + reserved: false + hidden: false + backend_roles: [] + hosts: [] + users: + - "*" + and_backend_roles: [] + description: "Allow full access to an index named like the username" + +logstash: + reserved: false + hidden: false + backend_roles: + - "logstash" + hosts: [] + users: [] + and_backend_roles: [] + +readall: + reserved: true + hidden: false + backend_roles: + - "readall" + hosts: [] + users: [] + and_backend_roles: [] + +manage_snapshots: + reserved: true + hidden: false + backend_roles: + - "snapshotrestore" + hosts: [] + users: [] + and_backend_roles: [] + +kibana_server: + reserved: true + hidden: false + backend_roles: [] + hosts: [] + users: + - "kibanaserver" + and_backend_roles: [] + +kibana_user: + reserved: false + hidden: false + backend_roles: + - "kibanauser" + hosts: [] + users: [] + and_backend_roles: [] + description: "Maps kibanauser to kibana_user" + +# Wazuh monitoring and statistics index permissions +manage_wazuh_index: + reserved: true + hidden: false + backend_roles: [] + hosts: [] + users: + - "kibanaserver" + and_backend_roles: [] diff --git a/unattended_installer/install_functions/checks.sh b/unattended_installer/install_functions/checks.sh new file mode 100644 index 0000000..0d42d2a --- /dev/null +++ b/unattended_installer/install_functions/checks.sh @@ -0,0 +1,495 @@ +# Wazuh installer - checks.sh functions. +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +function checks_arch() { + + common_logger -d "Checking system architecture." + arch=$(uname -m) + + if [ "${arch}" != "x86_64" ]; then + common_logger -e "Uncompatible system. This script must be run on a 64-bit system." + exit 1 + fi +} + +function checks_arguments() { + + # -------------- Port option validation --------------------- + + if [ -n "${port_specified}" ]; then + if [ -z "${AIO}" ] && [ -z "${dashboard}" ]; then + common_logger -e "The argument -p|--port can only be used with -a|--all-in-one or -wd|--wazuh-dashboard." + exit 1 + fi + fi + + # -------------- Offline installation --------------------- + + if [ -n "${offline_install}" ]; then + if [ -z "${AIO}" ] && [ -z "${dashboard}" ] && [ -z "${indexer}" ] && [ -z "${wazuh}" ] && [ -z "${start_indexer_cluster}" ]; then + common_logger -e "The -of|--offline-installation option must be used with -a, -ws, -s, -wi, or -wd." + exit 1 + fi + fi + + # -------------- Configurations --------------------------------- + + if [ -f "${tar_file}" ]; then + if [ -n "${AIO}" ]; then + rm -f "${tar_file}" + fi + if [ -n "${configurations}" ]; then + common_logger -e "File ${tar_file} already exists. Please remove it if you want to use a new configuration." + exit 1 + fi + fi + + if [[ -n "${configurations}" && ( -n "${AIO}" || -n "${indexer}" || -n "${dashboard}" || -n "${wazuh}" || -n "${overwrite}" || -n "${start_indexer_cluster}" || -n "${tar_conf}" || -n "${uninstall}" ) ]]; then + common_logger -e "The argument -g|--generate-config-files can't be used with -a|--all-in-one, -o|--overwrite, -s|--start-cluster, -t|--tar, -u|--uninstall, -wd|--wazuh-dashboard, -wi|--wazuh-indexer, or -ws|--wazuh-server." + exit 1 + fi + + # -------------- Overwrite -------------------------------------- + + if [ -n "${overwrite}" ] && [ -z "${AIO}" ] && [ -z "${indexer}" ] && [ -z "${dashboard}" ] && [ -z "${wazuh}" ]; then + common_logger -e "The argument -o|--overwrite must be used in conjunction with -a|--all-in-one, -wd|--wazuh-dashboard, -wi|--wazuh-indexer, or -ws|--wazuh-server." + exit 1 + fi + + # -------------- Uninstall -------------------------------------- + + if [ -n "${uninstall}" ]; then + + if [ -n "$AIO" ] || [ -n "$indexer" ] || [ -n "$dashboard" ] || [ -n "$wazuh" ]; then + common_logger -e "It is not possible to uninstall and install in the same operation. If you want to overwrite the components use -o|--overwrite." + exit 1 + fi + + if [ -z "${wazuh_installed}" ] && [ -z "${wazuh_remaining_files}" ]; then + common_logger "Wazuh manager not found in the system so it was not uninstalled." + fi + + if [ -z "${filebeat_installed}" ] && [ -z "${filebeat_remaining_files}" ]; then + common_logger "Filebeat not found in the system so it was not uninstalled." + fi + + if [ -z "${indexer_installed}" ] && [ -z "${indexer_remaining_files}" ]; then + common_logger "Wazuh indexer not found in the system so it was not uninstalled." + fi + + if [ -z "${dashboard_installed}" ] && [ -z "${dashboard_remaining_files}" ]; then + common_logger "Wazuh dashboard not found in the system so it was not uninstalled." + fi + + fi + + # -------------- All-In-One ------------------------------------- + + if [ -n "${AIO}" ]; then + + if [ -n "$indexer" ] || [ -n "$dashboard" ] || [ -n "$wazuh" ]; then + common_logger -e "Argument -a|--all-in-one is not compatible with -wi|--wazuh-indexer, -wd|--wazuh-dashboard or -ws|--wazuh-server." + exit 1 + fi + + if [ -n "${overwrite}" ]; then + installCommon_rollBack + fi + + if [ -z "${overwrite}" ] && { [ -n "${wazuh_installed}" ] || [ -n "${wazuh_remaining_files}" ]; }; then + common_logger -e "Wazuh manager already installed." + installedComponent=1 + fi + if [ -z "${overwrite}" ] && { [ -n "${indexer_installed}" ] || [ -n "${indexer_remaining_files}" ]; };then + common_logger -e "Wazuh indexer already installed." + installedComponent=1 + fi + if [ -z "${overwrite}" ] && { [ -n "${dashboard_installed}" ] || [ -n "${dashboard_remaining_files}" ]; }; then + common_logger -e "Wazuh dashboard already installed." + installedComponent=1 + fi + if [ -z "${overwrite}" ] && { [ -n "${filebeat_installed}" ] || [ -n "${filebeat_remaining_files}" ]; }; then + common_logger -e "Filebeat already installed." + installedComponent=1 + fi + if [ -n "${installedComponent}" ]; then + common_logger "If you want to overwrite the current installation, run this script adding the option -o/--overwrite. This will erase all the existing configuration and data." + exit 1 + fi + + fi + + # -------------- Indexer ---------------------------------- + + if [ -n "${indexer}" ]; then + + if [ -n "${indexer_installed}" ] || [ -n "${indexer_remaining_files}" ]; then + if [ -n "${overwrite}" ]; then + installCommon_rollBack + else + common_logger -e "Wazuh indexer is already installed in this node or some of its files have not been removed. Use option -o|--overwrite to overwrite all components." + exit 1 + fi + fi + fi + + # -------------- Wazuh dashboard -------------------------------- + + if [ -n "${dashboard}" ]; then + if [ -n "${dashboard_installed}" ] || [ -n "${dashboard_remaining_files}" ]; then + if [ -n "${overwrite}" ]; then + installCommon_rollBack + else + common_logger -e "Wazuh dashboard is already installed in this node or some of its files have not been removed. Use option -o|--overwrite to overwrite all components." + exit 1 + fi + fi + fi + + # -------------- Wazuh ------------------------------------------ + + if [ -n "${wazuh}" ]; then + if [ -n "${wazuh_installed}" ] || [ -n "${wazuh_remaining_files}" ] || [ -n "${filebeat_installed}" ] || [ -n "${filebeat_remaining_files}" ]; then + if [ -n "${overwrite}" ]; then + installCommon_rollBack + else + common_logger -e "Wazuh server components (wazuh-manager and filebeat) are already installed in this node or some of their files have not been removed. Use option -o|--overwrite to overwrite all components." + exit 1 + fi + fi + fi + + # -------------- Cluster start ---------------------------------- + + if [[ -n "${start_indexer_cluster}" && ( -n "${AIO}" || -n "${indexer}" || -n "${dashboard}" || -n "${wazuh}" || -n "${overwrite}" || -n "${configurations}" || -n "${tar_conf}" || -n "${uninstall}") ]]; then + common_logger -e "The argument -s|--start-cluster can't be used with -a|--all-in-one, -g|--generate-config-files,-o|--overwrite , -u|--uninstall, -wi|--wazuh-indexer, -wd|--wazuh-dashboard, -s|--start-cluster, -ws|--wazuh-server." + exit 1 + fi + + # -------------- Global ----------------------------------------- + + if [ -z "${AIO}" ] && [ -z "${indexer}" ] && [ -z "${dashboard}" ] && [ -z "${wazuh}" ] && [ -z "${start_indexer_cluster}" ] && [ -z "${configurations}" ] && [ -z "${uninstall}" ] && [ -z "${download}" ]; then + common_logger -e "At least one of these arguments is necessary -a|--all-in-one, -g|--generate-config-files, -wi|--wazuh-indexer, -wd|--wazuh-dashboard, -s|--start-cluster, -ws|--wazuh-server, -u|--uninstall, -dw|--download-wazuh." + exit 1 + fi + + if [ -n "${force}" ] && [ -z "${dashboard}" ]; then + common_logger -e "The -fd|--force-install-dashboard argument needs to be used alongside -wd|--wazuh-dashboard." + exit 1 + fi + +} + +# Checks if the --retry-connrefused is available in curl +function check_curlVersion() { + + common_logger -d "Checking curl tool version." + # --retry-connrefused was added in 7.52.0 + curl_version=$(curl -V | head -n 1 | awk '{ print $2 }') + if [ $(check_versions ${curl_version} 7.52.0) == "0" ]; then + curl_has_connrefused=0 + fi + +} + +function check_dist() { + common_logger -d "Checking system distribution." + dist_detect + if [ "${DIST_NAME}" != "centos" ] && [ "${DIST_NAME}" != "rhel" ] && + [ "${DIST_NAME}" != "amzn" ] && [ "${DIST_NAME}" != "ubuntu" ] && [ "${DIST_NAME}" != "rocky" ]; then + notsupported=1 + fi + if [ "${DIST_NAME}" == "centos" ] && { [ "${DIST_VER}" -ne "7" ] && [ "${DIST_VER}" -ne "8" ]; }; then + notsupported=1 + fi + if [ "${DIST_NAME}" == "rhel" ] && { [ "${DIST_VER}" -ne "7" ] && [ "${DIST_VER}" -ne "8" ] && [ "${DIST_VER}" -ne "9" ]; }; then + notsupported=1 + fi + + if [ "${DIST_NAME}" == "amzn" ]; then + if [ "${DIST_VER}" != "2" ] && + [ "${DIST_VER}" != "2023" ] && + [ "${DIST_VER}" != "2018.03" ]; then + notsupported=1 + fi + if [ "${DIST_VER}" -eq "2023" ]; then + checks_specialDepsAL2023 + fi + fi + + if [ "${DIST_NAME}" == "ubuntu" ]; then + if [ "${DIST_VER}" == "16" ] || [ "${DIST_VER}" == "18" ] || + [ "${DIST_VER}" == "20" ] || [ "${DIST_VER}" == "22" ] || + [ "${DIST_VER}" == "24" ]; then + if [ "${DIST_SUBVER}" != "04" ]; then + notsupported=1 + fi + else + notsupported=1 + fi + fi + + if [ "${DIST_NAME}" == "rocky" ]; then + if [ "${DIST_VER}" != "9" ] || [ "${DIST_SUBVER}" != "4" ]; then + notsupported=1 + fi + fi + + if [ -n "${notsupported}" ]; then + common_logger "The recommended systems are: Red Hat Enterprise Linux 7, 8, 9; CentOS 7, 8; Amazon Linux 2; Ubuntu 16.04, 18.04, 20.04, 22.04." + common_logger -w "The current system does not match with the list of recommended systems. The installation may not work properly." + fi + common_logger -d "Detected distribution name: ${DIST_NAME}" + common_logger -d "Detected distribution version: ${DIST_VER}" + +} + +function checks_health() { + + checks_specifications + + common_logger -d "CPU cores detected: ${cores}" + common_logger -d "Free RAM memory detected: ${ram_gb}" + + if [ -n "${indexer}" ]; then + if [ "${cores}" -lt 2 ] || [ "${ram_gb}" -lt 3700 ]; then + common_logger -e "Your system does not meet the recommended minimum hardware requirements of 4Gb of RAM and 2 CPU cores. If you want to proceed with the installation use the -i option to ignore these requirements." + exit 1 + fi + fi + + if [ -n "${dashboard}" ]; then + if [ "${cores}" -lt 2 ] || [ "${ram_gb}" -lt 3700 ]; then + common_logger -e "Your system does not meet the recommended minimum hardware requirements of 4Gb of RAM and 2 CPU cores. If you want to proceed with the installation use the -i option to ignore these requirements." + exit 1 + fi + fi + + if [ -n "${wazuh}" ]; then + if [ "${cores}" -lt 2 ] || [ "${ram_gb}" -lt 1700 ]; then + common_logger -e "Your system does not meet the recommended minimum hardware requirements of 2Gb of RAM and 2 CPU cores . If you want to proceed with the installation use the -i option to ignore these requirements." + exit 1 + fi + fi + + if [ -n "${AIO}" ]; then + if [ "${cores}" -lt 2 ] || [ "${ram_gb}" -lt 3700 ]; then + common_logger -e "Your system does not meet the recommended minimum hardware requirements of 4Gb of RAM and 2 CPU cores. If you want to proceed with the installation use the -i option to ignore these requirements." + exit 1 + fi + fi + +} + +# This function ensures different names in the config.yml file. +function checks_names() { + + common_logger -d "Checking node names in the configuration file." + if [ -n "${indxname}" ] && [ -n "${dashname}" ] && [ "${indxname}" == "${dashname}" ]; then + common_logger -e "The node names for Wazuh indexer and Wazuh dashboard must be different." + exit 1 + fi + + if [ -n "${indxname}" ] && [ -n "${winame}" ] && [ "${indxname}" == "${winame}" ]; then + common_logger -e "The node names for Elastisearch and Wazuh must be different." + exit 1 + fi + + if [ -n "${winame}" ] && [ -n "${dashname}" ] && [ "${winame}" == "${dashname}" ]; then + common_logger -e "The node names for Wazuh server and Wazuh indexer must be different." + exit 1 + fi + + if [ -n "${winame}" ] && ! echo "${server_node_names[@]}" | grep -w -q "${winame}"; then + common_logger -e "The Wazuh server node name ${winame} does not appear on the configuration file." + exit 1 + fi + + if [ -n "${indxname}" ] && ! echo "${indexer_node_names[@]}" | grep -w -q "${indxname}"; then + common_logger -e "The Wazuh indexer node name ${indxname} does not appear on the configuration file." + exit 1 + fi + + if [ -n "${dashname}" ] && ! echo "${dashboard_node_names[@]}" | grep -w -q "${dashname}"; then + common_logger -e "The Wazuh dashboard node name ${dashname} does not appear on the configuration file." + exit 1 + fi + + if [[ "${dashname}" == -* ]] || [[ "${indxname}" == -* ]] || [[ "${winame}" == -* ]]; then + common_logger -e "Node name cannot start with \"-\"" + exit 1 + fi + +} + +# This function checks if the target certificates are created before to start the installation. +function checks_previousCertificate() { + common_logger -d "Checking previous certificate existence." + if [ ! -f "${tar_file}" ]; then + common_logger -e "Cannot find ${tar_file}. Run the script with the option -g|--generate-config-files to create it or copy it from another node." + exit 1 + fi + + if [ -n "${indxname}" ]; then + if ! tar -tf "${tar_file}" | grep -q -E ^wazuh-install-files/"${indxname}".pem || ! tar -tf "${tar_file}" | grep -q -E ^wazuh-install-files/"${indxname}"-key.pem; then + common_logger -e "There is no certificate for the indexer node ${indxname} in ${tar_file}." + exit 1 + fi + fi + + if [ -n "${dashname}" ]; then + if ! tar -tf "${tar_file}" | grep -q -E ^wazuh-install-files/"${dashname}".pem || ! tar -tf "${tar_file}" | grep -q -E ^wazuh-install-files/"${dashname}"-key.pem; then + common_logger -e "There is no certificate for the Wazuh dashboard node ${dashname} in ${tar_file}." + exit 1 + fi + fi + + if [ -n "${winame}" ]; then + if ! tar -tf "${tar_file}" | grep -q -E ^wazuh-install-files/"${winame}".pem || ! tar -tf "${tar_file}" | grep -q -E ^wazuh-install-files/"${winame}"-key.pem; then + common_logger -e "There is no certificate for the wazuh server node ${winame} in ${tar_file}." + exit 1 + fi + fi +} + +# Manages the special dependencies in case of AL2023 +function checks_specialDepsAL2023() { + + # Change curl for curl-minimal + wia_yum_dependencies=( "${wia_yum_dependencies[@]/curl/curl-minimal}" ) + + # In containers, coreutils is replaced for coreutils-single + if [ -f "/.dockerenv" ]; then + wia_yum_dependencies=( "${wia_yum_dependencies[@]/coreutils/coreutils-single}" ) + fi +} + +function checks_specifications() { + + cores=$(grep -c processor /proc/cpuinfo) + ram_gb=$(free -m | awk 'FNR == 2 {print $2}') + +} + +function checks_ports() { + + if [ -z "${offline_install}" ]; then + dep="lsof" + if [ "${sys_type}" == "yum" ]; then + installCommon_yumInstallList "${dep}" + elif [ "${sys_type}" == "apt-get" ]; then + installCommon_aptInstallList "${dep}" + fi + + if [ "${#not_installed[@]}" -gt 0 ]; then + wia_dependencies_installed+=("${dep}") + fi + fi + + common_logger -d "Checking ports availability." + used_port=0 + ports=("$@") + + checks_firewall "${ports[@]}" + + if command -v lsof > /dev/null; then + port_command="lsof -sTCP:LISTEN -i:" + else + common_logger -w "Cannot find lsof. Port checking will be skipped." + return 1 + fi + + for i in "${!ports[@]}"; do + if eval "${port_command}""${ports[i]}" > /dev/null; then + used_port=1 + common_logger -e "Port ${ports[i]} is being used by another process. Please, check it before installing Wazuh." + fi + done + + if [ "${used_port}" -eq 1 ]; then + common_logger "The installation can not continue due to port usage by other processes." + installCommon_rollBack + exit 1 + fi + +} + +# Checks if the first version is greater equal than to second one +function check_versions() { + + if test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; then + echo 0 + else + echo 1 + fi +} + +function checks_available_port() { + chosen_port="$1" + shift + ports_list=("$@") + + if [ "$chosen_port" -ne "${http_port}" ]; then + for port in "${ports_list[@]}"; do + if [ "$chosen_port" -eq "$port" ]; then + common_logger -e "Port ${chosen_port} is reserved by Wazuh. Please, choose another port." + exit 1 + fi + done + fi +} + +function checks_firewall(){ + ports_list=("$@") + f_ports="" + f_message="The system has firewall enabled. Please ensure that traffic is allowed on " + firewalld_installed=0 + ufw_installed=0 + + + # Record of the ports that must be exposed according to the installation + if [ -n "${AIO}" ]; then + f_message+="these ports: 1515, 1514, ${http_port}" + elif [ -n "${dashboard}" ]; then + f_message+="this port: ${http_port}" + else + f_message+="these ports:" + for port in "${ports_list[@]}"; do + f_message+=" ${port}," + done + + # Deletes last comma + f_message="${f_message%,}" + fi + + # Check if the firewall is installed + if [ "${sys_type}" == "yum" ]; then + eval "rpm -q firewalld --quiet && firewalld_installed=1" + eval "rpm -q ufw --quiet && ufw_installed=1" + elif [ "${sys_type}" == "apt-get" ]; then + if apt list --installed 2>/dev/null | grep -q -E ^"firewalld"\/; then + firewalld_installed=1 + fi + if apt list --installed 2>/dev/null | grep -q -E ^"ufw"\/; then + ufw_installed=1 + fi + fi + + # Check if the firewall is running + if [ "${firewalld_installed}" == "1" ]; then + if firewall-cmd --state 2>/dev/null | grep -q -w "running"; then + common_logger -w "${f_message/firewall/Firewalld}." + fi + fi + if [ "${ufw_installed}" == "1" ]; then + if ufw status 2>/dev/null | grep -q -w "active"; then + common_logger -w "${f_message/firewall/UFW}." + fi + fi + +} diff --git a/unattended_installer/install_functions/dashboard.sh b/unattended_installer/install_functions/dashboard.sh new file mode 100644 index 0000000..2b43fb5 --- /dev/null +++ b/unattended_installer/install_functions/dashboard.sh @@ -0,0 +1,226 @@ +# Wazuh installer - dashboard.sh functions. +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +function dashboard_changePort() { + + chosen_port="$1" + http_port="${chosen_port}" + wazuh_dashboard_port=( "${http_port}" ) + wazuh_aio_ports=(9200 9300 1514 1515 1516 55000 "${http_port}") + + sed -i 's/server\.port: [0-9]\+$/server.port: '"${chosen_port}"'/' "$0" + common_logger "Wazuh web interface port will be ${chosen_port}." +} + +function dashboard_configure() { + + common_logger -d "Configuring Wazuh dashboard." + if [ -n "${AIO}" ]; then + eval "installCommon_getConfig dashboard/dashboard_unattended.yml /etc/wazuh-dashboard/opensearch_dashboards.yml ${debug}" + dashboard_copyCertificates "${debug}" + else + eval "installCommon_getConfig dashboard/dashboard_unattended_distributed.yml /etc/wazuh-dashboard/opensearch_dashboards.yml ${debug}" + dashboard_copyCertificates "${debug}" + if [ "${#dashboard_node_names[@]}" -eq 1 ]; then + pos=0 + ip=${dashboard_node_ips[0]} + else + for i in "${!dashboard_node_names[@]}"; do + if [[ "${dashboard_node_names[i]}" == "${dashname}" ]]; then + pos="${i}"; + fi + done + ip=${dashboard_node_ips[pos]} + fi + + if [[ "${ip}" != "127.0.0.1" ]]; then + echo "server.host: ${ip}" >> /etc/wazuh-dashboard/opensearch_dashboards.yml + else + echo 'server.host: '0.0.0.0'' >> /etc/wazuh-dashboard/opensearch_dashboards.yml + fi + + if [ "${#indexer_node_names[@]}" -eq 1 ]; then + echo "opensearch.hosts: https://${indexer_node_ips[0]}:9200" >> /etc/wazuh-dashboard/opensearch_dashboards.yml + else + echo "opensearch.hosts:" >> /etc/wazuh-dashboard/opensearch_dashboards.yml + for i in "${indexer_node_ips[@]}"; do + echo " - https://${i}:9200" >> /etc/wazuh-dashboard/opensearch_dashboards.yml + done + fi + fi + + sed -i 's/server\.port: [0-9]\+$/server.port: '"${chosen_port}"'/' /etc/wazuh-dashboard/opensearch_dashboards.yml + + common_logger "Wazuh dashboard post-install configuration finished." + +} + +function dashboard_copyCertificates() { + + common_logger -d "Copying Wazuh dashboard certificates." + eval "rm -f ${dashboard_cert_path}/* ${debug}" + name=${dashboard_node_names[pos]} + + if [ -f "${tar_file}" ]; then + if ! tar -tvf "${tar_file}" | grep -q "${name}" ; then + common_logger -e "Tar file does not contain certificate for the node ${name}." + installCommon_rollBack + exit 1; + fi + eval "mkdir ${dashboard_cert_path} ${debug}" + eval "sed -i s/dashboard.pem/${name}.pem/ /etc/wazuh-dashboard/opensearch_dashboards.yml ${debug}" + eval "sed -i s/dashboard-key.pem/${name}-key.pem/ /etc/wazuh-dashboard/opensearch_dashboards.yml ${debug}" + eval "tar -xf ${tar_file} -C ${dashboard_cert_path} wazuh-install-files/${name}.pem --strip-components 1 ${debug}" + eval "tar -xf ${tar_file} -C ${dashboard_cert_path} wazuh-install-files/${name}-key.pem --strip-components 1 ${debug}" + eval "tar -xf ${tar_file} -C ${dashboard_cert_path} wazuh-install-files/root-ca.pem --strip-components 1 ${debug}" + eval "chown -R wazuh-dashboard:wazuh-dashboard /etc/wazuh-dashboard/ ${debug}" + eval "chmod 500 ${dashboard_cert_path} ${debug}" + eval "chmod 400 ${dashboard_cert_path}/* ${debug}" + eval "chown wazuh-dashboard:wazuh-dashboard ${dashboard_cert_path}/* ${debug}" + common_logger -d "Wazuh dashboard certificate setup finished." + else + common_logger -e "No certificates found. Wazuh dashboard could not be initialized." + installCommon_rollBack + exit 1 + fi + +} + +function dashboard_initialize() { + + common_logger "Initializing Wazuh dashboard web application." + installCommon_getPass "admin" + j=0 + + if [ "${#dashboard_node_names[@]}" -eq 1 ]; then + nodes_dashboard_ip=${dashboard_node_ips[0]} + else + for i in "${!dashboard_node_names[@]}"; do + if [[ "${dashboard_node_names[i]}" == "${dashname}" ]]; then + pos="${i}"; + fi + done + nodes_dashboard_ip=${dashboard_node_ips[pos]} + fi + + if [ "${nodes_dashboard_ip}" == "localhost" ] || [[ "${nodes_dashboard_ip}" == 127.* ]]; then + print_ip="" + else + print_ip="${nodes_dashboard_ip}" + fi + + until [ "$(curl -XGET https://"${nodes_dashboard_ip}":"${http_port}"/status -uadmin:"${u_pass}" -k -w %"{http_code}" -s -o /dev/null)" -eq "200" ] || [ "${j}" -eq "12" ]; do + sleep 10 + j=$((j+1)) + common_logger -d "Retrying Wazuh dashboard connection..." + done + + if [ ${j} -lt 12 ]; then + common_logger -d "Wazuh dashboard connection was successful." + if [ "${#server_node_names[@]}" -eq 1 ]; then + wazuh_api_address=${server_node_ips[0]} + else + for i in "${!server_node_types[@]}"; do + if [[ "${server_node_types[i]}" == "master" ]]; then + wazuh_api_address=${server_node_ips[i]} + fi + done + fi + if [ -f "/usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml" ]; then + eval "sed -i 's,url: https://localhost,url: https://${wazuh_api_address},g' /usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml ${debug}" + fi + + common_logger "Wazuh dashboard web application initialized." + common_logger -nl "--- Summary ---" + common_logger -nl "You can access the web interface https://${print_ip}:${http_port}\n User: admin\n Password: ${u_pass}" + + else + flag="-w" + if [ -z "${force}" ]; then + flag="-e" + fi + failed_nodes=() + common_logger "${flag}" "Cannot connect to Wazuh dashboard." + + for i in "${!indexer_node_ips[@]}"; do + curl=$(common_curl -XGET https://"${indexer_node_ips[i]}":9200/ -uadmin:"${u_pass}" -k -s --max-time 300 --retry 5 --retry-delay 5 --fail) + exit_code=${PIPESTATUS[0]} + if [[ "${exit_code}" -eq "7" ]]; then + failed_connect=1 + failed_nodes+=("${indexer_node_names[i]}") + elif [ "${exit_code}" -eq "22" ]; then + sec_not_initialized=1 + fi + done + if [ -n "${failed_connect}" ]; then + common_logger "${flag}" "Failed to connect with ${failed_nodes[*]}. Connection refused." + fi + + if [ -n "${sec_not_initialized}" ]; then + common_logger "${flag}" "Wazuh indexer security settings not initialized. Please run the installation assistant using -s|--start-cluster in one of the wazuh indexer nodes." + fi + + if [ -z "${force}" ]; then + common_logger "If you want to install Wazuh dashboard without waiting for the Wazuh indexer cluster, use the -fd option" + installCommon_rollBack + exit 1 + else + common_logger -nl "--- Summary ---" + common_logger -nl "When Wazuh dashboard is able to connect to your Wazuh indexer cluster, you can access the web interface https://${print_ip}\n User: admin\n Password: ${u_pass}" + fi + fi + +} + +function dashboard_initializeAIO() { + + wazuh_api_address=${server_node_ips[0]} + common_logger "Initializing Wazuh dashboard web application." + installCommon_getPass "admin" + http_code=$(curl -XGET https://localhost:"${http_port}"/status -uadmin:"${u_pass}" -k -w %"{http_code}" -s -o /dev/null) + retries=0 + max_dashboard_initialize_retries=20 + while [ "${http_code}" -ne "200" ] && [ "${retries}" -lt "${max_dashboard_initialize_retries}" ] + do + http_code=$(curl -XGET https://localhost:"${http_port}"/status -uadmin:"${u_pass}" -k -w %"{http_code}" -s -o /dev/null) + common_logger "Wazuh dashboard web application not yet initialized. Waiting..." + retries=$((retries+1)) + sleep 15 + done + if [ "${http_code}" -eq "200" ]; then + if [ -f "/usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml" ]; then + eval "sed -i 's,url: https://localhost,url: https://${wazuh_api_address},g' /usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml ${debug}" + fi + common_logger "Wazuh dashboard web application initialized." + common_logger -nl "--- Summary ---" + common_logger -nl "You can access the web interface https://:${http_port}\n User: admin\n Password: ${u_pass}" + else + common_logger -e "Wazuh dashboard installation failed." + installCommon_rollBack + exit 1 + fi +} + +function dashboard_install() { + + common_logger "Starting Wazuh dashboard installation." + if [ "${sys_type}" == "yum" ]; then + installCommon_yumInstall "wazuh-dashboard" "${wazuh_version}-*" + elif [ "${sys_type}" == "apt-get" ]; then + installCommon_aptInstall "wazuh-dashboard" "${wazuh_version}-*" + fi + common_checkInstalled + if [ "$install_result" != 0 ] || [ -z "${dashboard_installed}" ]; then + common_logger -e "Wazuh dashboard installation failed." + installCommon_rollBack + exit 1 + else + common_logger "Wazuh dashboard installation finished." + fi + +} diff --git a/unattended_installer/install_functions/filebeat.sh b/unattended_installer/install_functions/filebeat.sh new file mode 100644 index 0000000..9fef47d --- /dev/null +++ b/unattended_installer/install_functions/filebeat.sh @@ -0,0 +1,132 @@ +# Wazuh installer - filebeat.sh functions. +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +function filebeat_checkService() { + common_logger "Checking Filebeat connection" + + if filebeat test output | grep -q -i -w "ERROR"; then + common_logger -e "Filebeat connection Error." + eval "filebeat test output x ${debug}" + installCommon_rollBack + exit 1 + else + common_logger "Filebeat connection successful" + fi +} + +function filebeat_configure(){ + + common_logger -d "Configuring Filebeat." + + if [ -z "${offline_install}" ]; then + eval "common_curl -sSo /etc/filebeat/wazuh-template.json ${filebeat_wazuh_template} --max-time 300 --retry 5 --retry-delay 5 --fail" + if [ ! -f "/etc/filebeat/wazuh-template.json" ]; then + common_logger -e "Error downloading wazuh-template.json file." + installCommon_rollBack + exit 1 + fi + common_logger -d "Filebeat template was download successfully." + + eval "(common_curl -sS ${filebeat_wazuh_module} --max-time 300 --retry 5 --retry-delay 5 --fail | tar -xvz -C /usr/share/filebeat/module) ${debug}" + if [ ! -d "/usr/share/filebeat/module" ]; then + common_logger -e "Error downloading wazuh filebeat module." + installCommon_rollBack + exit 1 + fi + common_logger -d "Filebeat module was downloaded successfully." + else + eval "cp ${offline_files_path}/wazuh-template.json /etc/filebeat/wazuh-template.json ${debug}" + eval "tar -xvzf ${offline_files_path}/wazuh-filebeat-*.tar.gz -C /usr/share/filebeat/module ${debug}" + fi + + eval "chmod go+r /etc/filebeat/wazuh-template.json ${debug}" + if [ -n "${AIO}" ]; then + eval "installCommon_getConfig filebeat/filebeat_unattended.yml /etc/filebeat/filebeat.yml ${debug}" + else + eval "installCommon_getConfig filebeat/filebeat_distributed.yml /etc/filebeat/filebeat.yml ${debug}" + if [ ${#indexer_node_names[@]} -eq 1 ]; then + echo -e "\noutput.elasticsearch.hosts:" >> /etc/filebeat/filebeat.yml + echo " - ${indexer_node_ips[0]}:9200" >> /etc/filebeat/filebeat.yml + else + echo -e "\noutput.elasticsearch.hosts:" >> /etc/filebeat/filebeat.yml + for i in "${indexer_node_ips[@]}"; do + echo " - ${i}:9200" >> /etc/filebeat/filebeat.yml + done + fi + fi + + eval "mkdir /etc/filebeat/certs ${debug}" + filebeat_copyCertificates + + eval "filebeat keystore create ${debug}" + eval "(echo admin | filebeat keystore add username --force --stdin)" "${debug}" + eval "(echo admin | filebeat keystore add password --force --stdin)" "${debug}" + + common_logger "Filebeat post-install configuration finished." +} + +function filebeat_copyCertificates() { + + common_logger -d "Copying Filebeat certificates." + if [ -f "${tar_file}" ]; then + if [ -n "${AIO}" ]; then + if ! tar -tvf "${tar_file}" | grep -q "${server_node_names[0]}" ; then + common_logger -e "Tar file does not contain certificate for the node ${server_node_names[0]}." + installCommon_rollBack + exit 1 + fi + eval "sed -i s/filebeat.pem/${server_node_names[0]}.pem/ /etc/filebeat/filebeat.yml ${debug}" + eval "sed -i s/filebeat-key.pem/${server_node_names[0]}-key.pem/ /etc/filebeat/filebeat.yml ${debug}" + eval "tar -xf ${tar_file} -C ${filebeat_cert_path} --wildcards wazuh-install-files/${server_node_names[0]}.pem --strip-components 1 ${debug}" + eval "tar -xf ${tar_file} -C ${filebeat_cert_path} --wildcards wazuh-install-files/${server_node_names[0]}-key.pem --strip-components 1 ${debug}" + eval "tar -xf ${tar_file} -C ${filebeat_cert_path} wazuh-install-files/root-ca.pem --strip-components 1 ${debug}" + eval "rm -rf ${filebeat_cert_path}/wazuh-install-files/ ${debug}" + else + if ! tar -tvf "${tar_file}" | grep -q "${winame}" ; then + common_logger -e "Tar file does not contain certificate for the node ${winame}." + installCommon_rollBack + exit 1 + fi + eval "sed -i s/filebeat.pem/${winame}.pem/ /etc/filebeat/filebeat.yml ${debug}" + eval "sed -i s/filebeat-key.pem/${winame}-key.pem/ /etc/filebeat/filebeat.yml ${debug}" + eval "tar -xf ${tar_file} -C ${filebeat_cert_path} wazuh-install-files/${winame}.pem --strip-components 1 ${debug}" + eval "tar -xf ${tar_file} -C ${filebeat_cert_path} wazuh-install-files/${winame}-key.pem --strip-components 1 ${debug}" + eval "tar -xf ${tar_file} -C ${filebeat_cert_path} wazuh-install-files/root-ca.pem --strip-components 1 ${debug}" + eval "rm -rf ${filebeat_cert_path}/wazuh-install-files/ ${debug}" + fi + eval "chmod 500 ${filebeat_cert_path} ${debug}" + eval "chmod 400 ${filebeat_cert_path}/* ${debug}" + eval "chown root:root ${filebeat_cert_path}/* ${debug}" + else + common_logger -e "No certificates found. Could not initialize Filebeat" + installCommon_rollBack + exit 1 + fi + +} + +function filebeat_install() { + + common_logger "Starting Filebeat installation." + if [ "${sys_type}" == "yum" ]; then + installCommon_yumInstall "filebeat" "${filebeat_version}" + elif [ "${sys_type}" == "apt-get" ]; then + installCommon_aptInstall "filebeat" "${filebeat_version}" + fi + + install_result="${PIPESTATUS[0]}" + common_checkInstalled + if [ "$install_result" != 0 ] || [ -z "${filebeat_installed}" ]; then + common_logger -e "Filebeat installation failed." + installCommon_rollBack + exit 1 + else + common_logger "Filebeat installation finished." + fi + +} diff --git a/unattended_installer/install_functions/indexer.sh b/unattended_installer/install_functions/indexer.sh new file mode 100644 index 0000000..5345fd2 --- /dev/null +++ b/unattended_installer/install_functions/indexer.sh @@ -0,0 +1,218 @@ +# Wazuh installer - indexer.sh functions. +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +function indexer_configure() { + + common_logger -d "Configuring Wazuh indexer." + eval "export JAVA_HOME=/usr/share/wazuh-indexer/jdk/" + + # Configure JVM options for Wazuh indexer + ram_gb=$(free -m | awk 'FNR == 2 {print $2}') + ram="$(( ram_mb / 2 ))" + + if [ "${ram}" -eq "0" ]; then + ram=1024; + fi + eval "sed -i "s/-Xms1g/-Xms${ram}m/" /etc/wazuh-indexer/jvm.options ${debug}" + eval "sed -i "s/-Xmx1g/-Xmx${ram}m/" /etc/wazuh-indexer/jvm.options ${debug}" + + if [ -n "${AIO}" ]; then + eval "installCommon_getConfig indexer/indexer_all_in_one.yml /etc/wazuh-indexer/opensearch.yml ${debug}" + else + eval "installCommon_getConfig indexer/indexer_unattended_distributed.yml /etc/wazuh-indexer/opensearch.yml ${debug}" + if [ "${#indexer_node_names[@]}" -eq 1 ]; then + pos=0 + { + echo "node.name: ${indxname}" + echo "network.host: ${indexer_node_ips[0]}" + echo "cluster.initial_master_nodes: ${indxname}" + echo "plugins.security.nodes_dn:" + echo ' - CN='"${indxname}"',OU=Wazuh,O=Wazuh,L=California,C=US' + } >> /etc/wazuh-indexer/opensearch.yml + else + echo "node.name: ${indxname}" >> /etc/wazuh-indexer/opensearch.yml + echo "cluster.initial_master_nodes:" >> /etc/wazuh-indexer/opensearch.yml + for i in "${indexer_node_names[@]}"; do + echo " - ${i}" >> /etc/wazuh-indexer/opensearch.yml + done + + echo "discovery.seed_hosts:" >> /etc/wazuh-indexer/opensearch.yml + for i in "${indexer_node_ips[@]}"; do + echo " - ${i}" >> /etc/wazuh-indexer/opensearch.yml + done + + for i in "${!indexer_node_names[@]}"; do + if [[ "${indexer_node_names[i]}" == "${indxname}" ]]; then + pos="${i}"; + fi + done + + echo "network.host: ${indexer_node_ips[pos]}" >> /etc/wazuh-indexer/opensearch.yml + + echo "plugins.security.nodes_dn:" >> /etc/wazuh-indexer/opensearch.yml + for i in "${indexer_node_names[@]}"; do + echo " - CN=${i},OU=Wazuh,O=Wazuh,L=California,C=US" >> /etc/wazuh-indexer/opensearch.yml + done + fi + fi + + indexer_copyCertificates + + jv=$(java -version 2>&1 | grep -o -m1 '1.8.0' ) + if [ "$jv" == "1.8.0" ]; then + { + echo "wazuh-indexer hard nproc 4096" + echo "wazuh-indexer soft nproc 4096" + echo "wazuh-indexer hard nproc 4096" + echo "wazuh-indexer soft nproc 4096" + } >> /etc/security/limits.conf + echo -ne "\nbootstrap.system_call_filter: false" >> /etc/wazuh-indexer/opensearch.yml + fi + + common_logger "Wazuh indexer post-install configuration finished." +} + +function indexer_copyCertificates() { + + common_logger -d "Copying Wazuh indexer certificates." + eval "rm -f ${indexer_cert_path}/* ${debug}" + name=${indexer_node_names[pos]} + + if [ -f "${tar_file}" ]; then + if ! tar -tvf "${tar_file}" | grep -q "${name}" ; then + common_logger -e "Tar file does not contain certificate for the node ${name}." + installCommon_rollBack + exit 1; + fi + eval "mkdir ${indexer_cert_path} ${debug}" + eval "sed -i s/indexer.pem/${name}.pem/ /etc/wazuh-indexer/opensearch.yml ${debug}" + eval "sed -i s/indexer-key.pem/${name}-key.pem/ /etc/wazuh-indexer/opensearch.yml ${debug}" + eval "tar -xf ${tar_file} -C ${indexer_cert_path} wazuh-install-files/${name}.pem --strip-components 1 ${debug}" + eval "tar -xf ${tar_file} -C ${indexer_cert_path} wazuh-install-files/${name}-key.pem --strip-components 1 ${debug}" + eval "tar -xf ${tar_file} -C ${indexer_cert_path} wazuh-install-files/root-ca.pem --strip-components 1 ${debug}" + eval "tar -xf ${tar_file} -C ${indexer_cert_path} wazuh-install-files/admin.pem --strip-components 1 ${debug}" + eval "tar -xf ${tar_file} -C ${indexer_cert_path} wazuh-install-files/admin-key.pem --strip-components 1 ${debug}" + eval "rm -rf ${indexer_cert_path}/wazuh-install-files/ ${debug}" + eval "chown -R wazuh-indexer:wazuh-indexer ${indexer_cert_path} ${debug}" + eval "chmod 500 ${indexer_cert_path} ${debug}" + eval "chmod 400 ${indexer_cert_path}/* ${debug}" + else + common_logger -e "No certificates found. Could not initialize Wazuh indexer" + installCommon_rollBack + exit 1; + fi + +} + +function indexer_initialize() { + + common_logger "Initializing Wazuh indexer cluster security settings." + eval "common_curl -XGET https://"${indexer_node_ips[pos]}":9200/ -uadmin:admin -k --max-time 120 --silent --output /dev/null" + e_code="${PIPESTATUS[0]}" + + if [ "${e_code}" -ne "0" ]; then + common_logger -e "Cannot initialize Wazuh indexer cluster." + installCommon_rollBack + exit 1 + fi + + if [ -n "${AIO}" ]; then + eval "sudo -u wazuh-indexer JAVA_HOME=/usr/share/wazuh-indexer/jdk/ OPENSEARCH_CONF_DIR=/etc/wazuh-indexer /usr/share/wazuh-indexer/plugins/opensearch-security/tools/securityadmin.sh -cd /etc/wazuh-indexer/opensearch-security -icl -p 9200 -nhnv -cacert ${indexer_cert_path}/root-ca.pem -cert ${indexer_cert_path}/admin.pem -key ${indexer_cert_path}/admin-key.pem -h 127.0.0.1 ${debug}" + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "The Wazuh indexer cluster security configuration could not be initialized." + installCommon_rollBack + exit 1 + else + common_logger "Wazuh indexer cluster security configuration initialized." + fi + fi + + if [ "${#indexer_node_names[@]}" -eq 1 ] && [ -z "${AIO}" ]; then + installCommon_changePasswords + fi + + common_logger "Wazuh indexer cluster initialized." + +} + +function indexer_install() { + + common_logger "Starting Wazuh indexer installation." + + if [ "${sys_type}" == "yum" ]; then + installCommon_yumInstall "wazuh-indexer" "${wazuh_version}-*" + elif [ "${sys_type}" == "apt-get" ]; then + installCommon_aptInstall "wazuh-indexer" "${wazuh_version}-*" + fi + + common_checkInstalled + if [ "$install_result" != 0 ] || [ -z "${indexer_installed}" ]; then + common_logger -e "Wazuh indexer installation failed." + installCommon_rollBack + exit 1 + else + common_logger "Wazuh indexer installation finished." + fi + + eval "sysctl -q -w vm.max_map_count=262144 ${debug}" + +} + +function indexer_startCluster() { + + common_logger -d "Starting Wazuh indexer cluster." + for ip_to_test in "${indexer_node_ips[@]}"; do + eval "common_curl -XGET https://"${ip_to_test}":9200/ -k -s -o /dev/null" + e_code="${PIPESTATUS[0]}" + + if [ "${e_code}" -eq "7" ]; then + common_logger -e "Connectivity check failed on node ${ip_to_test} port 9200. Possible causes: Wazuh indexer not installed on the node, the Wazuh indexer service is not running or you have connectivity issues with that node. Please check this before trying again." + exit 1 + fi + done + + eval "wazuh_indexer_ip=( $(cat /etc/wazuh-indexer/opensearch.yml | grep network.host | sed 's/network.host:\s//') )" + eval "sudo -u wazuh-indexer JAVA_HOME=/usr/share/wazuh-indexer/jdk/ OPENSEARCH_CONF_DIR=/etc/wazuh-indexer /usr/share/wazuh-indexer/plugins/opensearch-security/tools/securityadmin.sh -cd /etc/wazuh-indexer/opensearch-security -icl -p 9200 -nhnv -cacert /etc/wazuh-indexer/certs/root-ca.pem -cert /etc/wazuh-indexer/certs/admin.pem -key /etc/wazuh-indexer/certs/admin-key.pem -h ${wazuh_indexer_ip} ${debug}" + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "The Wazuh indexer cluster security configuration could not be initialized." + installCommon_rollBack + exit 1 + else + common_logger "Wazuh indexer cluster security configuration initialized." + fi + + # Validate Wazuh indexer security admin it is initialized + indexer_security_admin_comm="common_curl -XGET https://"${indexer_node_ips[pos]}":9200/ -uadmin:admin -k --max-time 120 --silent -w \"%{http_code}\" --output /dev/null" + http_status=$(eval "${indexer_security_admin_comm}") + retries=0 + max_retries=5 + while [ "${http_status}" -ne 200 ]; do + common_logger -d "Waiting for Wazuh indexer to be ready. wazuh-indexer status: ${http_status}" + sleep 5 + retries=$((retries+1)) + if [ "${retries}" -eq "${max_retries}" ]; then + common_logger -e "The Wazuh indexer cluster security configuration could not be initialized." + exit 1 + fi + http_status=$(eval "${indexer_security_admin_comm}") + done + + # Wazuh alerts template injection + if [ -n "${offline_install}" ]; then + filebeat_wazuh_template="file://${offline_files_path}/wazuh-template.json" + fi + http_status=$(eval "common_curl --silent '${filebeat_wazuh_template}' --max-time 300 --retry 5 --retry-delay 5" | eval "common_curl -X PUT 'https://${indexer_node_ips[pos]}:9200/_template/wazuh' -H \'Content-Type: application/json\' -d @- -uadmin:admin -k --max-time 300 --silent --retry 5 --retry-delay 5 -w "%{http_code}" -o /dev/null") + if [ "${http_status}" -ne 200 ]; then + common_logger -e "The wazuh-alerts template could not be inserted into the Wazuh indexer cluster." + exit 1 + else + common_logger -d "Inserted wazuh-alerts template into the Wazuh indexer cluster." + fi + + +} diff --git a/unattended_installer/install_functions/installCommon.sh b/unattended_installer/install_functions/installCommon.sh new file mode 100644 index 0000000..6bbd2c9 --- /dev/null +++ b/unattended_installer/install_functions/installCommon.sh @@ -0,0 +1,938 @@ +# Wazuh installer - common.sh functions. +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +function installCommon_addCentOSRepository() { + + local repo_name="$1" + local repo_description="$2" + local repo_baseurl="$3" + + echo "[$repo_name]" >> "${centos_repo}" + echo "name=${repo_description}" >> "${centos_repo}" + echo "baseurl=${repo_baseurl}" >> "${centos_repo}" + echo 'gpgcheck=1' >> "${centos_repo}" + echo 'enabled=1' >> "${centos_repo}" + echo "gpgkey=file://${centos_key}" >> "${centos_repo}" + echo '' >> "${centos_repo}" + +} + +function installCommon_cleanExit() { + + rollback_conf="" + + if [ -n "$spin_pid" ]; then + eval "kill -9 $spin_pid ${debug}" + fi + + until [[ "${rollback_conf}" =~ ^[N|Y|n|y]$ ]]; do + echo -ne "\nDo you want to remove the ongoing installation?[Y/N]" + read -r rollback_conf + done + if [[ "${rollback_conf}" =~ [N|n] ]]; then + exit 1 + else + common_checkInstalled + installCommon_rollBack + exit 1 + fi + +} + +function installCommon_addWazuhRepo() { + + common_logger -d "Adding the Wazuh repository." + + if [ -n "${development}" ]; then + if [ "${sys_type}" == "yum" ]; then + eval "rm -f /etc/yum.repos.d/wazuh.repo ${debug}" + elif [ "${sys_type}" == "apt-get" ]; then + eval "rm -f /etc/apt/sources.list.d/wazuh.list ${debug}" + fi + fi + + if [ ! -f "/etc/yum.repos.d/wazuh.repo" ] && [ ! -f "/etc/zypp/repos.d/wazuh.repo" ] && [ ! -f "/etc/apt/sources.list.d/wazuh.list" ] ; then + if [ "${sys_type}" == "yum" ]; then + eval "rpm --import ${repogpg} ${debug}" + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "Cannot import Wazuh GPG key" + exit 1 + fi + eval "(echo -e '[wazuh]\ngpgcheck=1\ngpgkey=${repogpg}\nenabled=1\nname=EL-\${releasever} - Wazuh\nbaseurl='${repobaseurl}'/yum/\nprotect=1' | tee /etc/yum.repos.d/wazuh.repo)" "${debug}" + eval "chmod 644 /etc/yum.repos.d/wazuh.repo ${debug}" + elif [ "${sys_type}" == "apt-get" ]; then + eval "common_curl -s ${repogpg} --max-time 300 --retry 5 --retry-delay 5 --fail | gpg --no-default-keyring --keyring gnupg-ring:/usr/share/keyrings/wazuh.gpg --import - ${debug}" + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "Cannot import Wazuh GPG key" + exit 1 + fi + eval "chmod 644 /usr/share/keyrings/wazuh.gpg ${debug}" + eval "(echo \"deb [signed-by=/usr/share/keyrings/wazuh.gpg] ${repobaseurl}/apt/ ${reporelease} main\" | tee /etc/apt/sources.list.d/wazuh.list)" "${debug}" + eval "apt-get update -q ${debug}" + eval "chmod 644 /etc/apt/sources.list.d/wazuh.list ${debug}" + fi + else + common_logger -d "Wazuh repository already exists. Skipping addition." + fi + + if [ -n "${development}" ]; then + common_logger "Wazuh development repository added." + else + common_logger "Wazuh repository added." + fi +} + +function installCommon_aptInstall() { + + package="${1}" + version="${2}" + attempt=0 + if [ -n "${version}" ]; then + installer=${package}${sep}${version} + else + installer=${package} + fi + + # Offline installation case: get package name and install it + if [ -n "${offline_install}" ]; then + package_name=$(ls ${offline_packages_path} | grep ${package}) + installer="${offline_packages_path}/${package_name}" + fi + + command="DEBIAN_FRONTEND=noninteractive apt-get install ${installer} -y -q" + common_checkAptLock + + if [ "${attempt}" -ne "${max_attempts}" ]; then + apt_output=$(eval "${command} 2>&1") + install_result="${PIPESTATUS[0]}" + eval "echo \${apt_output} ${debug}" + fi + +} + +function installCommon_aptInstallList(){ + + dependencies=("$@") + not_installed=() + + for dep in "${dependencies[@]}"; do + if ! apt list --installed 2>/dev/null | grep -q -E ^"${dep}"\/; then + not_installed+=("${dep}") + for wia_dep in "${wia_apt_dependencies[@]}"; do + if [ "${wia_dep}" == "${dep}" ]; then + wia_dependencies_installed+=("${dep}") + fi + done + fi + done + + if [ "${#not_installed[@]}" -gt 0 ]; then + common_logger "--- Dependencies ----" + for dep in "${not_installed[@]}"; do + common_logger "Installing $dep." + installCommon_aptInstall "${dep}" + if [ "${install_result}" != 0 ]; then + common_logger -e "Cannot install dependency: ${dep}." + installCommon_rollBack + exit 1 + fi + done + fi + +} + +function installCommon_changePasswordApi() { + + common_logger -d "Changing API passwords." + + #Change API password tool + if [ -n "${changeall}" ]; then + for i in "${!api_passwords[@]}"; do + if [ -n "${wazuh}" ] || [ -n "${AIO}" ]; then + passwords_getApiUserId "${api_users[i]}" + WAZUH_PASS_API='{\"password\":\"'"${api_passwords[i]}"'\"}' + eval 'common_curl -s -k -X PUT -H \"Authorization: Bearer $TOKEN_API\" -H \"Content-Type: application/json\" -d "$WAZUH_PASS_API" "https://localhost:55000/security/users/${user_id}" -o /dev/null --max-time 300 --retry 5 --retry-delay 5 --fail' + if [ "${api_users[i]}" == "${adminUser}" ]; then + sleep 1 + adminPassword="${api_passwords[i]}" + passwords_getApiToken + fi + fi + if [ "${api_users[i]}" == "wazuh-wui" ] && { [ -n "${dashboard}" ] || [ -n "${AIO}" ]; }; then + passwords_changeDashboardApiPassword "${api_passwords[i]}" + fi + done + else + if [ -n "${wazuh}" ] || [ -n "${AIO}" ]; then + passwords_getApiUserId "${nuser}" + WAZUH_PASS_API='{\"password\":\"'"${password}"'\"}' + eval 'common_curl -s -k -X PUT -H \"Authorization: Bearer $TOKEN_API\" -H \"Content-Type: application/json\" -d "$WAZUH_PASS_API" "https://localhost:55000/security/users/${user_id}" -o /dev/null --max-time 300 --retry 5 --retry-delay 5 --fail' + fi + if [ "${nuser}" == "wazuh-wui" ] && { [ -n "${dashboard}" ] || [ -n "${AIO}" ]; }; then + passwords_changeDashboardApiPassword "${password}" + fi + fi + +} + +function installCommon_createCertificates() { + + common_logger -d "Creating Wazuh certificates." + if [ -n "${AIO}" ]; then + eval "installCommon_getConfig certificate/config_aio.yml ${config_file} ${debug}" + fi + + cert_readConfig + + if [ -d /tmp/wazuh-certificates/ ]; then + eval "rm -rf /tmp/wazuh-certificates/ ${debug}" + fi + eval "mkdir /tmp/wazuh-certificates/ ${debug}" + + cert_tmp_path="/tmp/wazuh-certificates/" + + cert_generateRootCAcertificate + cert_generateAdmincertificate + cert_generateIndexercertificates + cert_generateFilebeatcertificates + cert_generateDashboardcertificates + cert_cleanFiles + eval "chmod 400 /tmp/wazuh-certificates/* ${debug}" + eval "mv /tmp/wazuh-certificates/* /tmp/wazuh-install-files ${debug}" + eval "rm -rf /tmp/wazuh-certificates/ ${debug}" + +} + +function installCommon_createClusterKey() { + + openssl rand -hex 16 >> "/tmp/wazuh-install-files/clusterkey" + +} + +function installCommon_createInstallFiles() { + + if [ -d /tmp/wazuh-install-files ]; then + eval "rm -rf /tmp/wazuh-install-files ${debug}" + fi + + if eval "mkdir /tmp/wazuh-install-files ${debug}"; then + common_logger "Generating configuration files." + + dep="openssl" + if [ "${sys_type}" == "yum" ]; then + installCommon_yumInstallList "${dep}" + elif [ "${sys_type}" == "apt-get" ]; then + installCommon_aptInstallList "${dep}" + fi + + if [ "${#not_installed[@]}" -gt 0 ]; then + wia_dependencies_installed+=("${dep}") + fi + + if [ -n "${configurations}" ]; then + cert_checkOpenSSL + fi + installCommon_createCertificates + if [ -n "${server_node_types[*]}" ]; then + installCommon_createClusterKey + fi + gen_file="/tmp/wazuh-install-files/wazuh-passwords.txt" + passwords_generatePasswordFile + eval "cp '${config_file}' '/tmp/wazuh-install-files/config.yml' ${debug}" + eval "chown root:root /tmp/wazuh-install-files/* ${debug}" + eval "tar -zcf '${tar_file}' -C '/tmp/' wazuh-install-files/ ${debug}" + eval "rm -rf '/tmp/wazuh-install-files' ${debug}" + eval "rm -rf ${config_file} ${debug}" + common_logger "Created ${tar_file_name}. It contains the Wazuh cluster key, certificates, and passwords necessary for installation." + else + common_logger -e "Unable to create /tmp/wazuh-install-files" + exit 1 + fi +} + +function installCommon_changePasswords() { + + common_logger -d "Setting Wazuh indexer cluster passwords." + if [ -f "${tar_file}" ]; then + eval "tar -xf ${tar_file} -C /tmp wazuh-install-files/wazuh-passwords.txt ${debug}" + p_file="/tmp/wazuh-install-files/wazuh-passwords.txt" + common_checkInstalled + if [ -n "${start_indexer_cluster}" ] || [ -n "${AIO}" ]; then + changeall=1 + passwords_readUsers + else + no_indexer_backup=1 + fi + if { [ -n "${wazuh}" ] || [ -n "${AIO}" ]; } && { [ "${server_node_types[pos]}" == "master" ] || [ "${#server_node_names[@]}" -eq 1 ]; }; then + passwords_getApiToken + passwords_getApiUsers + passwords_getApiIds + else + api_users=( wazuh wazuh-wui ) + fi + installCommon_readPasswordFileUsers + else + common_logger -e "Cannot find passwords file. Exiting" + installCommon_rollBack + exit 1 + fi + if [ -n "${start_indexer_cluster}" ] || [ -n "${AIO}" ]; then + passwords_getNetworkHost + passwords_generateHash + fi + + passwords_changePassword + + if [ -n "${start_indexer_cluster}" ] || [ -n "${AIO}" ]; then + passwords_runSecurityAdmin + fi + if [ -n "${wazuh}" ] || [ -n "${dashboard}" ] || [ -n "${AIO}" ]; then + if [ "${server_node_types[pos]}" == "master" ] || [ "${#server_node_names[@]}" -eq 1 ] || [ -n "${dashboard_installed}" ]; then + installCommon_changePasswordApi + fi + fi + +} + +# Adds the CentOS repository to install lsof. +function installCommon_configureCentOSRepositories() { + + centos_repos_configured=1 + centos_key="/etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial" + eval "common_curl -sLo ${centos_key} 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-Official' --max-time 300 --retry 5 --retry-delay 5 --fail" + + if [ ! -f "${centos_key}" ]; then + common_logger -w "The CentOS key could not be added. Some dependencies may not be installed." + else + centos_repo="/etc/yum.repos.d/centos.repo" + eval "touch ${centos_repo} ${debug}" + common_logger -d "CentOS repository file created." + + if [ "${DIST_VER}" == "9" ]; then + installCommon_addCentOSRepository "appstream" "CentOS Stream \$releasever - AppStream" "https://mirror.stream.centos.org/9-stream/AppStream/\$basearch/os/" + installCommon_addCentOSRepository "baseos" "CentOS Stream \$releasever - BaseOS" "https://mirror.stream.centos.org/9-stream/BaseOS/\$basearch/os/" + elif [ "${DIST_VER}" == "8" ]; then + installCommon_addCentOSRepository "extras" "CentOS Linux \$releasever - Extras" "http://vault.centos.org/centos/\$releasever/extras/\$basearch/os/" + installCommon_addCentOSRepository "baseos" "CentOS Linux \$releasever - BaseOS" "http://vault.centos.org/centos/\$releasever/BaseOS/\$basearch/os/" + installCommon_addCentOSRepository "appstream" "CentOS Linux \$releasever - AppStream" "http://vault.centos.org/centos/\$releasever/AppStream/\$basearch/os/" + fi + + common_logger -d "CentOS repositories added." + fi + +} + +function installCommon_extractConfig() { + + common_logger -d "Extracting Wazuh configuration." + if ! tar -tf "${tar_file}" | grep -q wazuh-install-files/config.yml; then + common_logger -e "There is no config.yml file in ${tar_file}." + exit 1 + fi + eval "tar -xf ${tar_file} -C /tmp wazuh-install-files/config.yml ${debug}" + +} + +function installCommon_getConfig() { + + if [ "$#" -ne 2 ]; then + common_logger -e "installCommon_getConfig should be called with two arguments" + exit 1 + fi + + config_name="config_file_$(eval "echo ${1} | sed 's|/|_|g;s|.yml||'")" + if [ -z "$(eval "echo \${${config_name}}")" ]; then + common_logger -e "Unable to find configuration file ${1}. Exiting." + installCommon_rollBack + exit 1 + fi + eval "echo \"\${${config_name}}\"" > "${2}" +} + +function installCommon_getPass() { + + for i in "${!users[@]}"; do + if [ "${users[i]}" == "${1}" ]; then + u_pass=${passwords[i]} + fi + done +} + +function installCommon_installCheckDependencies() { + + common_logger -d "Installing check dependencies." + if [ "${sys_type}" == "yum" ]; then + if [[ "${DIST_NAME}" == "rhel" ]] && [[ "${DIST_VER}" == "8" || "${DIST_VER}" == "9" ]]; then + installCommon_configureCentOSRepositories + fi + installCommon_yumInstallList "${wia_yum_dependencies[@]}" + + # In RHEL cases, remove the CentOS repositories configuration + if [ "${centos_repos_configured}" == 1 ]; then + installCommon_removeCentOSrepositories + fi + + elif [ "${sys_type}" == "apt-get" ]; then + eval "apt-get update -q ${debug}" + installCommon_aptInstallList "${wia_apt_dependencies[@]}" + fi + +} + +function installCommon_installPrerequisites() { + + message="Installing prerequisites dependencies." + if [ "${sys_type}" == "yum" ]; then + if [ "${1}" == "AIO" ]; then + deps=($(echo "${indexer_yum_dependencies[@]}" "${dashboard_yum_dependencies[@]}" | tr ' ' '\n' | sort -u)) + if [ -z "${offline_install}" ]; then + common_logger -d "${message}" + installCommon_yumInstallList "${deps[@]}" + else + offline_checkPrerequisites "${deps[@]}" + fi + fi + if [ "${1}" == "indexer" ]; then + if [ -z "${offline_install}" ]; then + common_logger -d "${message}" + installCommon_yumInstallList "${indexer_yum_dependencies[@]}" + else + offline_checkPrerequisites "${indexer_yum_dependencies[@]}" + fi + fi + if [ "${1}" == "dashboard" ]; then + if [ -z "${offline_install}" ]; then + common_logger -d "${message}" + installCommon_yumInstallList "${dashboard_yum_dependencies[@]}" + else + offline_checkPrerequisites "${dashboard_yum_dependencies[@]}" + fi + fi + elif [ "${sys_type}" == "apt-get" ]; then + if [ -z "${offline_install}" ]; then + eval "apt-get update -q ${debug}" + fi + if [ "${1}" == "AIO" ]; then + deps=($(echo "${wazuh_apt_dependencies[@]}" "${indexer_apt_dependencies[@]}" "${dashboard_apt_dependencies[@]}" | tr ' ' '\n' | sort -u)) + if [ -z "${offline_install}" ]; then + common_logger -d "${message}" + installCommon_aptInstallList "${deps[@]}" + else + offline_checkPrerequisites "${deps[@]}" + fi + fi + if [ "${1}" == "indexer" ]; then + if [ -z "${offline_install}" ]; then + common_logger -d "${message}" + installCommon_aptInstallList "${indexer_apt_dependencies[@]}" + else + offline_checkPrerequisites "${indexer_apt_dependencies[@]}" + fi + fi + if [ "${1}" == "dashboard" ]; then + if [ -z "${offline_install}" ]; then + common_logger -d "${message}" + installCommon_aptInstallList "${dashboard_apt_dependencies[@]}" + else + offline_checkPrerequisites "${dashboard_apt_dependencies[@]}" + fi + fi + if [ "${1}" == "wazuh" ]; then + if [ -z "${offline_install}" ]; then + common_logger -d "${message}" + installCommon_aptInstallList "${wazuh_apt_dependencies[@]}" + else + offline_checkPrerequisites "${wazuh_apt_dependencies[@]}" + fi + fi + fi + +} + +function installCommon_readPasswordFileUsers() { + + filecorrect=$(grep -Ev '^#|^\s*$' "${p_file}" | grep -Pzc "\A(\s*(indexer_username|api_username|indexer_password|api_password):[ \t]+[\'\"]?[\w.*+?-]+[\'\"]?)+\Z") + if [[ "${filecorrect}" -ne 1 ]]; then + common_logger -e "The password file does not have a correct format or password uses invalid characters. Allowed characters: A-Za-z0-9.*+? + +For Wazuh indexer users, the file must have this format: + +# Description + indexer_username: + indexer_password: + +For Wazuh API users, the file must have this format: + +# Description + api_username: + api_password: + +" + installCommon_rollBack + exit 1 + fi + + sfileusers=$(grep indexer_username: "${p_file}" | awk '{ print substr( $2, 1, length($2) ) }' | sed -e "s/[\'\"]//g") + sfilepasswords=$(grep indexer_password: "${p_file}" | awk '{ print substr( $2, 1, length($2) ) }' | sed -e "s/[\'\"]//g") + + sfileapiusers=$(grep api_username: "${p_file}" | awk '{ print substr( $2, 1, length($2) ) }' | sed -e "s/[\'\"]//g") + sfileapipasswords=$(grep api_password: "${p_file}" | awk '{ print substr( $2, 1, length($2) ) }' | sed -e "s/[\'\"]//g") + + + mapfile -t fileusers < <(printf '%s\n' "${sfileusers}") + mapfile -t filepasswords < <(printf '%s\n' "${sfilepasswords}") + mapfile -t fileapiusers < <(printf '%s\n' "${sfileapiusers}") + mapfile -t fileapipasswords < <(printf '%s\n' "${sfileapipasswords}") + + if [ -n "${changeall}" ]; then + for j in "${!fileusers[@]}"; do + supported=false + for i in "${!users[@]}"; do + if [[ ${users[i]} == "${fileusers[j]}" ]]; then + passwords_checkPassword "${filepasswords[j]}" + passwords[i]=${filepasswords[j]} + supported=true + fi + done + if [ "${supported}" = false ] && [ -n "${indexer_installed}" ]; then + common_logger -e -d "The given user ${fileusers[j]} does not exist" + fi + done + + for j in "${!fileapiusers[@]}"; do + supported=false + for i in "${!api_users[@]}"; do + if [[ "${api_users[i]}" == "${fileapiusers[j]}" ]]; then + passwords_checkPassword "${fileapipasswords[j]}" + api_passwords[i]=${fileapipasswords[j]} + supported=true + fi + done + if [ "${supported}" = false ] && [ -n "${indexer_installed}" ]; then + common_logger -e "The Wazuh API user ${fileapiusers[j]} does not exist" + fi + done + else + finalusers=() + finalpasswords=() + + finalapiusers=() + finalapipasswords=() + + if [ -n "${dashboard_installed}" ] && [ -n "${dashboard}" ]; then + users=( kibanaserver admin ) + fi + + if [ -n "${filebeat_installed}" ] && [ -n "${wazuh}" ]; then + users=( admin ) + fi + + for j in "${!fileusers[@]}"; do + supported=false + for i in "${!users[@]}"; do + if [[ "${users[i]}" == "${fileusers[j]}" ]]; then + passwords_checkPassword "${filepasswords[j]}" + finalusers+=(${fileusers[j]}) + finalpasswords+=(${filepasswords[j]}) + supported=true + fi + done + if [ "${supported}" = "false" ] && [ -n "${indexer_installed}" ] && [ -n "${changeall}" ]; then + common_logger -e -d "The given user ${fileusers[j]} does not exist" + fi + done + + for j in "${!fileapiusers[@]}"; do + supported=false + for i in "${!api_users[@]}"; do + if [[ "${api_users[i]}" == "${fileapiusers[j]}" ]]; then + passwords_checkPassword "${fileapipasswords[j]}" + finalapiusers+=("${fileapiusers[j]}") + finalapipasswords+=("${fileapipasswords[j]}") + supported=true + fi + done + if [ ${supported} = false ] && [ -n "${indexer_installed}" ]; then + common_logger -e "The Wazuh API user ${fileapiusers[j]} does not exist" + fi + done + + users=() + mapfile -t users < <(printf '%s\n' "${finalusers[@]}") + mapfile -t passwords < <(printf '%s\n' "${finalpasswords[@]}") + mapfile -t api_users < <(printf '%s\n' "${finalapiusers[@]}") + mapfile -t api_passwords < <(printf '%s\n' "${finalapipasswords[@]}") + changeall=1 + fi + +} + +function installCommon_restoreWazuhrepo() { + + common_logger -d "Restoring Wazuh repository." + if [ -n "${development}" ]; then + if [ "${sys_type}" == "yum" ] && [ -f "/etc/yum.repos.d/wazuh.repo" ]; then + file="/etc/yum.repos.d/wazuh.repo" + elif [ "${sys_type}" == "apt-get" ] && [ -f "/etc/apt/sources.list.d/wazuh.list" ]; then + file="/etc/apt/sources.list.d/wazuh.list" + else + common_logger -w -d "Wazuh repository does not exists." + fi + eval "sed -i 's/-dev//g' ${file} ${debug}" + eval "sed -i 's/pre-release/4.x/g' ${file} ${debug}" + eval "sed -i 's/unstable/stable/g' ${file} ${debug}" + fi + +} + +function installCommon_removeCentOSrepositories() { + + eval "rm -f ${centos_repo} ${debug}" + eval "rm -f ${centos_key} ${debug}" + eval "yum clean all ${debug}" + centos_repos_configured=0 + common_logger -d "CentOS repositories and key deleted." + +} + +function installCommon_rollBack() { + + if [ -z "${uninstall}" ]; then + common_logger "--- Removing existing Wazuh installation ---" + fi + + if [ -f "/etc/yum.repos.d/wazuh.repo" ]; then + eval "rm /etc/yum.repos.d/wazuh.repo ${debug}" + elif [ -f "/etc/zypp/repos.d/wazuh.repo" ]; then + eval "rm /etc/zypp/repos.d/wazuh.repo ${debug}" + elif [ -f "/etc/apt/sources.list.d/wazuh.list" ]; then + eval "rm /etc/apt/sources.list.d/wazuh.list ${debug}" + fi + + if [[ -n "${wazuh_installed}" && ( -n "${wazuh}" || -n "${AIO}" || -n "${uninstall}" ) ]];then + common_logger "Removing Wazuh manager." + if [ "${sys_type}" == "yum" ]; then + common_checkYumLock + if [ "${attempt}" -ne "${max_attempts}" ]; then + eval "yum remove wazuh-manager -y ${debug}" + eval "rpm -q wazuh-manager --quiet && manager_installed=1" + fi + elif [ "${sys_type}" == "apt-get" ]; then + common_checkAptLock + eval "apt-get remove --purge wazuh-manager -y ${debug}" + manager_installed=$(apt list --installed 2>/dev/null | grep wazuh-manager) + fi + + if [ -n "${manager_installed}" ]; then + common_logger -w "The Wazuh manager package could not be removed." + else + common_logger "Wazuh manager removed." + fi + + fi + + if [[ ( -n "${wazuh_remaining_files}" || -n "${wazuh_installed}" ) && ( -n "${wazuh}" || -n "${AIO}" || -n "${uninstall}" ) ]]; then + eval "rm -rf /var/ossec/ ${debug}" + fi + + if [[ -n "${indexer_installed}" && ( -n "${indexer}" || -n "${AIO}" || -n "${uninstall}" ) ]]; then + common_logger "Removing Wazuh indexer." + if [ "${sys_type}" == "yum" ]; then + common_checkYumLock + if [ "${attempt}" -ne "${max_attempts}" ]; then + eval "yum remove wazuh-indexer -y ${debug}" + eval "rpm -q wazuh-indexer --quiet && indexer_installed=1" + fi + elif [ "${sys_type}" == "apt-get" ]; then + common_checkAptLock + eval "apt-get remove --purge wazuh-indexer -y ${debug}" + indexer_installed=$(apt list --installed 2>/dev/null | grep wazuh-indexer) + fi + + if [ -n "${indexer_installed}" ]; then + common_logger -w "The Wazuh indexer package could not be removed." + else + common_logger "Wazuh indexer removed." + fi + fi + + if [[ ( -n "${indexer_remaining_files}" || -n "${indexer_installed}" ) && ( -n "${indexer}" || -n "${AIO}" || -n "${uninstall}" ) ]]; then + eval "rm -rf /var/lib/wazuh-indexer/ ${debug}" + eval "rm -rf /usr/share/wazuh-indexer/ ${debug}" + eval "rm -rf /etc/wazuh-indexer/ ${debug}" + fi + + if [[ -n "${filebeat_installed}" && ( -n "${wazuh}" || -n "${AIO}" || -n "${uninstall}" ) ]]; then + common_logger "Removing Filebeat." + if [ "${sys_type}" == "yum" ]; then + common_checkYumLock + if [ "${attempt}" -ne "${max_attempts}" ]; then + eval "yum remove filebeat -y ${debug}" + eval "rpm -q filebeat --quiet && filebeat_installed=1" + fi + elif [ "${sys_type}" == "apt-get" ]; then + common_checkAptLock + eval "apt-get remove --purge filebeat -y ${debug}" + filebeat_installed=$(apt list --installed 2>/dev/null | grep filebeat) + fi + + if [ -n "${filebeat_installed}" ]; then + common_logger -w "The Filebeat package could not be removed." + else + common_logger "Filebeat removed." + fi + fi + + if [[ ( -n "${filebeat_remaining_files}" || -n "${filebeat_installed}" ) && ( -n "${wazuh}" || -n "${AIO}" || -n "${uninstall}" ) ]]; then + eval "rm -rf /var/lib/filebeat/ ${debug}" + eval "rm -rf /usr/share/filebeat/ ${debug}" + eval "rm -rf /etc/filebeat/ ${debug}" + fi + + if [[ -n "${dashboard_installed}" && ( -n "${dashboard}" || -n "${AIO}" || -n "${uninstall}" ) ]]; then + common_logger "Removing Wazuh dashboard." + if [ "${sys_type}" == "yum" ]; then + common_checkYumLock + if [ "${attempt}" -ne "${max_attempts}" ]; then + eval "yum remove wazuh-dashboard -y ${debug}" + eval "rpm -q wazuh-dashboard --quiet && dashboard_installed=1" + fi + elif [ "${sys_type}" == "apt-get" ]; then + common_checkAptLock + eval "apt-get remove --purge wazuh-dashboard -y ${debug}" + dashboard_installed=$(apt list --installed 2>/dev/null | grep wazuh-dashboard) + fi + + if [ -n "${dashboard_installed}" ]; then + common_logger -w "The Wazuh dashboard package could not be removed." + else + common_logger "Wazuh dashboard removed." + fi + fi + + if [[ ( -n "${dashboard_remaining_files}" || -n "${dashboard_installed}" ) && ( -n "${dashboard}" || -n "${AIO}" || -n "${uninstall}" ) ]]; then + eval "rm -rf /var/lib/wazuh-dashboard/ ${debug}" + eval "rm -rf /usr/share/wazuh-dashboard/ ${debug}" + eval "rm -rf /etc/wazuh-dashboard/ ${debug}" + eval "rm -rf /run/wazuh-dashboard/ ${debug}" + fi + + elements_to_remove=( "/var/log/wazuh-indexer/" + "/var/log/filebeat/" + "/etc/systemd/system/opensearch.service.wants/" + "/securityadmin_demo.sh" + "/etc/systemd/system/multi-user.target.wants/wazuh-manager.service" + "/etc/systemd/system/multi-user.target.wants/filebeat.service" + "/etc/systemd/system/multi-user.target.wants/opensearch.service" + "/etc/systemd/system/multi-user.target.wants/wazuh-dashboard.service" + "/etc/systemd/system/wazuh-dashboard.service" + "/lib/firewalld/services/dashboard.xml" + "/lib/firewalld/services/opensearch.xml" ) + + eval "rm -rf ${elements_to_remove[*]} ${debug}" + + common_remove_gpg_key + + installCommon_removeWIADependencies + + eval "systemctl daemon-reload ${debug}" + + if [ -z "${uninstall}" ]; then + if [ -n "${rollback_conf}" ] || [ -n "${overwrite}" ]; then + common_logger "Installation cleaned." + else + common_logger "Installation cleaned. Check the ${logfile} file to learn more about the issue." + fi + fi + +} + +function installCommon_startService() { + + if [ "$#" -ne 1 ]; then + common_logger -e "installCommon_startService must be called with 1 argument." + exit 1 + fi + + common_logger "Starting service ${1}." + + if [[ -d /run/systemd/system ]]; then + eval "systemctl daemon-reload ${debug}" + eval "systemctl enable ${1}.service ${debug}" + eval "systemctl start ${1}.service ${debug}" + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "${1} could not be started." + if [ -n "$(command -v journalctl)" ]; then + eval "journalctl -u ${1} >> ${logfile}" + fi + installCommon_rollBack + exit 1 + else + common_logger "${1} service started." + fi + elif ps -p 1 -o comm= | grep "init"; then + eval "chkconfig ${1} on ${debug}" + eval "service ${1} start ${debug}" + eval "/etc/init.d/${1} start ${debug}" + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "${1} could not be started." + if [ -n "$(command -v journalctl)" ]; then + eval "journalctl -u ${1} >> ${logfile}" + fi + installCommon_rollBack + exit 1 + else + common_logger "${1} service started." + fi + elif [ -x "/etc/rc.d/init.d/${1}" ] ; then + eval "/etc/rc.d/init.d/${1} start ${debug}" + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "${1} could not be started." + if [ -n "$(command -v journalctl)" ]; then + eval "journalctl -u ${1} >> ${logfile}" + fi + installCommon_rollBack + exit 1 + else + common_logger "${1} service started." + fi + else + common_logger -e "${1} could not start. No service manager found on the system." + exit 1 + fi + +} + +function installCommon_yumInstallList(){ + + dependencies=("$@") + not_installed=() + for dep in "${dependencies[@]}"; do + if ! rpm -q "${dep}" --quiet;then + not_installed+=("${dep}") + for wia_dep in "${wia_yum_dependencies[@]}"; do + if [ "${wia_dep}" == "${dep}" ]; then + wia_dependencies_installed+=("${dep}") + fi + done + fi + done + + if [ "${#not_installed[@]}" -gt 0 ]; then + common_logger "--- Dependencies ---" + for dep in "${not_installed[@]}"; do + common_logger "Installing $dep." + installCommon_yumInstall "${dep}" + yum_code="${PIPESTATUS[0]}" + + eval "echo \${yum_output} ${debug}" + if [ "${yum_code}" != 0 ]; then + common_logger -e "Cannot install dependency: ${dep}." + installCommon_rollBack + exit 1 + fi + done + fi + +} + +function installCommon_removeWIADependencies() { + + if [ "${sys_type}" == "yum" ]; then + installCommon_yumRemoveWIADependencies + elif [ "${sys_type}" == "apt-get" ]; then + installCommon_aptRemoveWIADependencies + fi + +} + +function installCommon_yumRemoveWIADependencies(){ + + if [ "${#wia_dependencies_installed[@]}" -gt 0 ]; then + common_logger "--- Dependencies ---" + for dep in "${wia_dependencies_installed[@]}"; do + if [ "${dep}" != "systemd" ]; then + common_logger "Removing $dep." + yum_output=$(yum remove ${dep} -y 2>&1) + yum_code="${PIPESTATUS[0]}" + + eval "echo \${yum_output} ${debug}" + if [ "${yum_code}" != 0 ]; then + common_logger -e "Cannot remove dependency: ${dep}." + exit 1 + fi + fi + done + fi + +} + +function installCommon_aptRemoveWIADependencies(){ + + if [ "${#wia_dependencies_installed[@]}" -gt 0 ]; then + common_logger "--- Dependencies ----" + for dep in "${wia_dependencies_installed[@]}"; do + if [ "${dep}" != "systemd" ]; then + common_logger "Removing $dep." + apt_output=$(apt-get remove --purge ${dep} -y 2>&1) + apt_code="${PIPESTATUS[0]}" + + eval "echo \${apt_output} ${debug}" + if [ "${apt_code}" != 0 ]; then + common_logger -e "Cannot remove dependency: ${dep}." + exit 1 + fi + fi + done + fi + +} +function installCommon_yumInstall() { + + package="${1}" + version="${2}" + install_result=1 + if [ -n "${version}" ]; then + installer="${package}-${version}" + else + installer="${package}" + fi + + # Offline installation case: get package name and install it + if [ -n "${offline_install}" ]; then + package_name=$(ls ${offline_packages_path} | grep ${package}) + installer="${offline_packages_path}/${package_name}" + command="rpm -ivh ${installer}" + common_logger -d "Installing local package: ${installer}" + else + command="yum install ${installer} -y" + fi + common_checkYumLock + + if [ "${attempt}" -ne "${max_attempts}" ]; then + yum_output=$(eval "${command} 2>&1") + install_result="${PIPESTATUS[0]}" + eval "echo \${yum_output} ${debug}" + fi + +} + + +function installCommon_checkAptLock() { + + attempt=0 + seconds=30 + max_attempts=10 + + while fuser "${apt_lockfile}" >/dev/null 2>&1 && [ "${attempt}" -lt "${max_attempts}" ]; do + attempt=$((attempt+1)) + common_logger "Another process is using APT. Waiting for it to release the lock. Next retry in ${seconds} seconds (${attempt}/${max_attempts})" + sleep "${seconds}" + done + +} diff --git a/unattended_installer/install_functions/installMain.sh b/unattended_installer/install_functions/installMain.sh new file mode 100755 index 0000000..c10dff0 --- /dev/null +++ b/unattended_installer/install_functions/installMain.sh @@ -0,0 +1,425 @@ +# Wazuh installer - main functions +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +function getHelp() { + + echo -e "" + echo -e "NAME" + echo -e " $(basename "$0") - Install and configure Wazuh central components: Wazuh server, Wazuh indexer, and Wazuh dashboard." + echo -e "" + echo -e "SYNOPSIS" + echo -e " $(basename "$0") [OPTIONS] -a | -c | -s | -wi | -wd | -ws " + echo -e "" + echo -e "DESCRIPTION" + echo -e " -a, --all-in-one" + echo -e " Install and configure Wazuh server, Wazuh indexer, Wazuh dashboard." + echo -e "" + echo -e " -c, --config-file " + echo -e " Path to the configuration file used to generate wazuh-install-files.tar file containing the files that will be needed for installation. By default, the Wazuh installation assistant will search for a file named config.yml in the same path as the script." + echo -e "" + echo -e " -dw, --download-wazuh " + echo -e " Download all the packages necessary for offline installation. Type of packages to download for offline installation (rpm, deb)" + echo -e "" + echo -e " -fd, --force-install-dashboard" + echo -e " Force Wazuh dashboard installation to continue even when it is not capable of connecting to the Wazuh indexer." + echo -e "" + echo -e " -g, --generate-config-files" + echo -e " Generate wazuh-install-files.tar file containing the files that will be needed for installation from config.yml. In distributed deployments you will need to copy this file to all hosts." + echo -e "" + echo -e " -h, --help" + echo -e " Display this help and exit." + echo -e "" + echo -e " -i, --ignore-check" + echo -e " Ignore the check for minimum hardware requirements." + echo -e "" + echo -e " -o, --overwrite" + echo -e " Overwrites previously installed components. This will erase all the existing configuration and data." + echo -e "" + echo -e " -of, --offline-installation" + echo -e " Perform an offline installation. This option must be used with -a, -ws, -s, -wi, or -wd." + echo -e "" + echo -e " -p, --port" + echo -e " Specifies the Wazuh web user interface port. By default is the 443 TCP port. Recommended ports are: 8443, 8444, 8080, 8888, 9000." + echo -e "" + echo -e " -s, --start-cluster" + echo -e " Initialize Wazuh indexer cluster security settings." + echo -e "" + echo -e " -t, --tar " + echo -e " Path to tar file containing certificate files. By default, the Wazuh installation assistant will search for a file named wazuh-install-files.tar in the same path as the script." + echo -e "" + echo -e " -u, --uninstall" + echo -e " Uninstalls all Wazuh components. This will erase all the existing configuration and data." + echo -e "" + echo -e " -v, --verbose" + echo -e " Shows the complete installation output." + echo -e "" + echo -e " -V, --version" + echo -e " Shows the version of the script and Wazuh packages." + echo -e "" + echo -e " -wd, --wazuh-dashboard " + echo -e " Install and configure Wazuh dashboard, used for distributed deployments." + echo -e "" + echo -e " -wi, --wazuh-indexer " + echo -e " Install and configure Wazuh indexer, used for distributed deployments." + echo -e "" + echo -e " -ws, --wazuh-server " + echo -e " Install and configure Wazuh manager and Filebeat, used for distributed deployments." + exit 1 + +} + + +function main() { + umask 177 + + if [ -z "${1}" ]; then + getHelp + fi + + while [ -n "${1}" ] + do + case "${1}" in + "-a"|"--all-in-one") + AIO=1 + shift 1 + ;; + "-c"|"--config-file") + if [ -z "${2}" ]; then + common_logger -e "Error on arguments. Probably missing after -c|--config-file" + getHelp + exit 1 + fi + file_conf=1 + config_file="${2}" + shift 2 + ;; + "-fd"|"--force-install-dashboard") + force=1 + shift 1 + ;; + "-g"|"--generate-config-files") + configurations=1 + shift 1 + ;; + "-h"|"--help") + getHelp + ;; + "-i"|"--ignore-check") + ignore=1 + shift 1 + ;; + "-o"|"--overwrite") + overwrite=1 + shift 1 + ;; + "-of"|"--offline-installation") + offline_install=1 + shift 1 + ;; + "-p"|"--port") + if [ -z "${2}" ]; then + common_logger -e "Error on arguments. Probably missing after -p|--port" + getHelp + exit 1 + fi + port_specified=1 + port_number="${2}" + shift 2 + ;; + "-s"|"--start-cluster") + start_indexer_cluster=1 + shift 1 + ;; + "-t"|"--tar") + if [ -z "${2}" ]; then + common_logger -e "Error on arguments. Probably missing after -t|--tar" + getHelp + exit 1 + fi + tar_conf=1 + tar_file="${2}" + shift 2 + ;; + "-u"|"--uninstall") + uninstall=1 + shift 1 + ;; + "-v"|"--verbose") + debugEnabled=1 + debug="2>&1 | tee -a ${logfile}" + shift 1 + ;; + "-V"|"--version") + showVersion=1 + shift 1 + ;; + "-wd"|"--wazuh-dashboard") + if [ -z "${2}" ]; then + common_logger -e "Error on arguments. Probably missing after -wd|---wazuh-dashboard" + getHelp + exit 1 + fi + dashboard=1 + dashname="${2}" + shift 2 + ;; + "-wi"|"--wazuh-indexer") + if [ -z "${2}" ]; then + common_logger -e "Arguments contain errors. Probably missing after -wi|--wazuh-indexer." + getHelp + exit 1 + fi + indexer=1 + indxname="${2}" + shift 2 + ;; + "-ws"|"--wazuh-server") + if [ -z "${2}" ]; then + common_logger -e "Error on arguments. Probably missing after -ws|--wazuh-server" + getHelp + exit 1 + fi + wazuh=1 + winame="${2}" + shift 2 + ;; + "-dw"|"--download-wazuh") + if [ "${2}" != "deb" ] && [ "${2}" != "rpm" ]; then + common_logger -e "Error on arguments. Probably missing after -dw|--download-wazuh" + getHelp + exit 1 + fi + download=1 + package_type="${2}" + shift 2 + ;; + *) + echo "Unknow option: ${1}" + getHelp + esac + done + + cat /dev/null > "${logfile}" + + if [ -z "${download}" ] && [ -z "${showVersion}" ]; then + common_checkRoot + fi + + if [ -n "${showVersion}" ]; then + common_logger "Wazuh version: ${wazuh_version}" + common_logger "Filebeat version: ${filebeat_version}" + common_logger "Wazuh installation assistant version: ${wazuh_install_vesion}" + exit 0 + fi + + common_logger "Starting Wazuh installation assistant. Wazuh version: ${wazuh_version}" + common_logger "Verbose logging redirected to ${logfile}" + +# -------------- Uninstall case ------------------------------------ + + common_checkSystem + + if [ -z "${download}" ]; then + check_dist + fi + + if [ -z "${uninstall}" ] && [ -z "${offline_install}" ]; then + installCommon_installCheckDependencies + elif [ -n "${offline_install}" ]; then + offline_checkDependencies + fi + + common_checkInstalled + checks_arguments + if [ -n "${uninstall}" ]; then + installCommon_rollBack + exit 0 + fi + + checks_arch + if [ -n "${ignore}" ]; then + common_logger -w "Hardware checks ignored." + else + common_logger "Verifying that your system meets the recommended minimum hardware requirements." + checks_health + fi + +# -------------- Preliminary checks and Prerequisites -------------------------------- + + if [ -z "${configurations}" ] && [ -z "${AIO}" ] && [ -z "${download}" ]; then + checks_previousCertificate + fi + + if [ -n "${port_specified}" ]; then + checks_available_port "${port_number}" "${wazuh_aio_ports[@]}" + dashboard_changePort "${port_number}" + elif [ -n "${AIO}" ] || [ -n "${dashboard}" ]; then + dashboard_changePort "${http_port}" + fi + + if [ -n "${AIO}" ]; then + rm -f "${tar_file}" + checks_ports "${wazuh_aio_ports[@]}" + installCommon_installPrerequisites "AIO" + fi + + if [ -n "${indexer}" ]; then + checks_ports "${wazuh_indexer_ports[@]}" + installCommon_installPrerequisites "indexer" + fi + + if [ -n "${wazuh}" ]; then + checks_ports "${wazuh_manager_ports[@]}" + installCommon_installPrerequisites "wazuh" + fi + + if [ -n "${dashboard}" ]; then + checks_ports "${wazuh_dashboard_port}" + installCommon_installPrerequisites "dashboard" + fi + + +# -------------- Wazuh repo ---------------------- + + # Offline installation case: extract the compressed files + if [ -n "${offline_install}" ]; then + offline_checkPreinstallation + offline_extractFiles + fi + + if [ -n "${AIO}" ] || [ -n "${indexer}" ] || [ -n "${dashboard}" ] || [ -n "${wazuh}" ]; then + check_curlVersion + if [ -z "${offline_install}" ]; then + installCommon_addWazuhRepo + fi + fi + +# -------------- Configuration creation case ----------------------- + + # Creation certificate case: Only AIO and -g option can create certificates. + if [ -n "${configurations}" ] || [ -n "${AIO}" ]; then + common_logger "--- Configuration files ---" + installCommon_createInstallFiles + fi + + if [ -z "${configurations}" ] && [ -z "${download}" ]; then + installCommon_extractConfig + config_file="/tmp/wazuh-install-files/config.yml" + cert_readConfig + fi + + # Distributed architecture: node names must be different + if [[ -z "${AIO}" && -z "${download}" && ( -n "${indexer}" || -n "${dashboard}" || -n "${wazuh}" ) ]]; then + checks_names + fi + + if [ -n "${configurations}" ]; then + installCommon_removeWIADependencies + fi + +# -------------- Wazuh indexer case ------------------------------- + + if [ -n "${indexer}" ]; then + common_logger "--- Wazuh indexer ---" + indexer_install + indexer_configure + installCommon_startService "wazuh-indexer" + indexer_initialize + installCommon_removeWIADependencies + fi + +# -------------- Start Wazuh indexer cluster case ------------------ + + if [ -n "${start_indexer_cluster}" ]; then + indexer_startCluster + installCommon_changePasswords + installCommon_removeWIADependencies + fi + +# -------------- Wazuh dashboard case ------------------------------ + + if [ -n "${dashboard}" ]; then + common_logger "--- Wazuh dashboard ----" + dashboard_install + dashboard_configure + installCommon_startService "wazuh-dashboard" + installCommon_changePasswords + dashboard_initialize + installCommon_removeWIADependencies + + fi + +# -------------- Wazuh server case --------------------------------------- + + if [ -n "${wazuh}" ]; then + common_logger "--- Wazuh server ---" + manager_install + manager_configure + if [ -n "${server_node_types[*]}" ]; then + manager_startCluster + fi + installCommon_startService "wazuh-manager" + manager_checkService + filebeat_install + filebeat_configure + installCommon_changePasswords + installCommon_startService "filebeat" + filebeat_checkService + installCommon_removeWIADependencies + fi + +# -------------- AIO case ------------------------------------------ + + if [ -n "${AIO}" ]; then + + common_logger "--- Wazuh indexer ---" + indexer_install + indexer_configure + installCommon_startService "wazuh-indexer" + indexer_initialize + common_logger "--- Wazuh server ---" + manager_install + manager_configure + installCommon_startService "wazuh-manager" + manager_checkService + filebeat_install + filebeat_configure + installCommon_startService "filebeat" + filebeat_checkService + common_logger "--- Wazuh dashboard ---" + dashboard_install + dashboard_configure + installCommon_startService "wazuh-dashboard" + installCommon_changePasswords + dashboard_initializeAIO + installCommon_removeWIADependencies + + fi + +# -------------- Offline case ------------------------------------------ + + if [ -n "${download}" ]; then + common_logger "--- Download Packages ---" + offline_download + fi + + +# ------------------------------------------------------------------- + + if [ -z "${configurations}" ] && [ -z "${download}" ] && [ -z "${offline_install}" ]; then + installCommon_restoreWazuhrepo + fi + + if [ -n "${AIO}" ] || [ -n "${indexer}" ] || [ -n "${dashboard}" ] || [ -n "${wazuh}" ]; then + eval "rm -rf /tmp/wazuh-install-files ${debug}" + common_logger "Installation finished." + elif [ -n "${start_indexer_cluster}" ]; then + common_logger "Wazuh indexer cluster started." + fi + +} diff --git a/unattended_installer/install_functions/installVariables.sh b/unattended_installer/install_functions/installVariables.sh new file mode 100644 index 0000000..19626c1 --- /dev/null +++ b/unattended_installer/install_functions/installVariables.sh @@ -0,0 +1,68 @@ +# Wazuh installer - variables +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +## Package vars +readonly wazuh_major="4.10" +readonly wazuh_version="4.10.0" +readonly filebeat_version="7.10.2" +readonly wazuh_install_vesion="0.1" +readonly source_branch="v${wazuh_version}" + +## Links and paths to resources +readonly resources="https://${bucket}/${wazuh_major}" +readonly base_url="https://${bucket}/${repository}" +base_path="$(dirname "$(readlink -f "$0")")" +readonly base_path +config_file="${base_path}/config.yml" +readonly tar_file_name="wazuh-install-files.tar" +tar_file="${base_path}/${tar_file_name}" + +filebeat_wazuh_template="https://raw.githubusercontent.com/wazuh/wazuh/${source_branch}/extensions/elasticsearch/7.x/wazuh-template.json" + +readonly dashboard_cert_path="/etc/wazuh-dashboard/certs" +readonly filebeat_cert_path="/etc/filebeat/certs" +readonly indexer_cert_path="/etc/wazuh-indexer/certs" + +readonly logfile="/var/log/wazuh-install.log" +debug=">> ${logfile} 2>&1" +readonly yum_lockfile="/var/run/yum.pid" +readonly apt_lockfile="/var/lib/dpkg/lock" + +## Offline Installation vars +readonly base_dest_folder="wazuh-offline" +readonly manager_deb_base_url="${base_url}/apt/pool/main/w/wazuh-manager" +readonly filebeat_deb_base_url="${base_url}/apt/pool/main/f/filebeat" +readonly filebeat_deb_package="filebeat-oss-${filebeat_version}-amd64.deb" +readonly indexer_deb_base_url="${base_url}/apt/pool/main/w/wazuh-indexer" +readonly dashboard_deb_base_url="${base_url}/apt/pool/main/w/wazuh-dashboard" +readonly manager_rpm_base_url="${base_url}/yum" +readonly filebeat_rpm_base_url="${base_url}/yum" +readonly filebeat_rpm_package="filebeat-oss-${filebeat_version}-x86_64.rpm" +readonly indexer_rpm_base_url="${base_url}/yum" +readonly dashboard_rpm_base_url="${base_url}/yum" +readonly wazuh_gpg_key="https://${bucket}/key/GPG-KEY-WAZUH" +readonly filebeat_config_file="${resources}/tpl/wazuh/filebeat/filebeat.yml" + +adminUser="wazuh" +adminPassword="wazuh" + +http_port=443 +wazuh_aio_ports=( 9200 9300 1514 1515 1516 55000 "${http_port}") +readonly wazuh_indexer_ports=( 9200 9300 ) +readonly wazuh_manager_ports=( 1514 1515 1516 55000 ) +wazuh_dashboard_port="${http_port}" +# `lsof` and `openssl` are installed separately +wia_yum_dependencies=( systemd grep tar coreutils sed procps-ng gawk curl ) +readonly wia_apt_dependencies=( systemd grep tar coreutils sed procps gawk curl ) +readonly wazuh_yum_dependencies=( libcap ) +readonly wazuh_apt_dependencies=( apt-transport-https libcap2-bin software-properties-common gnupg ) +readonly indexer_yum_dependencies=( coreutils ) +readonly indexer_apt_dependencies=( debconf adduser procps gnupg apt-transport-https ) +readonly dashboard_yum_dependencies=( libcap ) +readonly dashboard_apt_dependencies=( debhelper tar curl libcap2-bin gnupg apt-transport-https ) +wia_dependencies_installed=() diff --git a/unattended_installer/install_functions/manager.sh b/unattended_installer/install_functions/manager.sh new file mode 100644 index 0000000..a33e564 --- /dev/null +++ b/unattended_installer/install_functions/manager.sh @@ -0,0 +1,102 @@ +# Wazuh installer - manager.sh functions. +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +function manager_startCluster() { + + common_logger -d "Starting Wazuh manager cluster." + for i in "${!server_node_names[@]}"; do + if [[ "${server_node_names[i]}" == "${winame}" ]]; then + pos="${i}"; + fi + done + + for i in "${!server_node_types[@]}"; do + if [[ "${server_node_types[i],,}" == "master" ]]; then + master_address=${server_node_ips[i]} + fi + done + + key=$(tar -axf "${tar_file}" wazuh-install-files/clusterkey -O) + bind_address="0.0.0.0" + port="1516" + hidden="no" + disabled="no" + lstart=$(grep -n "" /var/ossec/etc/ossec.conf | cut -d : -f 1) + lend=$(grep -n "" /var/ossec/etc/ossec.conf | cut -d : -f 1) + + eval 'sed -i -e "${lstart},${lend}s/.*<\/name>/wazuh_cluster<\/name>/" \ + -e "${lstart},${lend}s/.*<\/node_name>/${winame}<\/node_name>/" \ + -e "${lstart},${lend}s/.*<\/node_type>/${server_node_types[pos],,}<\/node_type>/" \ + -e "${lstart},${lend}s/.*<\/key>/${key}<\/key>/" \ + -e "${lstart},${lend}s/.*<\/port>/${port}<\/port>/" \ + -e "${lstart},${lend}s/.*<\/bind_addr>/${bind_address}<\/bind_addr>/" \ + -e "${lstart},${lend}s/.*<\/node>/${master_address}<\/node>/" \ + -e "${lstart},${lend}s/.*<\/hidden>/${hidden}<\/hidden>/" \ + -e "${lstart},${lend}s/.*<\/disabled>/${disabled}<\/disabled>/" \ + /var/ossec/etc/ossec.conf' + +} + +function manager_checkService() { + common_logger "Checking Wazuh API connection" + eval "TOKEN=$(curl -k -s -X POST -u "wazuh-wui:wazuh-wui" https://127.0.0.1:55000/security/user/authenticate/run_as?raw=true -d '{"user_name":"wzread"}' -H "content-type:application/json")" + wm_error=$(curl -k -s -X GET "https://127.0.0.1:55000/agents/outdated?pretty=true" -H "Authorization: Bearer ${TOKEN}") + + if [[ ${wm_error,,} = '"error": 0' ]]; then + common_logger "Wazuh API connection successful" + else + common_logger -e "Wazuh API connection Error. $wm_error" + eval "/var/ossec/bin/wazuh-control status ${debug}" + installCommon_rollBack + exit 1 + fi +} + +function manager_configure(){ + + common_logger -d "Configuring Wazuh manager." + + if [ ${#indexer_node_names[@]} -eq 1 ]; then + eval "sed -i 's/.*<\/host>/https:\/\/${indexer_node_ips[0]}:9200<\/host>/g' /var/ossec/etc/ossec.conf ${debug}" + else + lstart=$(grep -n "" /var/ossec/etc/ossec.conf | cut -d : -f 1) + lend=$(grep -n "" /var/ossec/etc/ossec.conf | cut -d : -f 1) + for i in "${!indexer_node_ips[@]}"; do + if [ $i -eq 0 ]; then + eval "sed -i 's/.*<\/host>/https:\/\/${indexer_node_ips[0]}:9200<\/host>/g' /var/ossec/etc/ossec.conf ${debug}" + else + eval "sed -i '//a\ https:\/\/${indexer_node_ips[$i]}:9200<\/host>' /var/ossec/etc/ossec.conf" + fi + done + fi + eval "sed -i s/filebeat.pem/${server_node_names[0]}.pem/ /var/ossec/etc/ossec.conf ${debug}" + eval "sed -i s/filebeat-key.pem/${server_node_names[0]}-key.pem/ /var/ossec/etc/ossec.conf ${debug}" + common_logger -d "Setting provisional Wazuh indexer password." + eval "/var/ossec/bin/wazuh-keystore -f indexer -k username -v admin" + eval "/var/ossec/bin/wazuh-keystore -f indexer -k password -v admin" + common_logger "Wazuh manager vulnerability detection configuration finished." +} + +function manager_install() { + + common_logger "Starting the Wazuh manager installation." + if [ "${sys_type}" == "yum" ]; then + installCommon_yumInstall "wazuh-manager" "${wazuh_version}-*" + elif [ "${sys_type}" == "apt-get" ]; then + installCommon_aptInstall "wazuh-manager" "${wazuh_version}-*" + fi + + common_checkInstalled + if [ "$install_result" != 0 ] || [ -z "${wazuh_installed}" ]; then + common_logger -e "Wazuh installation failed." + installCommon_rollBack + exit 1 + else + common_logger "Wazuh manager installation finished." + fi +} diff --git a/unattended_installer/install_functions/wazuh-offline-download.sh b/unattended_installer/install_functions/wazuh-offline-download.sh new file mode 100755 index 0000000..cd81f19 --- /dev/null +++ b/unattended_installer/install_functions/wazuh-offline-download.sh @@ -0,0 +1,171 @@ +#!/bin/bash + +# Wazuh installer: offline download +# Copyright (C) 2021, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +function offline_download() { + + common_logger "Starting Wazuh packages download." + common_logger "Downloading Wazuh ${package_type} packages for ${arch}." + dest_path="${base_dest_folder}/wazuh-packages" + + if [ -d "${dest_path}" ]; then + eval "rm -f ${dest_path}/* ${debug}" # Clean folder before downloading specific versions + eval "chmod 700 ${dest_path} ${debug}" + else + eval "mkdir -m700 -p ${dest_path} ${debug}" # Create folder if it does not exist + fi + + packages_to_download=( "manager" "filebeat" "indexer" "dashboard" ) + + manager_revision="1" + indexer_revision="1" + dashboard_revision="1" + + if [ "${package_type}" == "rpm" ]; then + manager_rpm_package="wazuh-manager-${wazuh_version}-${manager_revision}.x86_64.${package_type}" + indexer_rpm_package="wazuh-indexer-${wazuh_version}-${indexer_revision}.x86_64.${package_type}" + dashboard_rpm_package="wazuh-dashboard-${wazuh_version}-${dashboard_revision}.x86_64.${package_type}" + manager_base_url="${manager_rpm_base_url}" + indexer_base_url="${indexer_rpm_base_url}" + dashboard_base_url="${dashboard_rpm_base_url}" + manager_package="${manager_rpm_package}" + indexer_package="${indexer_rpm_package}" + dashboard_package="${dashboard_rpm_package}" + elif [ "${package_type}" == "deb" ]; then + manager_deb_package="wazuh-manager_${wazuh_version}-${manager_revision}_amd64.${package_type}" + indexer_deb_package="wazuh-indexer_${wazuh_version}-${indexer_revision}_amd64.${package_type}" + dashboard_deb_package="wazuh-dashboard_${wazuh_version}-${dashboard_revision}_amd64.${package_type}" + manager_base_url="${manager_deb_base_url}" + indexer_base_url="${indexer_deb_base_url}" + dashboard_base_url="${dashboard_deb_base_url}" + manager_package="${manager_deb_package}" + indexer_package="${indexer_deb_package}" + dashboard_package="${dashboard_deb_package}" + else + common_logger "Unsupported package type: ${package_type}" + exit 1 + fi + + while common_curl -s -I -o /dev/null -w "%{http_code}" "${manager_base_url}/${manager_package}" --max-time 300 --retry 5 --retry-delay 5 --fail | grep -q "200"; do + manager_revision=$((manager_revision+1)) + if [ "${package_type}" == "rpm" ]; then + manager_rpm_package="wazuh-manager-${wazuh_version}-${manager_revision}.x86_64.rpm" + manager_package="${manager_rpm_package}" + else + manager_deb_package="wazuh-manager_${wazuh_version}-${manager_revision}_amd64.deb" + manager_package="${manager_deb_package}" + fi + done + if [ "$manager_revision" -gt 1 ] && [ "$(common_curl -s -I -o /dev/null -w "%{http_code}" "${manager_base_url}/${manager_package}" --max-time 300 --retry 5 --retry-delay 5 --fail)" -ne "200" ]; then + manager_revision=$((manager_revision-1)) + if [ "${package_type}" == "rpm" ]; then + manager_rpm_package="wazuh-manager-${wazuh_version}-${manager_revision}.x86_64.rpm" + else + manager_deb_package="wazuh-manager_${wazuh_version}-${manager_revision}_amd64.deb" + fi + fi + common_logger -d "Wazuh manager package revision fetched." + + while common_curl -s -I -o /dev/null -w "%{http_code}" "${indexer_base_url}/${indexer_package}" --max-time 300 --retry 5 --retry-delay 5 --fail | grep -q "200"; do + indexer_revision=$((indexer_revision+1)) + if [ "${package_type}" == "rpm" ]; then + indexer_rpm_package="wazuh-indexer-${wazuh_version}-${indexer_revision}.x86_64.rpm" + indexer_package="${indexer_rpm_package}" + else + indexer_deb_package="wazuh-indexer_${wazuh_version}-${indexer_revision}_amd64.deb" + indexer_package="${indexer_deb_package}" + fi + done + if [ "$indexer_revision" -gt 1 ] && [ "$(common_curl -s -I -o /dev/null -w "%{http_code}" "${indexer_base_url}/${indexer_package}" --max-time 300 --retry 5 --retry-delay 5 --fail)" -ne "200" ]; then + indexer_revision=$((indexer_revision-1)) + if [ "${package_type}" == "rpm" ]; then + indexer_rpm_package="wazuh-indexer-${wazuh_version}-${indexer_revision}.x86_64.rpm" + else + indexer_deb_package="wazuh-indexer_${wazuh_version}-${indexer_revision}_amd64.deb" + fi + fi + common_logger -d "Wazuh indexer package revision fetched." + + while common_curl -s -I -o /dev/null -w "%{http_code}" "${dashboard_base_url}/${dashboard_package}" --max-time 300 --retry 5 --retry-delay 5 --fail | grep -q "200"; do + dashboard_revision=$((dashboard_revision+1)) + if [ "${package_type}" == "rpm" ]; then + dashboard_rpm_package="wazuh-dashboard-${wazuh_version}-${dashboard_revision}.x86_64.rpm" + dashboard_package="${dashboard_rpm_package}" + else + dashboard_deb_package="wazuh-dashboard_${wazuh_version}-${dashboard_revision}_amd64.deb" + dashboard_package="${dashboard_deb_package}" + fi + done + if [ "$dashboard_revision" -gt 1 ] && [ "$(common_curl -s -I -o /dev/null -w "%{http_code}" "${dashboard_base_url}/${dashboard_package}" --max-time 300 --retry 5 --retry-delay 5 --fail)" -ne "200" ]; then + dashboard_revision=$((dashboard_revision-1)) + if [ "${package_type}" == "rpm" ]; then + dashboard_rpm_package="wazuh-dashboard-${wazuh_version}-${dashboard_revision}.x86_64.rpm" + else + dashboard_deb_package="wazuh-dashboard_${wazuh_version}-${dashboard_revision}_amd64.deb" + fi + fi + common_logger -d "Wazuh dashboard package revision fetched." + + for package in "${packages_to_download[@]}" + do + common_logger -d "Downloading Wazuh ${package} package..." + package_name="${package}_${package_type}_package" + eval "package_base_url=${package}_${package_type}_base_url" + + if output=$(common_curl -sSo "${dest_path}/${!package_name}" "${!package_base_url}/${!package_name}" --max-time 300 --retry 5 --retry-delay 5 --fail 2>&1); then + common_logger "The ${package} package was downloaded." + else + common_logger -e "The ${package} package could not be downloaded. Exiting." + eval "echo \${output} ${debug}" + exit 1 + fi + + done + + common_logger "The packages are in ${dest_path}" + +# -------------------------------------------------- + + common_logger "Downloading configuration files and assets." + dest_path="${base_dest_folder}/wazuh-files" + + if [ -d "${dest_path}" ]; then + eval "rm -f ${dest_path}/* ${debug}" # Clean folder before downloading specific versions + eval "chmod 700 ${dest_path} ${debug}" + else + eval "mkdir -m700 -p ${dest_path} ${debug}" # Create folder if it does not exist + fi + + files_to_download=( "${wazuh_gpg_key}" "${filebeat_config_file}" "${filebeat_wazuh_template}" "${filebeat_wazuh_module}" ) + + eval "cd ${dest_path}" + for file in "${files_to_download[@]}" + do + common_logger -d "Downloading ${file}..." + if output=$(common_curl -sSO ${file} --max-time 300 --retry 5 --retry-delay 5 --fail 2>&1); then + common_logger "The resource ${file} was downloaded." + else + common_logger -e "The resource ${file} could not be downloaded. Exiting." + eval "echo \${output} ${debug}" + exit 1 + fi + + done + eval "cd - > /dev/null" + + eval "chmod 500 ${base_dest_folder} ${debug}" + + common_logger "The configuration files and assets are in wazuh-offline.tar.gz" + + eval "tar -czf ${base_dest_folder}.tar.gz ${base_dest_folder} ${debug}" + eval "chmod -R 700 ${base_dest_folder} && rm -rf ${base_dest_folder} ${debug}" + + common_logger "You can follow the installation guide here https://documentation.wazuh.com/current/deployment-options/offline-installation.html" + +} \ No newline at end of file diff --git a/unattended_installer/install_functions/wazuh-offline-installation.sh b/unattended_installer/install_functions/wazuh-offline-installation.sh new file mode 100644 index 0000000..dab1f82 --- /dev/null +++ b/unattended_installer/install_functions/wazuh-offline-installation.sh @@ -0,0 +1,103 @@ +#!/bin/bash + +# Wazuh installer: offline download +# Copyright (C) 2023, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +# Checks the necessary dependencies for the installation +function offline_checkDependencies() { + + dependencies=( curl tar gnupg openssl lsof ) + + common_logger "Checking installed dependencies for Offline installation." + for dep in "${dependencies[@]}"; do + if [ "${sys_type}" == "yum" ]; then + eval "yum list installed 2>/dev/null | grep -q -E ^"${dep}"\\." + elif [ "${sys_type}" == "apt-get" ]; then + eval "apt list --installed 2>/dev/null | grep -q -E ^"${dep}"\/" + fi + + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "${dep} is necessary for the offline installation." + exit 1 + fi + done + common_logger -d "Offline dependencies are installed." + +} + +# Checks the necessary packages needed for a Wazuh component +function offline_checkPrerequisites(){ + + dependencies=("$@") + common_logger "Checking prerequisites for Offline installation." + for dep in "${dependencies[@]}"; do + if [ "${sys_type}" == "yum" ]; then + eval "yum list installed 2>/dev/null | grep -q -E ^"${dep}"\\." + elif [ "${sys_type}" == "apt-get" ]; then + eval "apt list --installed 2>/dev/null | grep -q -E ^"${dep}"\/" + fi + + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "${dep} is necessary for the offline installation." + exit 1 + fi + done + common_logger -d "Offline prerequisites are installed." +} + +# Checks the necessary files for the installation +function offline_checkPreinstallation() { + + offline_tarfile="${base_dest_folder}.tar.gz" + common_logger "Checking ${offline_tarfile} file." + if [ ! -f "${base_path}/${offline_tarfile}" ]; then + common_logger -e "The ${offline_tarfile} file was not found in ${base_path}." + exit 1 + fi + common_logger -d "${offline_tarfile} was found correctly." + +} + +# Extracts the files for the offline installation and check its content +function offline_extractFiles() { + + common_logger -d "Extracting files from ${offline_tarfile}" + if [ ! -d "${base_path}/wazuh-offline/" ]; then + eval "tar -xzf ${offline_tarfile} ${debug}" + + if [ ! -d "${base_path}/wazuh-offline/" ]; then + common_logger -e "The ${offline_tarfile} file could not be decompressed." + exit 1 + fi + fi + + offline_files_path="${base_path}/wazuh-offline/wazuh-files" + offline_packages_path="${base_path}/wazuh-offline/wazuh-packages" + + required_files=( + "${offline_files_path}/filebeat.yml" + "${offline_files_path}/GPG-KEY-WAZUH" + "${offline_files_path}/wazuh-filebeat-*.tar.gz" + "${offline_files_path}/wazuh-template.json" + ) + + if [ "${sys_type}" == "apt-get" ]; then + required_files+=("${offline_packages_path}/filebeat-oss-*.deb" "${offline_packages_path}/wazuh-dashboard_*.deb" "${offline_packages_path}/wazuh-indexer_*.deb" "${offline_packages_path}/wazuh-manager_*.deb") + elif [ "${sys_type}" == "rpm" ]; then + required_files+=("${offline_packages_path}/filebeat-oss-*.rpm" "${offline_packages_path}/wazuh-dashboard_*.rpm" "${offline_packages_path}/wazuh-indexer_*.rpm" "${offline_packages_path}/wazuh-manager_*.rpm") + fi + + for file in "${required_files[@]}"; do + if ! compgen -G "${file}" > /dev/null; then + common_logger -e "Missing necessary offline file: ${file}" + exit 1 + fi + done + + common_logger -d "Offline files extracted successfully." +} diff --git a/unattended_installer/passwords_tool/passwordsFunctions.sh b/unattended_installer/passwords_tool/passwordsFunctions.sh new file mode 100644 index 0000000..2316640 --- /dev/null +++ b/unattended_installer/passwords_tool/passwordsFunctions.sh @@ -0,0 +1,647 @@ +# Passwords tool - library functions +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +function passwords_changePassword() { + + if [ -n "${changeall}" ]; then + if [ -n "${indexer_installed}" ] && [ -z ${no_indexer_backup} ]; then + eval "mkdir /etc/wazuh-indexer/backup/ ${debug}" + eval "cp /etc/wazuh-indexer/opensearch-security/* /etc/wazuh-indexer/backup/ ${debug}" + passwords_createBackUp + fi + for i in "${!passwords[@]}" + do + if [ -n "${indexer_installed}" ] && [ -f "/etc/wazuh-indexer/backup/internal_users.yml" ]; then + awk -v new='"'"${hashes[i]}"'"' 'prev=="'${users[i]}':"{sub(/\042.*/,""); $0=$0 new} {prev=$1} 1' /etc/wazuh-indexer/backup/internal_users.yml > internal_users.yml_tmp && mv -f internal_users.yml_tmp /etc/wazuh-indexer/backup/internal_users.yml + fi + + if [ "${users[i]}" == "admin" ]; then + adminpass=${passwords[i]} + elif [ "${users[i]}" == "kibanaserver" ]; then + dashpass=${passwords[i]} + fi + + done + else + if [ -z "${api}" ] && [ -n "${indexer_installed}" ]; then + eval "mkdir /etc/wazuh-indexer/backup/ ${debug}" + eval "cp /etc/wazuh-indexer/opensearch-security/* /etc/wazuh-indexer/backup/ ${debug}" + passwords_createBackUp + fi + if [ -n "${indexer_installed}" ] && [ -f "/etc/wazuh-indexer/backup/internal_users.yml" ]; then + awk -v new='"'"${hash}"'"' 'prev=="'${nuser}':"{sub(/\042.*/,""); $0=$0 new} {prev=$1} 1' /etc/wazuh-indexer/backup/internal_users.yml > internal_users.yml_tmp && mv -f internal_users.yml_tmp /etc/wazuh-indexer/backup/internal_users.yml + fi + + if [ "${nuser}" == "admin" ]; then + adminpass=${password} + elif [ "${nuser}" == "kibanaserver" ]; then + dashpass=${password} + fi + + fi + + if [ "${nuser}" == "admin" ] || [ -n "${changeall}" ]; then + if [ -n "${filebeat_installed}" ]; then + file_username=$(grep "username:" /etc/filebeat/filebeat.yml | awk '{print $2}') + file_password=$(grep "password:" /etc/filebeat/filebeat.yml | awk '{print $2}') + if [ "$file_username" != "\${username}" ] || [ "$file_password" != "\${password}" ]; then + common_logger -w "The user and password configured in the filebeat.yml file will be updated and stored in Filebeat Keystore." + fi + eval "echo ${adminpass} | filebeat keystore add password --force --stdin ${debug}" + conf="$(awk '{sub("password: .*", "password: ${password}")}1' /etc/filebeat/filebeat.yml)" + echo "${conf}" > /etc/filebeat/filebeat.yml + eval "echo admin | filebeat keystore add username --force --stdin ${debug}" + conf="$(awk '{sub("username: .*", "username: ${username}")}1' /etc/filebeat/filebeat.yml)" + echo "${conf}" > /etc/filebeat/filebeat.yml + common_logger "The filebeat.yml file has been updated to use the Filebeat Keystore username and password." + passwords_restartService "filebeat" + eval "/var/ossec/bin/wazuh-keystore -f indexer -k password -v ${adminpass}" + passwords_restartService "wazuh-manager" + fi + fi + + if [ "$nuser" == "kibanaserver" ] || [ -n "$changeall" ]; then + if [ -n "${dashboard_installed}" ] && [ -n "${dashpass}" ]; then + if /usr/share/wazuh-dashboard/bin/opensearch-dashboards-keystore --allow-root list | grep -q opensearch.password; then + eval "echo ${dashpass} | /usr/share/wazuh-dashboard/bin/opensearch-dashboards-keystore --allow-root add -f --stdin opensearch.password ${debug_pass} > /dev/null 2>&1" + else + wazuhdashold=$(grep "password:" /etc/wazuh-dashboard/opensearch_dashboards.yml ) + rk="opensearch.password: " + wazuhdashold="${wazuhdashold//$rk}" + conf="$(awk '{sub("opensearch.password: .*", "opensearch.password: '"${dashpass}"'")}1' /etc/wazuh-dashboard/opensearch_dashboards.yml)" + echo "${conf}" > /etc/wazuh-dashboard/opensearch_dashboards.yml + fi + passwords_restartService "wazuh-dashboard" + fi + fi + +} + +function passwords_changePasswordApi() { + #Change API password tool + if [ -n "${changeall}" ]; then + for i in "${!api_passwords[@]}"; do + if [ -n "${wazuh_installed}" ]; then + passwords_getApiUserId "${api_users[i]}" + WAZUH_PASS_API='{\"password\":\"'"${api_passwords[i]}"'\"}' + eval 'common_curl -s -k -X PUT -H \"Authorization: Bearer $TOKEN_API\" -H \"Content-Type: application/json\" -d "$WAZUH_PASS_API" "https://localhost:55000/security/users/${user_id}" -o /dev/null --max-time 300 --retry 5 --retry-delay 5 --fail' + if [ "${api_users[i]}" == "${adminUser}" ]; then + sleep 1 + adminPassword="${api_passwords[i]}" + passwords_getApiToken + fi + if [ -z "${AIO}" ] && [ -z "${indexer}" ] && [ -z "${dashboard}" ] && [ -z "${wazuh}" ] && [ -z "${start_indexer_cluster}" ]; then + common_logger -nl $"The password for Wazuh API user ${api_users[i]} is ${api_passwords[i]}" + fi + fi + if [ "${api_users[i]}" == "wazuh-wui" ] && [ -n "${dashboard_installed}" ]; then + passwords_changeDashboardApiPassword "${api_passwords[i]}" + fi + done + else + if [ -n "${wazuh_installed}" ]; then + passwords_getApiUserId "${nuser}" + WAZUH_PASS_API='{\"password\":\"'"${password}"'\"}' + eval 'common_curl -s -k -X PUT -H \"Authorization: Bearer $TOKEN_API\" -H \"Content-Type: application/json\" -d "$WAZUH_PASS_API" "https://localhost:55000/security/users/${user_id}" -o /dev/null --max-time 300 --retry 5 --retry-delay 5 --fail' + if [ -z "${AIO}" ] && [ -z "${indexer}" ] && [ -z "${dashboard}" ] && [ -z "${wazuh}" ] && [ -z "${start_indexer_cluster}" ]; then + common_logger -nl $"The password for Wazuh API user ${nuser} is ${password}" + fi + fi + if [ "${nuser}" == "wazuh-wui" ] && [ -n "${dashboard_installed}" ]; then + passwords_changeDashboardApiPassword "${password}" + fi + fi +} + +function passwords_changeDashboardApiPassword() { + + j=0 + until [ -n "${file_exists}" ] || [ "${j}" -eq "12" ]; do + if [ -f "/usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml" ]; then + eval "sed -i 's|password: .*|password: \"${1}\"|g' /usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml ${debug}" + if [ -z "${AIO}" ] && [ -z "${indexer}" ] && [ -z "${dashboard}" ] && [ -z "${wazuh}" ] && [ -z "${start_indexer_cluster}" ]; then + common_logger "Updated wazuh-wui user password in wazuh dashboard. Remember to restart the service." + fi + file_exists=1 + fi + sleep 5 + j=$((j+1)) + done + +} + +function passwords_checkUser() { + + if [ -n "${adminUser}" ] && [ -n "${adminPassword}" ]; then + for i in "${!api_users[@]}"; do + if [ "${api_users[i]}" == "${nuser}" ]; then + exists=1 + fi + done + else + for i in "${!users[@]}"; do + if [ "${users[i]}" == "${nuser}" ]; then + exists=1 + fi + done + fi + + if [ -z "${exists}" ]; then + common_logger -e "The given user does not exist" + exit 1; + fi + +} + +function passwords_checkPassword() { + + if ! echo "$1" | grep -q "[A-Z]" || ! echo "$1" | grep -q "[a-z]" || ! echo "$1" | grep -q "[0-9]" || ! echo "$1" | grep -q "[.*+?-]" || [ "${#1}" -lt 8 ] || [ "${#1}" -gt 64 ]; then + common_logger -e "The password must have a length between 8 and 64 characters and contain at least one upper and lower case letter, a number and a symbol(.*+?-)." + if [[ $(type -t installCommon_rollBack) == "function" ]]; then + installCommon_rollBack + fi + exit 1 + fi + +} + +function passwords_createBackUp() { + + if [ -z "${indexer_installed}" ] && [ -z "${dashboard_installed}" ] && [ -z "${filebeat_installed}" ]; then + common_logger -e "Cannot find Wazuh indexer, Wazuh dashboard or Filebeat on the system." + exit 1; + else + if [ -n "${indexer_installed}" ]; then + capem=$(grep "plugins.security.ssl.transport.pemtrustedcas_filepath: " /etc/wazuh-indexer/opensearch.yml ) + rcapem="plugins.security.ssl.transport.pemtrustedcas_filepath: " + capem="${capem//$rcapem}" + fi + fi + + common_logger -d "Creating password backup." + if [ ! -d "/etc/wazuh-indexer/backup" ]; then + eval "mkdir /etc/wazuh-indexer/backup ${debug}" + fi + eval "JAVA_HOME=/usr/share/wazuh-indexer/jdk/ OPENSEARCH_CONF_DIR=/etc/wazuh-indexer /usr/share/wazuh-indexer/plugins/opensearch-security/tools/securityadmin.sh -backup /etc/wazuh-indexer/backup -icl -p 9200 -nhnv -cacert ${capem} -cert ${adminpem} -key ${adminkey} -h ${IP} ${debug}" + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "The backup could not be created" + if [[ $(type -t installCommon_rollBack) == "function" ]]; then + installCommon_rollBack + fi + exit 1; + fi + common_logger -d "Password backup created in /etc/wazuh-indexer/backup." + +} + +function passwords_generateHash() { + + if [ -n "${changeall}" ]; then + common_logger -d "Generating password hashes." + for i in "${!passwords[@]}" + do + nhash=$(bash /usr/share/wazuh-indexer/plugins/opensearch-security/tools/hash.sh -p "${passwords[i]}" 2>&1 | grep -A 2 'issues' | tail -n 1) + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "Hash generation failed." + if [[ $(type -t installCommon_rollBack) == "function" ]]; then + installCommon_rollBack + fi + exit 1; + fi + hashes+=("${nhash}") + done + common_logger -d "Password hashes generated." + else + common_logger "Generating password hash" + hash=$(bash /usr/share/wazuh-indexer/plugins/opensearch-security/tools/hash.sh -p "${password}" 2>&1 | grep -A 2 'issues' | tail -n 1) + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "Hash generation failed." + if [[ $(type -t installCommon_rollBack) == "function" ]]; then + installCommon_rollBack + fi + exit 1; + fi + common_logger -d "Password hash generated." + fi + +} + +function passwords_generatePassword() { + + if [ -n "${nuser}" ]; then + common_logger -d "Generating random password." + pass=$(< /dev/urandom tr -dc "A-Za-z0-9.*+?" | head -c "${1:-28}";echo;) + special_char=$(< /dev/urandom tr -dc ".*+?" | head -c "${1:-1}";echo;) + minus_char=$(< /dev/urandom tr -dc "a-z" | head -c "${1:-1}";echo;) + mayus_char=$(< /dev/urandom tr -dc "A-Z" | head -c "${1:-1}";echo;) + number_char=$(< /dev/urandom tr -dc "0-9" | head -c "${1:-1}";echo;) + password="$(echo "${pass}${special_char}${minus_char}${mayus_char}${number_char}" | fold -w1 | shuf | tr -d '\n')" + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "The password could not been generated." + exit 1; + fi + else + common_logger -d "Generating random passwords." + for i in "${!users[@]}"; do + pass=$(< /dev/urandom tr -dc "A-Za-z0-9.*+?" | head -c "${1:-28}";echo;) + special_char=$(< /dev/urandom tr -dc ".*+?" | head -c "${1:-1}";echo;) + minus_char=$(< /dev/urandom tr -dc "a-z" | head -c "${1:-1}";echo;) + mayus_char=$(< /dev/urandom tr -dc "A-Z" | head -c "${1:-1}";echo;) + number_char=$(< /dev/urandom tr -dc "0-9" | head -c "${1:-1}";echo;) + passwords+=("$(echo "${pass}${special_char}${minus_char}${mayus_char}${number_char}" | fold -w1 | shuf | tr -d '\n')") + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "The password could not been generated." + exit 1; + fi + done + for i in "${!api_users[@]}"; do + pass=$(< /dev/urandom tr -dc "A-Za-z0-9.*+?" | head -c "${1:-28}";echo;) + special_char=$(< /dev/urandom tr -dc ".*+?" | head -c "${1:-1}";echo;) + minus_char=$(< /dev/urandom tr -dc "a-z" | head -c "${1:-1}";echo;) + mayus_char=$(< /dev/urandom tr -dc "A-Z" | head -c "${1:-1}";echo;) + number_char=$(< /dev/urandom tr -dc "0-9" | head -c "${1:-1}";echo;) + api_passwords+=("$(echo "${pass}${special_char}${minus_char}${mayus_char}${number_char}" | fold -w1 | shuf | tr -d '\n')") + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "The password could not been generated." + exit 1; + fi + done + fi +} + +function passwords_generatePasswordFile() { + + common_logger -d "Generating password file." + users=( admin anomalyadmin kibanaserver kibanaro logstash readall snapshotrestore ) + api_users=( wazuh wazuh-wui ) + user_description=( + "Admin user for the web user interface and Wazuh indexer. Use this user to log in to Wazuh dashboard" + "Anomaly detection user for the web user interface" + "Wazuh dashboard user for establishing the connection with Wazuh indexer" + "Regular Dashboard user, only has read permissions to all indices and all permissions on the .kibana index" + "Filebeat user for CRUD operations on Wazuh indices" + "User with READ access to all indices" + "User with permissions to perform snapshot and restore operations" + "Admin user used to communicate with Wazuh API" + "Regular user to query Wazuh API" + ) + api_user_description=( + "Password for wazuh API user" + "Password for wazuh-wui API user" + ) + passwords_generatePassword + + for i in "${!users[@]}"; do + { + echo "# ${user_description[${i}]}" + echo " indexer_username: '${users[${i}]}'" + echo " indexer_password: '${passwords[${i}]}'" + echo "" + } >> "${gen_file}" + done + + for i in "${!api_users[@]}"; do + { + echo "# ${api_user_description[${i}]}" + echo " api_username: '${api_users[${i}]}'" + echo " api_password: '${api_passwords[${i}]}'" + echo "" + } >> "${gen_file}" + done + +} + +function passwords_getApiToken() { + retries=0 + max_internal_error_retries=20 + + TOKEN_API=$(curl -s -u "${adminUser}":"${adminPassword}" -k -X POST "https://localhost:55000/security/user/authenticate?raw=true" --max-time 300 --retry 5 --retry-delay 5) + while [[ "${TOKEN_API}" =~ "Wazuh Internal Error" ]] && [ "${retries}" -lt "${max_internal_error_retries}" ] + do + common_logger "There was an error accessing the API. Retrying..." + TOKEN_API=$(curl -s -u "${adminUser}":"${adminPassword}" -k -X POST "https://localhost:55000/security/user/authenticate?raw=true" --max-time 300 --retry 5 --retry-delay 5) + retries=$((retries+1)) + sleep 10 + done + if [[ ${TOKEN_API} =~ "Wazuh Internal Error" ]]; then + common_logger -e "There was an error while trying to get the API token." + if [[ $(type -t installCommon_rollBack) == "function" ]]; then + installCommon_rollBack + fi + exit 1 + elif [[ ${TOKEN_API} =~ "Invalid credentials" ]]; then + common_logger -e "Invalid admin user credentials" + if [[ $(type -t installCommon_rollBack) == "function" ]]; then + installCommon_rollBack + fi + exit 1 + fi + +} + +function passwords_getApiUsers() { + + mapfile -t api_users < <(common_curl -s -k -X GET -H \"Authorization: Bearer $TOKEN_API\" -H \"Content-Type: application/json\" \"https://localhost:55000/security/users?pretty=true\" --max-time 300 --retry 5 --retry-delay 5 | grep username | awk -F': ' '{print $2}' | sed -e "s/[\'\",]//g") + +} + +function passwords_getApiIds() { + + mapfile -t api_ids < <(common_curl -s -k -X GET -H \"Authorization: Bearer $TOKEN_API\" -H \"Content-Type: application/json\" \"https://localhost:55000/security/users?pretty=true\" --max-time 300 --retry 5 --retry-delay 5 | grep id | awk -F': ' '{print $2}' | sed -e "s/[\'\",]//g") + +} + +function passwords_getApiUserId() { + + user_id="noid" + for u in "${!api_users[@]}"; do + if [ "${1}" == "${api_users[u]}" ]; then + user_id="${api_ids[u]}" + fi + done + + if [ "${user_id}" == "noid" ]; then + common_logger -e "User ${1} is not registered in Wazuh API" + if [[ $(type -t installCommon_rollBack) == "function" ]]; then + installCommon_rollBack + fi + exit 1 + fi + +} + + +function passwords_getNetworkHost() { + + IP=$(grep -hr "^network.host:" /etc/wazuh-indexer/opensearch.yml) + NH="network.host: " + IP="${IP//$NH}" + + # Remove surrounding double quotes if present + IP="${IP//\"}" + + #allow to find ip with an interface + if [[ ${IP} =~ _.*_ ]]; then + interface="${IP//_}" + IP=$(ip -o -4 addr list "${interface}" | awk '{print $4}' | cut -d/ -f1) + fi + + if [ "${IP}" == "0.0.0.0" ]; then + IP="localhost" + fi +} + +function passwords_readFileUsers() { + + filecorrect=$(grep -Ev '^#|^\s*$' "${p_file}" | grep -Pzc "\A(\s*(indexer_username|api_username|indexer_password|api_password):[ \t]+[\'\"]?[\w.*+?-]+[\'\"]?)+\Z") + if [[ "${filecorrect}" -ne 1 ]]; then + common_logger -e "The password file does not have a correct format or password uses invalid characters. Allowed characters: A-Za-z0-9.*+? + +For Wazuh indexer users, the file must have this format: + +# Description + indexer_username: + indexer_password: + +For Wazuh API users, the file must have this format: + +# Description + api_username: + api_password: + +" + exit 1 + fi + + sfileusers=$(grep indexer_username: "${p_file}" | awk '{ print substr( $2, 1, length($2) ) }' | sed -e "s/[\'\"]//g") + sfilepasswords=$(grep indexer_password: "${p_file}" | awk '{ print substr( $2, 1, length($2) ) }' | sed -e "s/[\'\"]//g") + + sfileapiusers=$(grep api_username: "${p_file}" | awk '{ print substr( $2, 1, length($2) ) }' | sed -e "s/[\'\"]//g") + sfileapipasswords=$(grep api_password: "${p_file}" | awk '{ print substr( $2, 1, length($2) ) }' | sed -e "s/[\'\"]//g") + + mapfile -t fileusers <<< "${sfileusers}" + mapfile -t filepasswords <<< "${sfilepasswords}" + + mapfile -t fileapiusers <<< "${sfileapiusers}" + mapfile -t fileapipasswords <<< "${sfileapipasswords}" + + if [ -n "${changeall}" ]; then + for j in "${!fileusers[@]}"; do + supported=false + for i in "${!users[@]}"; do + if [[ "${users[i]}" == "${fileusers[j]}" ]]; then + passwords_checkPassword "${filepasswords[j]}" + passwords[i]=${filepasswords[j]} + supported=true + fi + done + if [ "${supported}" = false ] && [ -n "${indexer_installed}" ]; then + common_logger -e "The user ${fileusers[j]} does not exist" + fi + done + + if [ -n "${adminUser}" ] && [ -n "${adminPassword}" ]; then + for j in "${!fileapiusers[@]}"; do + supported=false + for i in "${!api_users[@]}"; do + if [[ "${api_users[i]}" == "${fileapiusers[j]}" ]]; then + passwords_checkPassword "${fileapipasswords[j]}" + api_passwords[i]=${fileapipasswords[j]} + supported=true + fi + done + if [ "${supported}" = false ] && [ -n "${indexer_installed}" ]; then + common_logger -e "The Wazuh API user ${fileapiusers[j]} does not exist" + fi + done + fi + else + finalusers=() + finalpasswords=() + + finalapiusers=() + finalapipasswords=() + + for j in "${!fileusers[@]}"; do + supported=false + for i in "${!users[@]}"; do + if [[ "${users[i]}" == "${fileusers[j]}" ]]; then + passwords_checkPassword "${filepasswords[j]}" + finalusers+=("${fileusers[j]}") + finalpasswords+=("${filepasswords[j]}") + supported=true + fi + done + if [ ${supported} = false ] && [ -n "${indexer_installed}" ]; then + common_logger -e "The user ${fileusers[j]} does not exist" + fi + done + + if [ -n "${adminUser}" ] && [ -n "${adminPassword}" ]; then + for j in "${!fileapiusers[@]}"; do + supported=false + for i in "${!api_users[@]}"; do + if [[ "${api_users[i]}" == "${fileapiusers[j]}" ]]; then + passwords_checkPassword "${fileapipasswords[j]}" + finalapiusers+=("${fileapiusers[j]}") + finalapipasswords+=("${fileapipasswords[j]}") + supported=true + fi + done + if [ ${supported} = false ] && [ -n "${indexer_installed}" ]; then + common_logger -e "The Wazuh API user ${fileapiusers[j]} does not exist" + fi + done + fi + + users=() + passwords=() + mapfile -t users < <(printf "%s\n" "${finalusers[@]}") + mapfile -t passwords < <(printf "%s\n" "${finalpasswords[@]}") + mapfile -t api_users < <(printf "%s\n" "${finalapiusers[@]}") + mapfile -t api_passwords < <(printf "%s\n" "${finalapipasswords[@]}") + + changeall=1 + fi + +} + +function passwords_readUsers() { + + passwords_updateInternalUsers + susers=$(grep -B 1 hash: /etc/wazuh-indexer/opensearch-security/internal_users.yml | grep -v hash: | grep -v "-" | awk '{ print substr( $0, 1, length($0)-1 ) }') + mapfile -t users <<< "${susers[@]}" + +} + +function passwords_restartService() { + + common_logger -d "Restarting ${1} service..." + if [ "$#" -ne 1 ]; then + common_logger -e "passwords_restartService must be called with 1 argument." + exit 1 + fi + + if [[ -d /run/systemd/system ]]; then + eval "systemctl daemon-reload ${debug}" + eval "systemctl restart ${1}.service ${debug}" + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "${1} could not be started." + if [ -n "$(command -v journalctl)" ]; then + eval "journalctl -u ${1} >> ${logfile}" + fi + if [[ $(type -t installCommon_rollBack) == "function" ]]; then + installCommon_rollBack + fi + exit 1; + else + common_logger -d "${1} started." + fi + elif ps -p 1 -o comm= | grep "init"; then + eval "/etc/init.d/${1} restart ${debug}" + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "${1} could not be started." + if [ -n "$(command -v journalctl)" ]; then + eval "journalctl -u ${1} >> ${logfile}" + fi + if [[ $(type -t installCommon_rollBack) == "function" ]]; then + installCommon_rollBack + fi + exit 1; + else + common_logger -d "${1} started." + fi + elif [ -x "/etc/rc.d/init.d/${1}" ] ; then + eval "/etc/rc.d/init.d/${1} restart ${debug}" + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "${1} could not be started." + if [ -n "$(command -v journalctl)" ]; then + eval "journalctl -u ${1} >> ${logfile}" + fi + if [[ $(type -t installCommon_rollBack) == "function" ]]; then + installCommon_rollBack + fi + exit 1; + else + common_logger -d "${1} started." + fi + else + if [[ $(type -t installCommon_rollBack) == "function" ]]; then + installCommon_rollBack + fi + common_logger -e "${1} could not start. No service manager found on the system." + exit 1; + fi + +} + +function passwords_runSecurityAdmin() { + + common_logger -d "Running security admin tool." + if [ -z "${indexer_installed}" ] && [ -z "${dashboard_installed}" ] && [ -z "${filebeat_installed}" ]; then + common_logger -e "Cannot find Wazuh indexer, Wazuh dashboard or Filebeat on the system." + exit 1; + else + if [ -n "${indexer_installed}" ]; then + capem=$(grep "plugins.security.ssl.transport.pemtrustedcas_filepath: " /etc/wazuh-indexer/opensearch.yml ) + rcapem="plugins.security.ssl.transport.pemtrustedcas_filepath: " + capem="${capem//$rcapem}" + fi + fi + + common_logger -d "Loading new passwords changes." + eval "OPENSEARCH_CONF_DIR=/etc/wazuh-indexer /usr/share/wazuh-indexer/plugins/opensearch-security/tools/securityadmin.sh -f /etc/wazuh-indexer/backup/internal_users.yml -t internalusers -p 9200 -nhnv -cacert ${capem} -cert ${adminpem} -key ${adminkey} -icl -h ${IP} ${debug}" + if [ "${PIPESTATUS[0]}" != 0 ]; then + common_logger -e "Could not load the changes." + exit 1; + fi + eval "cp /etc/wazuh-indexer/backup/internal_users.yml /etc/wazuh-indexer/opensearch-security/internal_users.yml" + eval "rm -rf /etc/wazuh-indexer/backup/ ${debug}" + + if [[ -n "${nuser}" ]] && [[ -n ${autopass} ]]; then + common_logger -nl "The password for user ${nuser} is ${password}" + common_logger -w "Password changed. Remember to update the password in the Wazuh dashboard, Wazuh server, and Filebeat nodes if necessary, and restart the services." + fi + + if [[ -n "${nuser}" ]] && [[ -z ${autopass} ]]; then + common_logger -w "Password changed. Remember to update the password in the Wazuh dashboard, Wazuh server, and Filebeat nodes if necessary, and restart the services." + fi + + if [ -n "${changeall}" ]; then + if [ -z "${AIO}" ] && [ -z "${indexer}" ] && [ -z "${dashboard}" ] && [ -z "${wazuh}" ] && [ -z "${start_indexer_cluster}" ]; then + for i in "${!users[@]}"; do + common_logger -nl "The password for user ${users[i]} is ${passwords[i]}" + done + common_logger -w "Wazuh indexer passwords changed. Remember to update the password in the Wazuh dashboard, Wazuh server, and Filebeat nodes if necessary, and restart the services." + else + common_logger -d "Passwords changed." + fi + fi + +} + +function passwords_updateInternalUsers() { + + common_logger "Updating the internal users." + backup_datetime=$(date +"%Y%m%d_%H%M%S") + internal_users_backup_path="/etc/wazuh-indexer/internalusers-backup" + passwords_getNetworkHost + passwords_createBackUp + + eval "mkdir -p ${internal_users_backup_path} ${debug}" + eval "cp /etc/wazuh-indexer/backup/internal_users.yml ${internal_users_backup_path}/internal_users_${backup_datetime}.yml.bkp ${debug}" + eval "chmod 750 ${internal_users_backup_path} ${debug}" + eval "chmod 640 ${internal_users_backup_path}/internal_users_${backup_datetime}.yml.bkp" + eval "chown -R wazuh-indexer:wazuh-indexer ${internal_users_backup_path} ${debug}" + common_logger "A backup of the internal users has been saved in the /etc/wazuh-indexer/internalusers-backup folder." + + eval "cp /etc/wazuh-indexer/backup/internal_users.yml /etc/wazuh-indexer/opensearch-security/internal_users.yml ${debug}" + eval "rm -rf /etc/wazuh-indexer/backup/ ${debug}" + common_logger -d "The internal users have been updated before changing the passwords." + +} diff --git a/unattended_installer/passwords_tool/passwordsMain.sh b/unattended_installer/passwords_tool/passwordsMain.sh new file mode 100644 index 0000000..52691fa --- /dev/null +++ b/unattended_installer/passwords_tool/passwordsMain.sh @@ -0,0 +1,285 @@ +# Passwords tool - main functions +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +function getHelp() { + + echo -e "" + echo -e "NAME" + echo -e " $(basename "${0}") - Manage passwords for Wazuh indexer users." + echo -e "" + echo -e "SYNOPSIS" + echo -e " $(basename "${0}") [OPTIONS]" + echo -e "" + echo -e "DESCRIPTION" + echo -e " -a, --change-all" + echo -e " Changes all the Wazuh indexer and Wazuh API user passwords and prints them on screen." + echo -e " To change API passwords -au|--admin-user and -ap|--admin-password are required." + echo -e "" + echo -e " -A, --api" + echo -e " Change the Wazuh API password." + echo -e " Requires -u|--user, and -p|--password, -au|--admin-user and -ap|--admin-password." + echo -e "" + echo -e " -au, --admin-user " + echo -e " Admin user for Wazuh API, Required to change Wazuh API passwords." + echo -e " Requires -A|--api." + echo -e "" + echo -e " -ap, --admin-password " + echo -e " Password for Wazuh API admin user, Required to change Wazuh API passwords." + echo -e " Requires -A|--api." + echo -e "" + echo -e " -u, --user " + echo -e " Indicates the name of the user whose password will be changed." + echo -e " If no password specified it will generate a random one." + echo -e "" + echo -e " -p, --password " + echo -e " Indicates the new password, must be used with option -u." + echo -e "" + echo -e " -c, --cert " + echo -e " Indicates route to the admin certificate." + echo -e "" + echo -e " -k, --certkey " + echo -e " Indicates route to the admin certificate key." + echo -e "" + echo -e " -v, --verbose" + echo -e " Shows the complete script execution output." + echo -e "" + echo -e " -f, --file " + echo -e " Changes the passwords for the ones given in the file." + echo -e "" + echo -e " Wazuh indexer users must have this format:" + echo -e "" + echo -e " # Description" + echo -e " indexer_username: " + echo -e " indexer_password: " + echo -e "" + echo -e " Wazuh API users must have this format:" + echo -e "" + echo -e " # Description" + echo -e " api_username: " + echo -e " api_password: " + echo -e "" + echo -e " -gf, --generate-file " + echo -e " Generate password file with random passwords for standard users." + echo -e "" + echo -e " -h, --help" + echo -e " Shows help." + echo -e "" + exit 1 + +} + +function main() { + + umask 177 + + common_checkRoot + + if [ -n "${1}" ]; then + while [ -n "${1}" ] + do + case "${1}" in + "-v"|"--verbose") + verboseenabled=1 + shift 1 + ;; + "-a"|"--change-all") + changeall=1 + shift 1 + ;; + "-A"|"--api") + api=1 + shift 1 + ;; + "-au"|"--admin-user") + if [ -z "${2}" ]; then + echo "Argument au|--admin-user needs a second argument" + getHelp + exit 1 + fi + adminUser=${2} + shift 2 + ;; + "-ap"|"--admin-password") + if [ -z "${2}" ]; then + echo "Argument -ap|--admin-password needs a second argument" + getHelp + exit 1 + fi + adminPassword=${2} + shift 2 + ;; + "-u"|"--user") + if [ -z "${2}" ]; then + echo "Argument --user needs a second argument" + getHelp + exit 1 + fi + nuser=${2} + shift 2 + ;; + "-p"|"--password") + if [ -z "${2}" ]; then + echo "Argument --password needs a second argument" + getHelp + exit 1 + fi + password=${2} + shift 2 + ;; + "-c"|"--cert") + if [ -z "${2}" ]; then + echo "Argument --cert needs a second argument" + getHelp + exit 1 + fi + adminpem=${2} + shift 2 + ;; + "-k"|"--certkey") + if [ -z "${2}" ]; then + echo "Argument --certkey needs a second argument" + getHelp + exit 1 + fi + adminkey=${2} + shift 2 + ;; + "-f"|"--file") + if [ -z "${2}" ]; then + echo "Argument --file needs a second argument" + getHelp + exit 1 + fi + p_file=${2} + shift 2 + ;; + "-gf"|"--generate-file") + if [ -z "${2}" ]; then + echo "Argument --generate-file needs a second argument" + getHelp + exit 1 + fi + gen_file=${2} + shift 2 + ;; + "-h"|"--help") + getHelp + ;; + *) + getHelp + esac + done + + export JAVA_HOME=/usr/share/wazuh-indexer/jdk/ + + if [ -n "${verboseenabled}" ]; then + debug="2>&1 | tee -a ${logfile}" + fi + + if [ -n "${gen_file}" ]; then + passwords_generatePasswordFile + if [ -z "${p_file}" ] && [ -z "${nuser}" ] && [ -z "${changeall}" ]; then + exit 0 + fi + fi + + common_checkSystem + common_checkInstalled + + if [ -n "${p_file}" ] && [ ! -f "${p_file}" ]; then + getHelp + fi + + if [ -n "${nuser}" ] && [ -n "${changeall}" ]; then + getHelp + fi + + if [ -n "${password}" ] && [ -n "${changeall}" ]; then + getHelp + fi + + if [ -n "${nuser}" ] && [ -n "${p_file}" ]; then + getHelp + fi + + if [ -n "${password}" ] && [ -n "${p_file}" ]; then + getHelp + fi + + if [ -z "${nuser}" ] && [ -n "${password}" ]; then + getHelp + fi + + if [ -z "${nuser}" ] && [ -z "${password}" ] && [ -z "${changeall}" ] && [ -z "${p_file}" ]; then + getHelp + fi + + if [ -n "${adminUser}" ] && [ -n "${adminPassword}" ] && [ -z "${api}" ]; then + getHelp + fi + + if [ -n "${nuser}" ]; then + if [ -n "${adminUser}" ] && [ -n "${adminPassword}" ]; then + passwords_getApiToken + passwords_getApiUsers + passwords_getApiIds + elif [ -n "${indexer_installed}" ]; then + passwords_readUsers + fi + passwords_checkUser + fi + + if [ -n "${nuser}" ] && [ -z "${password}" ]; then + autopass=1 + passwords_generatePassword + fi + + if [ -n "${nuser}" ] && [ -n "${password}" ]; then + passwords_checkPassword "${password}" + fi + + + if [ -n "${changeall}" ] || [ -n "${p_file}" ]; then + if [ -n "${indexer_installed}" ]; then + passwords_readUsers + fi + if [ -n "${adminUser}" ] && [ -n "${adminPassword}" ]; then + passwords_getApiToken + passwords_getApiUsers + passwords_getApiIds + else + common_logger "Wazuh API admin credentials not provided, Wazuh API passwords not changed." + fi + if [ -n "${changeall}" ]; then + passwords_generatePassword + fi + fi + + + if [ -n "${p_file}" ]; then + passwords_readFileUsers + fi + + if { [ -z "${api}" ] || [ -n "${changeall}" ]; } && [ -n "${indexer_installed}" ]; then + passwords_getNetworkHost + passwords_generateHash + passwords_changePassword + passwords_runSecurityAdmin + fi + + if [ -n "${api}" ] || [ -n "${changeall}" ]; then + if [ -n "${adminUser}" ] && [ -n "${adminPassword}" ]; then + passwords_changePasswordApi + fi + fi + + else + getHelp + fi + +} \ No newline at end of file diff --git a/unattended_installer/passwords_tool/passwordsVariables.sh b/unattended_installer/passwords_tool/passwordsVariables.sh new file mode 100644 index 0000000..201c6f6 --- /dev/null +++ b/unattended_installer/passwords_tool/passwordsVariables.sh @@ -0,0 +1,10 @@ +# Passwords tool - variables +# Copyright (C) 2015, Wazuh Inc. +# +# This program is a free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License (version 2) as published by the FSF - Free Software +# Foundation. + +readonly logfile="/var/log/wazuh-passwords-tool.log" +debug=">> ${logfile} 2>&1" From 0ec64096a285966d9b14da1abae7b982b2d21192 Mon Sep 17 00:00:00 2001 From: c-bordon Date: Thu, 22 Aug 2024 09:16:33 -0300 Subject: [PATCH 2/2] Removed unattended_installer dir --- unattended_installer/Development-guide.md => Development-guide.md | 0 unattended_installer/builder.sh => builder.sh | 0 {unattended_installer/cert_tool => cert_tool}/certFunctions.sh | 0 {unattended_installer/cert_tool => cert_tool}/certMain.sh | 0 {unattended_installer/cert_tool => cert_tool}/certVariables.sh | 0 .../common_functions => common_functions}/common.sh | 0 .../common_functions => common_functions}/commonVariables.sh | 0 {unattended_installer/config => config}/certificate/config.yml | 0 .../config => config}/certificate/config_aio.yml | 0 {unattended_installer/config => config}/dashboard/dashboard.yml | 0 .../config => config}/dashboard/dashboard_all_in_one.yml | 0 .../config => config}/dashboard/dashboard_unattended.yml | 0 .../dashboard/dashboard_unattended_distributed.yml | 0 {unattended_installer/config => config}/filebeat/filebeat.yml | 0 .../config => config}/filebeat/filebeat_all_in_one.yml | 0 .../config => config}/filebeat/filebeat_distributed.yml | 0 .../config => config}/filebeat/filebeat_elastic_cluster.yml | 0 .../config => config}/filebeat/filebeat_unattended.yml | 0 {unattended_installer/config => config}/indexer/indexer.yml | 0 .../config => config}/indexer/indexer_all_in_one.yml | 0 .../config => config}/indexer/indexer_unattended_distributed.yml | 0 .../config => config}/indexer/roles/internal_users.yml | 0 {unattended_installer/config => config}/indexer/roles/roles.yml | 0 .../config => config}/indexer/roles/roles_mapping.yml | 0 .../install_functions => install_functions}/checks.sh | 0 .../install_functions => install_functions}/dashboard.sh | 0 .../install_functions => install_functions}/filebeat.sh | 0 .../install_functions => install_functions}/indexer.sh | 0 .../install_functions => install_functions}/installCommon.sh | 0 .../install_functions => install_functions}/installMain.sh | 0 .../install_functions => install_functions}/installVariables.sh | 0 .../install_functions => install_functions}/manager.sh | 0 .../wazuh-offline-download.sh | 0 .../wazuh-offline-installation.sh | 0 .../passwords_tool => passwords_tool}/passwordsFunctions.sh | 0 .../passwords_tool => passwords_tool}/passwordsMain.sh | 0 .../passwords_tool => passwords_tool}/passwordsVariables.sh | 0 37 files changed, 0 insertions(+), 0 deletions(-) rename unattended_installer/Development-guide.md => Development-guide.md (100%) rename unattended_installer/builder.sh => builder.sh (100%) rename {unattended_installer/cert_tool => cert_tool}/certFunctions.sh (100%) rename {unattended_installer/cert_tool => cert_tool}/certMain.sh (100%) rename {unattended_installer/cert_tool => cert_tool}/certVariables.sh (100%) rename {unattended_installer/common_functions => common_functions}/common.sh (100%) rename {unattended_installer/common_functions => common_functions}/commonVariables.sh (100%) rename {unattended_installer/config => config}/certificate/config.yml (100%) rename {unattended_installer/config => config}/certificate/config_aio.yml (100%) rename {unattended_installer/config => config}/dashboard/dashboard.yml (100%) rename {unattended_installer/config => config}/dashboard/dashboard_all_in_one.yml (100%) rename {unattended_installer/config => config}/dashboard/dashboard_unattended.yml (100%) rename {unattended_installer/config => config}/dashboard/dashboard_unattended_distributed.yml (100%) rename {unattended_installer/config => config}/filebeat/filebeat.yml (100%) rename {unattended_installer/config => config}/filebeat/filebeat_all_in_one.yml (100%) rename {unattended_installer/config => config}/filebeat/filebeat_distributed.yml (100%) rename {unattended_installer/config => config}/filebeat/filebeat_elastic_cluster.yml (100%) rename {unattended_installer/config => config}/filebeat/filebeat_unattended.yml (100%) rename {unattended_installer/config => config}/indexer/indexer.yml (100%) rename {unattended_installer/config => config}/indexer/indexer_all_in_one.yml (100%) rename {unattended_installer/config => config}/indexer/indexer_unattended_distributed.yml (100%) rename {unattended_installer/config => config}/indexer/roles/internal_users.yml (100%) rename {unattended_installer/config => config}/indexer/roles/roles.yml (100%) rename {unattended_installer/config => config}/indexer/roles/roles_mapping.yml (100%) rename {unattended_installer/install_functions => install_functions}/checks.sh (100%) rename {unattended_installer/install_functions => install_functions}/dashboard.sh (100%) rename {unattended_installer/install_functions => install_functions}/filebeat.sh (100%) rename {unattended_installer/install_functions => install_functions}/indexer.sh (100%) rename {unattended_installer/install_functions => install_functions}/installCommon.sh (100%) rename {unattended_installer/install_functions => install_functions}/installMain.sh (100%) rename {unattended_installer/install_functions => install_functions}/installVariables.sh (100%) rename {unattended_installer/install_functions => install_functions}/manager.sh (100%) rename {unattended_installer/install_functions => install_functions}/wazuh-offline-download.sh (100%) rename {unattended_installer/install_functions => install_functions}/wazuh-offline-installation.sh (100%) rename {unattended_installer/passwords_tool => passwords_tool}/passwordsFunctions.sh (100%) rename {unattended_installer/passwords_tool => passwords_tool}/passwordsMain.sh (100%) rename {unattended_installer/passwords_tool => passwords_tool}/passwordsVariables.sh (100%) diff --git a/unattended_installer/Development-guide.md b/Development-guide.md similarity index 100% rename from unattended_installer/Development-guide.md rename to Development-guide.md diff --git a/unattended_installer/builder.sh b/builder.sh similarity index 100% rename from unattended_installer/builder.sh rename to builder.sh diff --git a/unattended_installer/cert_tool/certFunctions.sh b/cert_tool/certFunctions.sh similarity index 100% rename from unattended_installer/cert_tool/certFunctions.sh rename to cert_tool/certFunctions.sh diff --git a/unattended_installer/cert_tool/certMain.sh b/cert_tool/certMain.sh similarity index 100% rename from unattended_installer/cert_tool/certMain.sh rename to cert_tool/certMain.sh diff --git a/unattended_installer/cert_tool/certVariables.sh b/cert_tool/certVariables.sh similarity index 100% rename from unattended_installer/cert_tool/certVariables.sh rename to cert_tool/certVariables.sh diff --git a/unattended_installer/common_functions/common.sh b/common_functions/common.sh similarity index 100% rename from unattended_installer/common_functions/common.sh rename to common_functions/common.sh diff --git a/unattended_installer/common_functions/commonVariables.sh b/common_functions/commonVariables.sh similarity index 100% rename from unattended_installer/common_functions/commonVariables.sh rename to common_functions/commonVariables.sh diff --git a/unattended_installer/config/certificate/config.yml b/config/certificate/config.yml similarity index 100% rename from unattended_installer/config/certificate/config.yml rename to config/certificate/config.yml diff --git a/unattended_installer/config/certificate/config_aio.yml b/config/certificate/config_aio.yml similarity index 100% rename from unattended_installer/config/certificate/config_aio.yml rename to config/certificate/config_aio.yml diff --git a/unattended_installer/config/dashboard/dashboard.yml b/config/dashboard/dashboard.yml similarity index 100% rename from unattended_installer/config/dashboard/dashboard.yml rename to config/dashboard/dashboard.yml diff --git a/unattended_installer/config/dashboard/dashboard_all_in_one.yml b/config/dashboard/dashboard_all_in_one.yml similarity index 100% rename from unattended_installer/config/dashboard/dashboard_all_in_one.yml rename to config/dashboard/dashboard_all_in_one.yml diff --git a/unattended_installer/config/dashboard/dashboard_unattended.yml b/config/dashboard/dashboard_unattended.yml similarity index 100% rename from unattended_installer/config/dashboard/dashboard_unattended.yml rename to config/dashboard/dashboard_unattended.yml diff --git a/unattended_installer/config/dashboard/dashboard_unattended_distributed.yml b/config/dashboard/dashboard_unattended_distributed.yml similarity index 100% rename from unattended_installer/config/dashboard/dashboard_unattended_distributed.yml rename to config/dashboard/dashboard_unattended_distributed.yml diff --git a/unattended_installer/config/filebeat/filebeat.yml b/config/filebeat/filebeat.yml similarity index 100% rename from unattended_installer/config/filebeat/filebeat.yml rename to config/filebeat/filebeat.yml diff --git a/unattended_installer/config/filebeat/filebeat_all_in_one.yml b/config/filebeat/filebeat_all_in_one.yml similarity index 100% rename from unattended_installer/config/filebeat/filebeat_all_in_one.yml rename to config/filebeat/filebeat_all_in_one.yml diff --git a/unattended_installer/config/filebeat/filebeat_distributed.yml b/config/filebeat/filebeat_distributed.yml similarity index 100% rename from unattended_installer/config/filebeat/filebeat_distributed.yml rename to config/filebeat/filebeat_distributed.yml diff --git a/unattended_installer/config/filebeat/filebeat_elastic_cluster.yml b/config/filebeat/filebeat_elastic_cluster.yml similarity index 100% rename from unattended_installer/config/filebeat/filebeat_elastic_cluster.yml rename to config/filebeat/filebeat_elastic_cluster.yml diff --git a/unattended_installer/config/filebeat/filebeat_unattended.yml b/config/filebeat/filebeat_unattended.yml similarity index 100% rename from unattended_installer/config/filebeat/filebeat_unattended.yml rename to config/filebeat/filebeat_unattended.yml diff --git a/unattended_installer/config/indexer/indexer.yml b/config/indexer/indexer.yml similarity index 100% rename from unattended_installer/config/indexer/indexer.yml rename to config/indexer/indexer.yml diff --git a/unattended_installer/config/indexer/indexer_all_in_one.yml b/config/indexer/indexer_all_in_one.yml similarity index 100% rename from unattended_installer/config/indexer/indexer_all_in_one.yml rename to config/indexer/indexer_all_in_one.yml diff --git a/unattended_installer/config/indexer/indexer_unattended_distributed.yml b/config/indexer/indexer_unattended_distributed.yml similarity index 100% rename from unattended_installer/config/indexer/indexer_unattended_distributed.yml rename to config/indexer/indexer_unattended_distributed.yml diff --git a/unattended_installer/config/indexer/roles/internal_users.yml b/config/indexer/roles/internal_users.yml similarity index 100% rename from unattended_installer/config/indexer/roles/internal_users.yml rename to config/indexer/roles/internal_users.yml diff --git a/unattended_installer/config/indexer/roles/roles.yml b/config/indexer/roles/roles.yml similarity index 100% rename from unattended_installer/config/indexer/roles/roles.yml rename to config/indexer/roles/roles.yml diff --git a/unattended_installer/config/indexer/roles/roles_mapping.yml b/config/indexer/roles/roles_mapping.yml similarity index 100% rename from unattended_installer/config/indexer/roles/roles_mapping.yml rename to config/indexer/roles/roles_mapping.yml diff --git a/unattended_installer/install_functions/checks.sh b/install_functions/checks.sh similarity index 100% rename from unattended_installer/install_functions/checks.sh rename to install_functions/checks.sh diff --git a/unattended_installer/install_functions/dashboard.sh b/install_functions/dashboard.sh similarity index 100% rename from unattended_installer/install_functions/dashboard.sh rename to install_functions/dashboard.sh diff --git a/unattended_installer/install_functions/filebeat.sh b/install_functions/filebeat.sh similarity index 100% rename from unattended_installer/install_functions/filebeat.sh rename to install_functions/filebeat.sh diff --git a/unattended_installer/install_functions/indexer.sh b/install_functions/indexer.sh similarity index 100% rename from unattended_installer/install_functions/indexer.sh rename to install_functions/indexer.sh diff --git a/unattended_installer/install_functions/installCommon.sh b/install_functions/installCommon.sh similarity index 100% rename from unattended_installer/install_functions/installCommon.sh rename to install_functions/installCommon.sh diff --git a/unattended_installer/install_functions/installMain.sh b/install_functions/installMain.sh similarity index 100% rename from unattended_installer/install_functions/installMain.sh rename to install_functions/installMain.sh diff --git a/unattended_installer/install_functions/installVariables.sh b/install_functions/installVariables.sh similarity index 100% rename from unattended_installer/install_functions/installVariables.sh rename to install_functions/installVariables.sh diff --git a/unattended_installer/install_functions/manager.sh b/install_functions/manager.sh similarity index 100% rename from unattended_installer/install_functions/manager.sh rename to install_functions/manager.sh diff --git a/unattended_installer/install_functions/wazuh-offline-download.sh b/install_functions/wazuh-offline-download.sh similarity index 100% rename from unattended_installer/install_functions/wazuh-offline-download.sh rename to install_functions/wazuh-offline-download.sh diff --git a/unattended_installer/install_functions/wazuh-offline-installation.sh b/install_functions/wazuh-offline-installation.sh similarity index 100% rename from unattended_installer/install_functions/wazuh-offline-installation.sh rename to install_functions/wazuh-offline-installation.sh diff --git a/unattended_installer/passwords_tool/passwordsFunctions.sh b/passwords_tool/passwordsFunctions.sh similarity index 100% rename from unattended_installer/passwords_tool/passwordsFunctions.sh rename to passwords_tool/passwordsFunctions.sh diff --git a/unattended_installer/passwords_tool/passwordsMain.sh b/passwords_tool/passwordsMain.sh similarity index 100% rename from unattended_installer/passwords_tool/passwordsMain.sh rename to passwords_tool/passwordsMain.sh diff --git a/unattended_installer/passwords_tool/passwordsVariables.sh b/passwords_tool/passwordsVariables.sh similarity index 100% rename from unattended_installer/passwords_tool/passwordsVariables.sh rename to passwords_tool/passwordsVariables.sh