diff --git a/docker/README.md b/docker/README.md index e012e8c42bed1..64e5c40ac33a6 100644 --- a/docker/README.md +++ b/docker/README.md @@ -78,3 +78,17 @@ Refer to [scripts/README.md](../scripts/README.md) for details about how to buil [docker-variant]: https://docs.docker.com/desktop/install/linux-install/#differences-between-docker-desktop-for-linux-and-docker-engine [docker-context]: https://docs.docker.com/desktop/install/linux-install/#context [wi-repo]: https://github.com/wazuh/wazuh-indexer + +## Building Docker images + +The [prod](./prod) folder contains the code to build Docker images. A tarball of `wazuh-indexer` needs to be located at the same level that the Dockerfile. Below there is example of the command needed to build the image. Set the build arguments and the image tag accordingly. + +```console +docker build --build-arg="VERSION=4.9.0" --build-arg="INDEXER_TAR_NAME=wazuh-indexer-4.9.0-1_linux-x64_cfca84f.tar.gz" --tag=wazuh-indexer:4.9.0 --progress=plain --no-cache . +``` + +Then, start a container with: + +```console +docker run -it --rm wazuh-indexer:4.9.0 +``` \ No newline at end of file diff --git a/docker/prod/Dockerfile b/docker/prod/Dockerfile new file mode 100644 index 0000000000000..256cad3ac2b8a --- /dev/null +++ b/docker/prod/Dockerfile @@ -0,0 +1,78 @@ +# Wazuh Docker Copyright (C) 2017, Wazuh Inc. (License GPLv2) +FROM amazonlinux:2023.3.20240219.0 AS builder + +ARG VERSION +ARG INDEXER_TAR_NAME + +RUN yum install openssl tar findutils shadow-utils -y + +COPY ${INDEXER_TAR_NAME} / + +COPY config/opensearch.yml / + +COPY config/config.yml / + +COPY config/config.sh / + +RUN bash config.sh + +################################################################################ +# Build stage 1 (the actual Wazuh indexer image): +# +# Copy wazuh-indexer from stage 0 +# Add entrypoint + +################################################################################ +FROM amazonlinux:2023.3.20240219.0 + +ENV USER="wazuh-indexer" \ + GROUP="wazuh-indexer" \ + NAME="wazuh-indexer" \ + INSTALL_DIR="/usr/share/wazuh-indexer" + +RUN yum install curl-minimal shadow-utils findutils hostname -y + +RUN getent group $GROUP || groupadd -r -g 1000 $GROUP + +RUN useradd --system \ + --uid 1000 \ + --no-create-home \ + --home-dir $INSTALL_DIR \ + --gid $GROUP \ + --shell /sbin/nologin \ + --comment "$USER user" \ + $USER + +WORKDIR $INSTALL_DIR + +COPY entrypoint.sh / + +COPY config/securityadmin.sh / + +RUN chmod 700 /entrypoint.sh && chmod 700 /securityadmin.sh + +RUN chown 1000:1000 /*.sh + +COPY --from=builder --chown=1000:1000 /debian/wazuh-indexer/usr/share/wazuh-indexer /usr/share/wazuh-indexer +COPY --from=builder --chown=0:0 /debian/wazuh-indexer/usr/lib/systemd /usr/lib/systemd +COPY --from=builder --chown=0:0 /debian/wazuh-indexer/usr/lib/sysctl.d /usr/lib/sysctl.d +COPY --from=builder --chown=0:0 /debian/wazuh-indexer/usr/lib/tmpfiles.d /usr/lib/tmpfiles.d + +RUN chown -R 1000:1000 /usr/share/wazuh-indexer + +RUN mkdir -p /var/lib/wazuh-indexer && chown 1000:1000 /var/lib/wazuh-indexer && \ + mkdir -p /usr/share/wazuh-indexer/logs && chown 1000:1000 /usr/share/wazuh-indexer/logs && \ + mkdir -p /run/wazuh-indexer && chown 1000:1000 /run/wazuh-indexer && \ + mkdir -p /var/log/wazuh-indexer && chown 1000:1000 /var/log/wazuh-indexer && \ + chmod 700 /usr/share/wazuh-indexer && \ + chmod 600 /usr/share/wazuh-indexer/config/jvm.options && \ + chmod 600 /usr/share/wazuh-indexer/config/opensearch.yml + +USER wazuh-indexer + +# Services ports +EXPOSE 9200 + +ENTRYPOINT ["/entrypoint.sh"] +# Dummy overridable parameter parsed by entrypoint +CMD ["opensearchwrapper"] \ No newline at end of file diff --git a/docker/prod/config/config.sh b/docker/prod/config/config.sh new file mode 100644 index 0000000000000..016fa89b28b00 --- /dev/null +++ b/docker/prod/config/config.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +# Wazuh Docker Copyright (C) 2017, Wazuh Inc. (License GPLv2) +# This has to be exported to make some magic below work. +export DH_OPTIONS + +export NAME=wazuh-indexer +export TARGET_DIR=${CURDIR}/debian/${NAME} + +# Package build options +export LOG_DIR=/var/log/${NAME} +export LIB_DIR=/var/lib/${NAME} +export PID_DIR=/run/${NAME} +export INDEXER_HOME=/usr/share/${NAME} +export CONFIG_DIR=${INDEXER_HOME}/config +export BASE_DIR=${NAME}-* + +rm -rf ${INDEXER_HOME:?}/ +tar -xf "${INDEXER_TAR_NAME}" + +## TOOLS + +## Variables +TOOLS_PATH=${NAME}-${VERSION}/plugins/opensearch-security/tools +CERT_TOOL=${TOOLS_PATH}/wazuh-certs-tool.sh + +# generate certificates +cp $CERT_TOOL . +chmod 755 wazuh-certs-tool.sh && bash wazuh-certs-tool.sh -A + +# copy to target +mkdir -p ${TARGET_DIR}${INDEXER_HOME} +# mkdir -p ${TARGET_DIR}${INDEXER_HOME}/opensearch-security/ <-- empty dir +mkdir -p ${TARGET_DIR}${CONFIG_DIR} +mkdir -p ${TARGET_DIR}${LIB_DIR} +mkdir -p ${TARGET_DIR}${LOG_DIR} +mkdir -p ${TARGET_DIR}/etc/init.d +mkdir -p ${TARGET_DIR}/etc/default +mkdir -p ${TARGET_DIR}/usr/lib/tmpfiles.d +mkdir -p ${TARGET_DIR}/usr/lib/sysctl.d +mkdir -p ${TARGET_DIR}/usr/lib/systemd/system +mkdir -p ${TARGET_DIR}${CONFIG_DIR}/certs +# Copy installation files to final location +cp -pr ${BASE_DIR}/* ${TARGET_DIR}${INDEXER_HOME} +cp -pr /opensearch.yml ${TARGET_DIR}${CONFIG_DIR} +# Copy Wazuh indexer's certificates +cp -pr /wazuh-certificates/demo.indexer.pem ${TARGET_DIR}${CONFIG_DIR}/certs/indexer.pem +cp -pr /wazuh-certificates/demo.indexer-key.pem ${TARGET_DIR}${CONFIG_DIR}/certs/indexer-key.pem +cp -pr /wazuh-certificates/root-ca.key ${TARGET_DIR}${CONFIG_DIR}/certs/root-ca.key +cp -pr /wazuh-certificates/root-ca.pem ${TARGET_DIR}${CONFIG_DIR}/certs/root-ca.pem +cp -pr /wazuh-certificates/admin.pem ${TARGET_DIR}${CONFIG_DIR}/certs/admin.pem +cp -pr /wazuh-certificates/admin-key.pem ${TARGET_DIR}${CONFIG_DIR}/certs/admin-key.pem + +# Set path to indexer home directory +sed -i 's/-Djava.security.policy=file:\/\/\/etc\/wazuh-indexer\/opensearch-performance-analyzer\/opensearch_security.policy/-Djava.security.policy=file:\/\/\/usr\/share\/wazuh-indexer\/opensearch-performance-analyzer\/opensearch_security.policy/g' ${TARGET_DIR}${CONFIG_DIR}/jvm.options + +chmod -R 500 ${TARGET_DIR}${CONFIG_DIR}/certs +chmod -R 400 ${TARGET_DIR}${CONFIG_DIR}/certs/* + +find ${TARGET_DIR} -type d -exec chmod 750 {} \; +find ${TARGET_DIR} -type f -perm 644 -exec chmod 640 {} \; +find ${TARGET_DIR} -type f -perm 664 -exec chmod 660 {} \; +find ${TARGET_DIR} -type f -perm 755 -exec chmod 750 {} \; +find ${TARGET_DIR} -type f -perm 744 -exec chmod 740 {} \; diff --git a/docker/prod/config/config.yml b/docker/prod/config/config.yml new file mode 100644 index 0000000000000..e5383c7c4f2eb --- /dev/null +++ b/docker/prod/config/config.yml @@ -0,0 +1,5 @@ +nodes: + # Wazuh indexer server nodes + indexer: + - name: demo.indexer + ip: demo.indexer \ No newline at end of file diff --git a/docker/prod/config/opensearch.yml b/docker/prod/config/opensearch.yml new file mode 100644 index 0000000000000..278b69d3144c8 --- /dev/null +++ b/docker/prod/config/opensearch.yml @@ -0,0 +1,26 @@ +network.host: "0.0.0.0" +node.name: "wazuh.indexer" +path.data: /var/lib/wazuh-indexer +path.logs: /var/log/wazuh-indexer +discovery.type: single-node +compatibility.override_main_response_version: true +plugins.security.ssl.http.pemcert_filepath: /usr/share/wazuh-indexer/config/certs/indexer.pem +plugins.security.ssl.http.pemkey_filepath: /usr/share/wazuh-indexer/config/certs/indexer-key.pem +plugins.security.ssl.http.pemtrustedcas_filepath: /usr/share/wazuh-indexer/config/certs/root-ca.pem +plugins.security.ssl.transport.pemcert_filepath: /usr/share/wazuh-indexer/config/certs/indexer.pem +plugins.security.ssl.transport.pemkey_filepath: /usr/share/wazuh-indexer/config/certs/indexer-key.pem +plugins.security.ssl.transport.pemtrustedcas_filepath: /usr/share/wazuh-indexer/config/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.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=demo.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"] \ No newline at end of file diff --git a/docker/prod/config/securityadmin.sh b/docker/prod/config/securityadmin.sh new file mode 100644 index 0000000000000..3c60c1548e8a5 --- /dev/null +++ b/docker/prod/config/securityadmin.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# Initialize the `.opendistro_security` index. +sleep 30 +bash "$INDEXER_HOME"/plugins/opensearch-security/tools/securityadmin.sh \ + -cacert "$INDEXER_HOME"/config/certs/root-ca.pem \ + -cert "$INDEXER_HOME"/config/certs/admin.pem \ + -key "$INDEXER_HOME"/config/certs/admin-key.pem \ + -cd "$INDEXER_HOME"/config/opensearch-security/ \ + -nhnv \ + -icl diff --git a/docker/prod/entrypoint.sh b/docker/prod/entrypoint.sh new file mode 100644 index 0000000000000..05017dc4ba493 --- /dev/null +++ b/docker/prod/entrypoint.sh @@ -0,0 +1,98 @@ +#!/usr/bin/env bash +# Wazuh Docker Copyright (C) 2017, Wazuh Inc. (License GPLv2) +set -e + +umask 0002 + +# Constants +INDEXER_HOME=/usr/share/wazuh-indexer +OPENSEARCH_PATH_CONF=${INDEXER_HOME}/config +JAVA_HOME=${INDEXER_HOME}/jdk + +# DISCOVERY=$(grep -oP "(?<=discovery.type: ).*" ${OPENSEARCH_PATH_CONF}/opensearch.yml) + +# Export variables to environment +export INDEXER_HOME +export OPENSEARCH_PATH_CONF +export JAVA_HOME + +run_as_other_user_if_needed() { + if [[ "$(id -u)" == "0" ]]; then + # If running as root, drop to specified UID and run command + exec chroot --userspec=1000:0 / "${@}" + else + # Either we are running in Openshift with random uid and are a member of the root group + # or with a custom --user + exec "${@}" + fi +} + +# Allow user specify custom CMD, maybe bin/opensearch itself +# for example to directly specify `-E` style parameters for opensearch on k8s +# or simply to run /bin/bash to check the image +if [[ "$1" != "opensearchwrapper" ]]; then + if [[ "$(id -u)" == "0" && $(basename "$1") == "opensearch" ]]; then + # Rewrite CMD args to replace $1 with `opensearch` explicitly, + # Without this, user could specify `opensearch -E x.y=z` but + # `bin/opensearch -E x.y=z` would not work. + set -- "opensearch" "${@:2}" + # Use chroot to switch to UID 1000 / GID 0 + exec chroot --userspec=1000:0 / "$@" + else + # User probably wants to run something else, like /bin/bash, with another uid forced (Openshift?) + exec "$@" + fi +fi + +# Allow environment variables to be set by creating a file with the +# contents, and setting an environment variable with the suffix _FILE to +# point to it. This can be used to provide secrets to a container, without +# the values being specified explicitly when running the container. +# +# This is also sourced in opensearch-env, and is only needed here +# as well because we use INDEXER_PASSWORD below. Sourcing this script +# is idempotent. +source /usr/share/wazuh-indexer/bin/opensearch-env-from-file + +if [[ -f bin/opensearch-users ]]; then + # Check for the INDEXER_PASSWORD environment variable to set the + # bootstrap password for Security. + # + # This is only required for the first node in a cluster with Security + # enabled, but we have no way of knowing which node we are yet. We'll just + # honor the variable if it's present. + if [[ -n "$INDEXER_PASSWORD" ]]; then + [[ -f /usr/share/wazuh-indexer/opensearch.keystore ]] || (run_as_other_user_if_needed opensearch-keystore create) + if ! (run_as_other_user_if_needed opensearch-keystore has-passwd --silent); then + # keystore is unencrypted + if ! (run_as_other_user_if_needed opensearch-keystore list | grep -q '^bootstrap.password$'); then + (run_as_other_user_if_needed echo "$INDEXER_PASSWORD" | opensearch-keystore add -x 'bootstrap.password') + fi + else + # keystore requires password + if ! (run_as_other_user_if_needed echo "$KEYSTORE_PASSWORD" | + opensearch-keystore list | grep -q '^bootstrap.password$'); then + COMMANDS="$(printf "%s\n%s" "$KEYSTORE_PASSWORD" "$INDEXER_PASSWORD")" + (run_as_other_user_if_needed echo "$COMMANDS" | opensearch-keystore add -x 'bootstrap.password') + fi + fi + fi +fi + +if [[ "$(id -u)" == "0" ]]; then + # If requested and running as root, mutate the ownership of bind-mounts + if [[ -n "$TAKE_FILE_OWNERSHIP" ]]; then + chown -R 1000:0 /usr/share/wazuh-indexer/{data,logs} + fi +fi + +# Initialize security +nohup /securityadmin.sh & + +#if [[ "$DISCOVERY" == "single-node" ]] && [[ ! -f "/var/lib/wazuh-indexer/.flag" ]]; then +# run securityadmin.sh for single node with CACERT, CERT and KEY parameter +# nohup /securityadmin.sh & +# touch "/var/lib/wazuh-indexer/.flag" +#fi + +run_as_other_user_if_needed /usr/share/wazuh-indexer/bin/opensearch <<<"$KEYSTORE_PASSWORD"