diff --git a/docker-compose.yml b/docker-compose.yml
index cd8f90ff..4e859267 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -3,14 +3,20 @@ version: '3.7'
services:
wazuh:
- build: wazuh
+ build: wazuh-opendistro/
+ image: wazuh-opendistro
hostname: wazuh-manager
restart: always
ports:
- - "1514:1514/udp"
+ - "1514:1514"
- "1515:1515"
- "514:514/udp"
- "55000:55000"
+ environment:
+ - ELASTICSEARCH_URL=https://elasticsearch:9200
+ - ELASTIC_USERNAME=admin
+ - ELASTIC_PASSWORD=admin
+ - FILEBEAT_SSL_VERIFICATION_MODE=none
volumes:
- ossec_api_configuration:/var/ossec/api/configuration
- ossec_etc:/var/ossec/etc
@@ -25,46 +31,45 @@ services:
- filebeat_var:/var/lib/filebeat
elasticsearch:
- image: docker.elastic.co/elasticsearch/elasticsearch:7.8.0
+ image: amazon/opendistro-for-elasticsearch:1.9.0
hostname: elasticsearch
restart: always
ports:
- "9200:9200"
environment:
- - "ES_JAVA_OPTS=-Xms1g -Xmx1g"
- - bootstrap.memory_lock=true
- discovery.type=single-node
+ - cluster.name=wazuh-cluster
+ - network.host=0.0.0.0
+ - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
+ - bootstrap.memory_lock=true
ulimits:
memlock:
soft: -1
hard: -1
- volumes:
- - ./elastic_conf/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
+ nofile:
+ soft: 65536
+ hard: 65536
kibana:
- build: kibana
+ build: kibana-opendistro/
+ image: wazuh-kibana-opendistro
hostname: kibana
restart: always
+ ports:
+ - 443:5601
+ environment:
+ - ELASTICSEARCH_USERNAME=admin
+ - ELASTICSEARCH_PASSWORD=admin
+ - SERVER_SSL_ENABLED=true
+ - SERVER_SSL_CERTIFICATE=/usr/share/kibana/config/opendistroforelasticsearch.example.org.cert
+ - SERVER_SSL_KEY=/usr/share/kibana/config/opendistroforelasticsearch.example.org.key
+
depends_on:
- elasticsearch
links:
- elasticsearch:elasticsearch
- wazuh:wazuh
- nginx:
- image: nginx:stable
- hostname: nginx
- restart: always
- ports:
- - "80:80"
- - "443:443"
- depends_on:
- - kibana
- links:
- - kibana:kibana
- volumes:
- - ./nginx_conf:/etc/nginx/conf.d:ro
-
volumes:
ossec_api_configuration:
ossec_etc:
diff --git a/kibana-opendistro/Dockerfile b/kibana-opendistro/Dockerfile
new file mode 100644
index 00000000..82631ca2
--- /dev/null
+++ b/kibana-opendistro/Dockerfile
@@ -0,0 +1,57 @@
+# Wazuh Docker Copyright (C) 2020 Wazuh Inc. (License GPLv2)
+FROM amazon/opendistro-for-elasticsearch-kibana:1.9.0
+USER kibana
+ARG ELASTIC_VERSION=7.8.0
+ARG WAZUH_VERSION=4.0.0
+ARG WAZUH_APP_VERSION="${WAZUH_VERSION}_${ELASTIC_VERSION}"
+
+WORKDIR /usr/share/kibana
+RUN ./bin/kibana-plugin install https://packages-dev.wazuh.com/pre-release/ui/kibana/wazuh_kibana-${WAZUH_APP_VERSION}-1.zip
+
+WORKDIR /
+USER root
+COPY config/entrypoint.sh ./entrypoint.sh
+RUN chmod 755 ./entrypoint.sh
+
+ENV PATTERN="" \
+ CHECKS_PATTERN="" \
+ CHECKS_TEMPLATE="" \
+ CHECKS_API="" \
+ CHECKS_SETUP="" \
+ EXTENSIONS_PCI="" \
+ EXTENSIONS_GDPR="" \
+ EXTENSIONS_AUDIT="" \
+ EXTENSIONS_OSCAP="" \
+ EXTENSIONS_CISCAT="" \
+ EXTENSIONS_AWS="" \
+ EXTENSIONS_VIRUSTOTAL="" \
+ EXTENSIONS_OSQUERY="" \
+ APP_TIMEOUT="" \
+ WAZUH_SHARDS="" \
+ WAZUH_REPLICAS="" \
+ WAZUH_VERSION_SHARDS="" \
+ WAZUH_VERSION_REPLICAS="" \
+ IP_SELECTOR="" \
+ IP_IGNORE="" \
+ WAZUH_MONITORING_ENABLED="" \
+ WAZUH_MONITORING_FREQUENCY="" \
+ WAZUH_MONITORING_SHARDS="" \
+ WAZUH_MONITORING_REPLICAS="" \
+ ADMIN_PRIVILEGES=""
+
+USER kibana
+RUN NODE_OPTIONS="--max-old-space-size=2048" /usr/local/bin/kibana-docker --optimize
+
+COPY ./config/custom_welcome /tmp/custom_welcome
+COPY --chown=kibana:kibana ./config/welcome_wazuh.sh ./
+RUN chmod +x ./welcome_wazuh.sh
+ARG CHANGE_WELCOME="true"
+RUN ./welcome_wazuh.sh
+
+COPY --chown=kibana:kibana ./config/wazuh_app_config.sh ./
+RUN chmod +x ./wazuh_app_config.sh
+
+COPY --chown=kibana:kibana ./config/kibana_settings.sh ./
+RUN chmod +x ./kibana_settings.sh
+
+ENTRYPOINT ./entrypoint.sh
diff --git a/kibana-opendistro/config/custom_welcome/security-login.style.css b/kibana-opendistro/config/custom_welcome/security-login.style.css
new file mode 100644
index 00000000..6648df2b
--- /dev/null
+++ b/kibana-opendistro/config/custom_welcome/security-login.style.css
@@ -0,0 +1,118 @@
+#security-login-app .content {
+ background: url(./wazuh_wazuh_bg.svg) !important;
+ width: 100% !important;
+ height: 100% !important;
+ background-size: cover !important;
+}
+
+.app-wrapper {
+ left: 0;
+}
+
+.global-nav.is-global-nav-open+.app-wrapper {
+ left: 0;
+}
+
+.btn-default {
+ background-color: #00a9e5!important;
+ border-color: #00a0e5!important;
+ color: #ffffff;
+ padding: 8px;
+}
+
+.btn-default:hover {
+ background-color: #00a9e5!important;
+ border-color: #00a0e5!important;
+ color: #ffffff;
+}
+
+.brand-image-container {
+ text-align: center;
+}
+
+.brand-image {
+ display: none;
+}
+
+.login-wrapper {
+ position: absolute;
+ width: 430px;
+ top: 55px;
+ border-radius: 1px;
+ padding: 1em;
+}
+
+.login-wrapper .login-title {
+ text-align: center;
+ padding-bottom: 10px;
+ color: #ffffff !important;
+ font-size: 35px !important;
+ font-weight: 300;
+}
+
+.login-wrapper .login-subtitle {
+ text-align: center;
+ padding-bottom: 15px;
+ color: #ffffff !important;
+ font-size: 16px !important;
+}
+
+.login-wrapper .login-form {
+ padding: 16px;
+ box-shadow: 0 2px 2px -1px rgba(152, 162, 179, 0.3), 0 1px 5px -2px rgba(152, 162, 179, 0.3);
+ background-color: #FFF;
+ border: 1px solid #D3DAE6;
+ border-radius: 4px;
+ -webkit-box-flex: 1;
+ -ms-flex-positive: 1;
+ flex-grow: 1;
+ margin-top: 32px;
+}
+
+.login-wrapper .login-form .input-group {
+ margin-bottom: 1em;
+}
+
+.login-wrapper .login-form .kuiTextInput {
+ cursor: initial;
+}
+
+.login-wrapper .login-form .kuiTextInput:invalid:not(.ng-touched) {
+ border-color: #D9D9D9;
+}
+
+.login-wrapper .login-form .kuiTextInput.has-error {
+ border-color: #A30000;
+}
+
+.login-wrapper .login-form .btn-login {
+ width: 100%;
+}
+
+.login-wrapper .error-message {
+ color: #b4251d;
+ font-size: 14px;
+ margin-top: 16px;
+ margin-bottom: 0;
+ background-color: #f8e9e9;
+ padding: 8px;
+ font-weight: 400;
+ border-left: 2px solid #BD271E;
+}
+
+.loginWelcome__logo {
+ display: inline-block;
+ width: 80px;
+ height: 80px;
+ line-height: 80px;
+ text-align: center;
+ background-color: #FFF;
+ border-radius: 100%;
+ padding: 16px;
+ box-shadow: 0 6px 12px -1px rgba(152, 162, 179, 0.2), 0 4px 4px -1px rgba(152, 162, 179, 0.2), 0 2px 2px 0 rgba(152, 162, 179, 0.2);
+ margin-bottom: 32px;
+}
+
+.loginWelcome__logo {
+ background: url(./wazuh_logo_circle.svg) center center no-repeat !important;
+}
\ No newline at end of file
diff --git a/kibana-opendistro/config/custom_welcome/template.js.hbs b/kibana-opendistro/config/custom_welcome/template.js.hbs
new file mode 100644
index 00000000..54255bca
--- /dev/null
+++ b/kibana-opendistro/config/custom_welcome/template.js.hbs
@@ -0,0 +1,112 @@
+var kbnCsp = JSON.parse(document.querySelector('kbn-csp').getAttribute('data'));
+window.__kbnStrictCsp__ = kbnCsp.strictCsp;
+window.__kbnDarkMode__ = {{darkMode}};
+window.__kbnPublicPath__ = {{publicPathMap}};
+
+if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) {
+ var legacyBrowserError = document.getElementById('kbn_legacy_browser_error');
+ legacyBrowserError.style.display = 'flex';
+} else {
+ if (!window.__kbnCspNotEnforced__ && window.console) {
+ window.console.log("^ A single error about an inline script not firing due to content security policy is expected!");
+ }
+ var loadingMessage = document.getElementById('kbn_loading_message');
+ loadingMessage.style.display = 'flex';
+
+ window.onload = function () {
+ //WAZUH
+ var interval = setInterval(() => {
+ var title = document.getElementsByClassName('login-title');
+ if ((title || []).length) {
+ clearInterval(interval);
+ title[0].textContent = "Welcome to Wazuh";
+ var subtitle = document.getElementsByClassName('login-subtitle');
+ subtitle[0].textContent = "The Open Source Security Platform";
+ var logo = document.getElementsByClassName('brand-image-container');
+ $(logo).append('');
+ }
+ })
+ //
+
+ function failure() {
+ // make subsequent calls to failure() noop
+ failure = function () {};
+
+ var err = document.createElement('h1');
+ err.style['color'] = 'white';
+ err.style['font-family'] = 'monospace';
+ err.style['text-align'] = 'center';
+ err.style['background'] = '#F44336';
+ err.style['padding'] = '25px';
+ err.innerText = document.querySelector('[data-error-message]').dataset.errorMessage;
+
+ document.body.innerHTML = err.outerHTML;
+ }
+
+var stylesheetTarget = document.querySelector('head meta[name="add-styles-here"]')
+ function loadStyleSheet(url, cb) {
+ var dom = document.createElement('link');
+ dom.rel = 'stylesheet';
+ dom.type = 'text/css';
+ dom.href = url;
+ dom.addEventListener('error', failure);
+ dom.addEventListener('load', cb);
+ document.head.insertBefore(dom, stylesheetTarget);
+ }
+
+ var scriptsTarget = document.querySelector('head meta[name="add-scripts-here"]')
+ function loadScript(url, cb) {
+ var dom = document.createElement('script');
+ {{!-- NOTE: async = false is used to trigger async-download/ordered-execution as outlined here: https://www.html5rocks.com/en/tutorials/speed/script-loading/ --}}
+ dom.async = false;
+ dom.src = url;
+ dom.addEventListener('error', failure);
+ dom.addEventListener('load', cb);
+ document.head.insertBefore(dom, scriptsTarget);
+ }
+
+ function load(urls, cb) {
+ var pending = urls.length;
+ urls.forEach(function (url) {
+ var innerCb = function () {
+ pending = pending - 1;
+ if (pending === 0 && typeof cb === 'function') {
+ cb();
+ }
+ }
+
+ if (typeof url !== 'string') {
+ load(url, innerCb);
+ } else if (url.slice(-4) === '.css') {
+ loadStyleSheet(url, innerCb);
+ } else {
+ loadScript(url, innerCb);
+ }
+ });
+ }
+
+ load([
+ {{#each jsDependencyPaths}}
+ '{{this}}',
+ {{/each}}
+ ], function () {
+ {{#unless legacyBundlePath}}
+ if (!__kbnBundles__ || !__kbnBundles__['entry/core'] || typeof __kbnBundles__['entry/core'].__kbnBootstrap__ !== 'function') {
+ console.error('entry/core bundle did not load correctly');
+ failure();
+ } else {
+ __kbnBundles__['entry/core'].__kbnBootstrap__()
+ }
+ {{/unless}}
+
+ load([
+ {{#if legacyBundlePath}}
+ '{{legacyBundlePath}}',
+ {{/if}}
+ {{#each styleSheetPaths}}
+ '{{this}}',
+ {{/each}}
+ ]);
+ });
+ }
+}
\ No newline at end of file
diff --git a/kibana-opendistro/config/custom_welcome/wazuh_logo_circle.svg b/kibana-opendistro/config/custom_welcome/wazuh_logo_circle.svg
new file mode 100644
index 00000000..45a61d74
--- /dev/null
+++ b/kibana-opendistro/config/custom_welcome/wazuh_logo_circle.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/kibana-opendistro/config/custom_welcome/wazuh_wazuh_bg.svg b/kibana-opendistro/config/custom_welcome/wazuh_wazuh_bg.svg
new file mode 100644
index 00000000..0c49c5c6
--- /dev/null
+++ b/kibana-opendistro/config/custom_welcome/wazuh_wazuh_bg.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/kibana-opendistro/config/entrypoint.sh b/kibana-opendistro/config/entrypoint.sh
new file mode 100644
index 00000000..f2c017f1
--- /dev/null
+++ b/kibana-opendistro/config/entrypoint.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+# Wazuh Docker Copyright (C) 2020 Wazuh Inc. (License GPLv2)
+
+set -e
+
+##############################################################################
+# Waiting for elasticsearch
+##############################################################################
+
+if [ "x${ELASTICSEARCH_URL}" == "x" ]; then
+ if [[ ${ENABLED_SECURITY} == "false" ]]; then
+ export el_url="http://elasticsearch:9200"
+ else
+ export el_url="https://elasticsearch:9200"
+ fi
+else
+ export el_url="${ELASTICSEARCH_URL}"
+fi
+
+if [[ ${ENABLED_SECURITY} == "false" || "x${ELASTICSEARCH_USERNAME}" == "x" || "x${ELASTICSEARCH_PASSWORD}" == "x" ]]; then
+ auth=""
+ # remove security plugin from kibana if elasticsearch is not using it either
+ /usr/share/kibana/bin/kibana-plugin remove opendistro_security
+else
+ export auth="--user ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} -k"
+fi
+
+until curl -XGET $el_url ${auth}; do
+ >&2 echo "Elastic is unavailable - sleeping"
+ sleep 5
+done
+
+sleep 2
+
+>&2 echo "Elasticsearch is up."
+
+
+##############################################################################
+# Waiting for wazuh alerts template
+##############################################################################
+
+strlen=0
+
+while [[ $strlen -eq 0 ]]
+do
+ template=$(curl ${auth} $el_url/_cat/templates/wazuh -s)
+ strlen=${#template}
+ >&2 echo "Wazuh alerts template not loaded - sleeping."
+ sleep 2
+done
+
+sleep 2
+
+>&2 echo "Wazuh alerts template is loaded."
+
+
+./wazuh_app_config.sh
+
+sleep 5
+
+./kibana_settings.sh &
+
+sleep 2
+
+/usr/local/bin/kibana-docker
diff --git a/kibana-opendistro/config/kibana_settings.sh b/kibana-opendistro/config/kibana_settings.sh
new file mode 100644
index 00000000..19cae116
--- /dev/null
+++ b/kibana-opendistro/config/kibana_settings.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+# Wazuh Docker Copyright (C) 2020 Wazuh Inc. (License GPLv2)
+
+WAZUH_MAJOR=4
+
+##############################################################################
+# Wait for the Kibana API to start. It is necessary to do it in this container
+# because the others are running Elastic Stack and we can not interrupt them.
+#
+# The following actions are performed:
+#
+# Add the wazuh alerts index as default.
+# Set the Discover time interval to 24 hours instead of 15 minutes.
+# Do not ask user to help providing usage statistics to Elastic.
+##############################################################################
+
+##############################################################################
+# Customize elasticsearch ip
+##############################################################################
+sed -i "s|elasticsearch.hosts:.*|elasticsearch.hosts: $el_url|g" /usr/share/kibana/config/kibana.yml
+# disable multitenancy
+sed -i "s|opendistro_security.multitenancy.enabled:.*|opendistro_security.multitenancy.enabled: false|g" /usr/share/kibana/config/kibana.yml
+
+# If KIBANA_INDEX was set, then change the default index in kibana.yml configuration file. If there was an index, then delete it and recreate.
+if [ "$KIBANA_INDEX" != "" ]; then
+ if grep -q 'kibana.index' /usr/share/kibana/config/kibana.yml; then
+ sed -i '/kibana.index/d' /usr/share/kibana/config/kibana.yml
+ fi
+ echo "kibana.index: $KIBANA_INDEX" >> /usr/share/kibana/config/kibana.yml
+fi
+
+while [[ "$(curl -XGET -I -s -o /dev/null -w '%{http_code}' -k https://127.0.0.1:5601/login)" != "200" ]]; do
+ echo "Waiting for Kibana API. Sleeping 5 seconds"
+ sleep 5
+done
+
+# Prepare index selection.
+echo "Kibana API is running"
+
+default_index="/tmp/default_index.json"
+
+cat > ${default_index} << EOF
+{
+ "changes": {
+ "defaultIndex": "wazuh-alerts-${WAZUH_MAJOR}.x-*"
+ }
+}
+EOF
+
+sleep 5
+# Add the wazuh alerts index as default.
+curl ${auth} -POST -k https://127.0.0.1:5601/api/kibana/settings -H "Content-Type: application/json" -H "kbn-xsrf: true" -d@${default_index}
+rm -f ${default_index}
+
+sleep 5
+# Configuring Kibana TimePicker.
+curl ${auth} -POST -k "https://127.0.0.1:5601/api/kibana/settings" -H "Content-Type: application/json" -H "kbn-xsrf: true" -d \
+'{"changes":{"timepicker:timeDefaults":"{\n \"from\": \"now-12h\",\n \"to\": \"now\",\n \"mode\": \"quick\"}"}}'
+
+echo "End settings"
diff --git a/kibana-opendistro/config/wazuh_app_config.sh b/kibana-opendistro/config/wazuh_app_config.sh
new file mode 100644
index 00000000..db1d8f82
--- /dev/null
+++ b/kibana-opendistro/config/wazuh_app_config.sh
@@ -0,0 +1,67 @@
+#!/bin/bash
+# Wazuh Docker Copyright (C) 2020 Wazuh Inc. (License GPLv2)
+
+wazuh_url="${WAZUH_API_URL:-https://wazuh}"
+wazuh_port="${API_PORT:-55000}"
+api_user="${API_USER:-wazuh}"
+api_password="${API_PASS:-wazuh}"
+
+kibana_config_file="/usr/share/kibana/optimize/wazuh/config/wazuh.yml"
+mkdir -p /usr/share/kibana/optimize/wazuh/config/
+touch $kibana_config_file
+
+declare -A CONFIG_MAP=(
+ [pattern]=$PATTERN
+ [checks.pattern]=$CHECKS_PATTERN
+ [checks.template]=$CHECKS_TEMPLATE
+ [checks.api]=$CHECKS_API
+ [checks.setup]=$CHECKS_SETUP
+ [extensions.pci]=$EXTENSIONS_PCI
+ [extensions.gdpr]=$EXTENSIONS_GDPR
+ [extensions.audit]=$EXTENSIONS_AUDIT
+ [extensions.oscap]=$EXTENSIONS_OSCAP
+ [extensions.ciscat]=$EXTENSIONS_CISCAT
+ [extensions.aws]=$EXTENSIONS_AWS
+ [extensions.virustotal]=$EXTENSIONS_VIRUSTOTAL
+ [extensions.osquery]=$EXTENSIONS_OSQUERY
+ [timeout]=$APP_TIMEOUT
+ [wazuh.shards]=$WAZUH_SHARDS
+ [wazuh.replicas]=$WAZUH_REPLICAS
+ [wazuh-version.shards]=$WAZUH_VERSION_SHARDS
+ [wazuh-version.replicas]=$WAZUH_VERSION_REPLICAS
+ [ip.selector]=$IP_SELECTOR
+ [ip.ignore]=$IP_IGNORE
+ [wazuh.monitoring.enabled]=$WAZUH_MONITORING_ENABLED
+ [wazuh.monitoring.frequency]=$WAZUH_MONITORING_FREQUENCY
+ [wazuh.monitoring.shards]=$WAZUH_MONITORING_SHARDS
+ [wazuh.monitoring.replicas]=$WAZUH_MONITORING_REPLICAS
+ [admin]=$ADMIN_PRIVILEGES
+)
+
+for i in "${!CONFIG_MAP[@]}"
+do
+ if [ "${CONFIG_MAP[$i]}" != "" ]; then
+ sed -i 's/.*#'"$i"'.*/'"$i"': '"${CONFIG_MAP[$i]}"'/' $kibana_config_file
+ fi
+done
+
+# remove default API entry (new in 3.11.0_7.5.1)
+sed -ie '/- default:/,+4d' $kibana_config_file
+
+CONFIG_CODE=$(curl ${auth} -s -o /dev/null -w "%{http_code}" -XGET $el_url/.wazuh/_doc/1513629884013)
+
+grep -q 1513629884013 $kibana_config_file
+_config_exists=$?
+
+if [[ "x$CONFIG_CODE" != "x200" && $_config_exists -ne 0 ]]; then
+cat << EOF > $kibana_config_file
+hosts:
+ - 1513629884013:
+ url: $wazuh_url
+ port: $wazuh_port
+ username: $api_user
+ password: $api_password
+EOF
+else
+ echo "Wazuh APP already configured"
+fi
diff --git a/kibana-opendistro/config/welcome_wazuh.sh b/kibana-opendistro/config/welcome_wazuh.sh
new file mode 100644
index 00000000..46aaddfa
--- /dev/null
+++ b/kibana-opendistro/config/welcome_wazuh.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+# Wazuh Docker Copyright (C) 2020 Wazuh Inc. (License GPLv2)
+
+if [[ $CHANGE_WELCOME == "true" ]]
+then
+ echo "Set Wazuh app as the default landing page"
+ echo "server.defaultRoute: /app/wazuh" >> /usr/share/kibana/config/kibana.yml
+
+ echo "Set custom welcome styles"
+ cp -f /tmp/custom_welcome/template.js.hbs /usr/share/kibana/src/legacy/ui/ui_render/bootstrap/template.js.hbs
+ cp -f /tmp/custom_welcome/security-login.style.css /usr/share/kibana/optimize/bundles/security-login.style.css
+ cp -f /tmp/custom_welcome/*svg /usr/share/kibana/optimize/bundles/
+fi
+
diff --git a/nginx_conf/kibana-web.conf b/nginx_conf/kibana-web.conf
index b3821747..9ac5b667 100644
--- a/nginx_conf/kibana-web.conf
+++ b/nginx_conf/kibana-web.conf
@@ -10,11 +10,11 @@ server {
ssl_certificate /etc/nginx/conf.d/ssl/kibana-access.pem;
ssl_certificate_key /etc/nginx/conf.d/ssl/kibana-access.key;
location / {
- auth_basic "Restricted Access";
- auth_basic_user_file /etc/nginx/conf.d/kibana.htpasswd;
+ # auth_basic "Restricted Access";
+ # auth_basic_user_file /etc/nginx/conf.d/kibana.htpasswd;
proxy_pass http://kibana:5601/;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
-}
+}
diff --git a/wazuh-opendistro/Dockerfile b/wazuh-opendistro/Dockerfile
new file mode 100644
index 00000000..dd76e266
--- /dev/null
+++ b/wazuh-opendistro/Dockerfile
@@ -0,0 +1,54 @@
+# Wazuh Docker Copyright (C) 2020 Wazuh Inc. (License GPLv2)
+FROM centos:7
+
+ARG FILEBEAT_VERSION=7.8.0
+ARG WAZUH_VERSION=4.0.0-1
+ARG TEMPLATE_VERSION="develop"
+ARG WAZUH_FILEBEAT_MODULE="wazuh-filebeat-0.2.tar.gz"
+
+ENV API_USER="foo" \
+ API_PASS="bar"
+
+
+# Set repositories.
+RUN rpm --import https://packages.wazuh.com/key/GPG-KEY-WAZUH
+
+COPY config/wazuh.repo /etc/yum.repos.d/wazuh.repo
+
+RUN yum --enablerepo=updates clean metadata && \
+ yum -y install openssl which && yum -y install wazuh-manager-${WAZUH_VERSION} -y && \
+ sed -i "s/^enabled=1/enabled=0/" /etc/yum.repos.d/wazuh.repo && \
+ yum clean all && rm -rf /var/cache/yum
+
+RUN curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-oss-${FILEBEAT_VERSION}-x86_64.rpm &&\
+ rpm -i filebeat-oss-${FILEBEAT_VERSION}-x86_64.rpm && rm -f filebeat-oss-${FILEBEAT_VERSION}-x86_64.rpm
+
+RUN curl -s https://packages-dev.wazuh.com/utils/${WAZUH_FILEBEAT_MODULE} | tar -xvz -C /usr/share/filebeat/module
+
+ARG S6_VERSION="v2.0.0.1"
+RUN curl --fail --silent -L https://github.com/just-containers/s6-overlay/releases/download/${S6_VERSION}/s6-overlay-amd64.tar.gz \
+ -o /tmp/s6-overlay-amd64.tar.gz && \
+ tar xzf /tmp/s6-overlay-amd64.tar.gz -C / --exclude="./bin" && \
+ tar xzf /tmp/s6-overlay-amd64.tar.gz -C /usr ./bin && \
+ rm /tmp/s6-overlay-amd64.tar.gz
+
+COPY config/filebeat.yml /etc/filebeat/
+
+RUN chmod go-w /etc/filebeat/filebeat.yml
+
+ADD https://raw.githubusercontent.com/wazuh/wazuh/$TEMPLATE_VERSION/extensions/elasticsearch/7.x/wazuh-template.json /etc/filebeat
+RUN chmod go-w /etc/filebeat/wazuh-template.json
+
+COPY config/etc/ /etc/
+
+# Prepare permanent data
+# Sync calls are due to https://github.com/docker/docker/issues/9547
+COPY config/permanent_data.env config/permanent_data.sh /
+RUN chmod 755 /permanent_data.sh && \
+ sync && /permanent_data.sh && \
+ sync && rm /permanent_data.sh
+
+# Services ports
+EXPOSE 55000/tcp 1514/tcp 1515/tcp 514/udp 1516/tcp
+
+ENTRYPOINT [ "/init" ]
diff --git a/wazuh-opendistro/config/etc/cont-init.d/0-wazuh-init b/wazuh-opendistro/config/etc/cont-init.d/0-wazuh-init
new file mode 100644
index 00000000..1aa78f65
--- /dev/null
+++ b/wazuh-opendistro/config/etc/cont-init.d/0-wazuh-init
@@ -0,0 +1,164 @@
+#!/usr/bin/with-contenv bash
+# Wazuh App Copyright (C) 2020 Wazuh Inc. (License GPLv2)
+
+# Variables
+source /permanent_data.env
+
+WAZUH_INSTALL_PATH=/var/ossec
+WAZUH_CONFIG_MOUNT=/wazuh-config-mount
+AUTO_ENROLLMENT_ENABLED=${AUTO_ENROLLMENT_ENABLED:-true}
+
+
+##############################################################################
+# Aux functions
+##############################################################################
+print() {
+ echo -e $1
+}
+
+error_and_exit() {
+ echo "Error executing command: '$1'."
+ echo 'Exiting.'
+ exit 1
+}
+
+exec_cmd() {
+ eval $1 > /dev/null 2>&1 || error_and_exit "$1"
+}
+
+exec_cmd_stdout() {
+ eval $1 2>&1 || error_and_exit "$1"
+}
+
+
+##############################################################################
+# This function will attempt to mount every directory in PERMANENT_DATA
+# into the respective path.
+# If the path is empty means permanent data volume is also empty, so a backup
+# will be copied into it. Otherwise it will not be copied because there is
+# already data inside the volume for the specified path.
+##############################################################################
+
+mount_permanent_data() {
+ for permanent_dir in "${PERMANENT_DATA[@]}"; do
+ # Check if the path is not empty
+ if find ${permanent_dir} -mindepth 1 | read; then
+ print "The path ${permanent_dir} is already mounted"
+ else
+ print "Installing ${permanent_dir}"
+ exec_cmd "cp -a ${WAZUH_INSTALL_PATH}/data_tmp/permanent${permanent_dir}/. ${permanent_dir}"
+ fi
+ done
+}
+
+##############################################################################
+# This function will replace from the permanent data volume every file
+# contained in PERMANENT_DATA_EXCP
+# Some files as 'internal_options.conf' are saved as permanent data, but
+# they must be updated to work properly if wazuh version is changed.
+##############################################################################
+
+apply_exclusion_data() {
+ for exclusion_file in "${PERMANENT_DATA_EXCP[@]}"; do
+ if [ -e ${WAZUH_INSTALL_PATH}/data_tmp/exclusion/${exclusion_file} ]
+ then
+ DIR=$(dirname "${exclusion_file}")
+ if [ ! -e ${DIR} ]
+ then
+ mkdir -p ${DIR}
+ fi
+
+ print "Updating ${exclusion_file}"
+ exec_cmd "cp -p ${WAZUH_INSTALL_PATH}/data_tmp/exclusion/${exclusion_file} ${exclusion_file}"
+ fi
+ done
+}
+
+##############################################################################
+# This function will delete from the permanent data volume every file
+# contained in PERMANENT_DATA_DEL
+##############################################################################
+
+remove_data_files() {
+ for del_file in "${PERMANENT_DATA_DEL[@]}"; do
+ if [ -e ${del_file} ]
+ then
+ print "Removing ${del_file}"
+ exec_cmd "rm ${del_file}"
+ fi
+ done
+}
+
+##############################################################################
+# Create certificates: Manager
+##############################################################################
+
+create_ossec_key_cert() {
+ print "Creating ossec-authd key and cert"
+ exec_cmd "openssl genrsa -out ${WAZUH_INSTALL_PATH}/etc/sslmanager.key 4096"
+ exec_cmd "openssl req -new -x509 -key ${WAZUH_INSTALL_PATH}/etc/sslmanager.key -out ${WAZUH_INSTALL_PATH}/etc/sslmanager.cert -days 3650 -subj /CN=${HOSTNAME}/"
+}
+
+##############################################################################
+# Copy all files from $WAZUH_CONFIG_MOUNT to $WAZUH_INSTALL_PATH and respect
+# destination files permissions
+#
+# For example, to mount the file /var/ossec/data/etc/ossec.conf, mount it at
+# $WAZUH_CONFIG_MOUNT/etc/ossec.conf in your container and this code will
+# replace the ossec.conf file in /var/ossec/data/etc with yours.
+##############################################################################
+
+mount_files() {
+ if [ -e "$WAZUH_CONFIG_MOUNT" ]
+ then
+ print "Identified Wazuh configuration files to mount..."
+ exec_cmd_stdout "cp --verbose -r $WAZUH_CONFIG_MOUNT/* $WAZUH_INSTALL_PATH"
+ else
+ print "No Wazuh configuration files to mount..."
+ fi
+}
+
+##############################################################################
+# Stop OSSEC
+##############################################################################
+
+function ossec_shutdown(){
+ ${WAZUH_INSTALL_PATH}/bin/ossec-control stop;
+}
+
+
+##############################################################################
+# Main function
+##############################################################################
+
+main() {
+ # Mount permanent data (i.e. ossec.conf)
+ mount_permanent_data
+
+ # Restore files stored in permanent data that are not permanent (i.e. internal_options.conf)
+ apply_exclusion_data
+
+ # Remove some files in permanent_data (i.e. .template.db)
+ remove_data_files
+
+ # Generate ossec-authd certs if AUTO_ENROLLMENT_ENABLED is true and does not exist
+ if [ $AUTO_ENROLLMENT_ENABLED == true ]
+ then
+ if [ ! -e ${WAZUH_INSTALL_PATH}/etc/sslmanager.key ]
+ then
+ create_ossec_key_cert
+ fi
+ fi
+
+ # Mount selected files (WAZUH_CONFIG_MOUNT) to container
+ mount_files
+
+ # Trap exit signals and do a proper shutdown
+ trap "ossec_shutdown; exit" SIGINT SIGTERM
+
+ # Delete temporary data folder
+ rm -rf ${WAZUH_INSTALL_PATH}/data_tmp
+
+}
+
+main
diff --git a/wazuh-opendistro/config/etc/cont-init.d/1-config-filebeat b/wazuh-opendistro/config/etc/cont-init.d/1-config-filebeat
new file mode 100644
index 00000000..ce033aa5
--- /dev/null
+++ b/wazuh-opendistro/config/etc/cont-init.d/1-config-filebeat
@@ -0,0 +1,45 @@
+#!/usr/bin/with-contenv bash
+# Wazuh App Copyright (C) 2020 Wazuh Inc. (License GPLv2)
+
+set -e
+
+if [ "$ELASTICSEARCH_URL" != "" ]; then
+ >&2 echo "Customize Elasticsearch ouput IP"
+ sed -i "s|hosts:.*|hosts: ['$ELASTICSEARCH_URL']|g" /etc/filebeat/filebeat.yml
+fi
+
+# Configure filebeat.yml security settings
+
+if [ "$ELASTIC_USERNAME" != "" ]; then
+ >&2 echo "Configuring username."
+ sed -i "s|#username:.*|username: '$ELASTIC_USERNAME'|g" /etc/filebeat/filebeat.yml
+fi
+
+if [ "$ELASTIC_PASSWORD" != "" ]; then
+ >&2 echo "Configuring password."
+ sed -i "s|#password:.*|password: '$ELASTIC_PASSWORD'|g" /etc/filebeat/filebeat.yml
+fi
+
+if [ "$FILEBEAT_SSL_VERIFICATION_MODE" != "" ]; then
+ >&2 echo "Configuring SSL verification mode."
+ sed -i "s|#ssl.verification_mode:.*|ssl.verification_mode: $FILEBEAT_SSL_VERIFICATION_MODE|g" /etc/filebeat/filebeat.yml
+fi
+
+if [ "$SSL_CERTIFICATE_AUTHORITIES" != "" ]; then
+ >&2 echo "Configuring Certificate Authorities."
+ sed -i "s|#ssl.certificate_authorities:.*|ssl.certificate_authorities: ['$SSL_CERTIFICATE_AUTHORITIES']|g" /etc/filebeat/filebeat.yml
+fi
+
+if [ "$SSL_CERTIFICATE" != "" ]; then
+ >&2 echo "Configuring SSL Certificate."
+ sed -i "s|#ssl.certificate:.*|ssl.certificate: '$SSL_CERTIFICATE'|g" /etc/filebeat/filebeat.yml
+fi
+
+if [ "$SSL_KEY" != "" ]; then
+ >&2 echo "Configuring SSL Key."
+ sed -i "s|#ssl.key:.*|ssl.key: '$SSL_KEY'|g" /etc/filebeat/filebeat.yml
+fi
+
+
+chmod go-w /etc/filebeat/filebeat.yml || true
+chown root: /etc/filebeat/filebeat.yml || true
diff --git a/wazuh-opendistro/config/etc/cont-init.d/2-manager b/wazuh-opendistro/config/etc/cont-init.d/2-manager
new file mode 100644
index 00000000..6ce02ae2
--- /dev/null
+++ b/wazuh-opendistro/config/etc/cont-init.d/2-manager
@@ -0,0 +1,3 @@
+#!/usr/bin/with-contenv bash
+
+/var/ossec/bin/ossec-control start
diff --git a/wazuh-opendistro/config/etc/services.d/filebeat/finish b/wazuh-opendistro/config/etc/services.d/filebeat/finish
new file mode 100644
index 00000000..8813eb67
--- /dev/null
+++ b/wazuh-opendistro/config/etc/services.d/filebeat/finish
@@ -0,0 +1,6 @@
+#!/usr/bin/env sh
+echo >&2 "Filebeat exited. code=${1}"
+
+# terminate other services to exit from the container
+exec s6-svscanctl -t /var/run/s6/services
+
diff --git a/wazuh-opendistro/config/etc/services.d/filebeat/run b/wazuh-opendistro/config/etc/services.d/filebeat/run
new file mode 100644
index 00000000..706ee5af
--- /dev/null
+++ b/wazuh-opendistro/config/etc/services.d/filebeat/run
@@ -0,0 +1,4 @@
+#!/usr/bin/with-contenv sh
+echo >&2 "starting Filebeat"
+
+exec /usr/share/filebeat/bin/filebeat -e -c /etc/filebeat/filebeat.yml -path.home /usr/share/filebeat -path.config /etc/filebeat -path.data /var/lib/filebeat -path.logs /var/log/filebeat
diff --git a/wazuh-opendistro/config/filebeat.yml b/wazuh-opendistro/config/filebeat.yml
new file mode 100644
index 00000000..8a627bf9
--- /dev/null
+++ b/wazuh-opendistro/config/filebeat.yml
@@ -0,0 +1,22 @@
+
+# Wazuh - Filebeat configuration file
+filebeat.modules:
+ - module: wazuh
+ alerts:
+ enabled: true
+ archives:
+ enabled: false
+
+setup.template.json.enabled: true
+setup.template.json.path: '/etc/filebeat/wazuh-template.json'
+setup.template.json.name: 'wazuh'
+setup.template.overwrite: true
+setup.ilm.enabled: false
+output.elasticsearch:
+ hosts: ['https://elasticsearch:9200']
+ #username:
+ #password:
+ #ssl.verification_mode:
+ #ssl.certificate_authorities:
+ #ssl.certificate:
+ #ssl.key:
diff --git a/wazuh-opendistro/config/permanent_data.env b/wazuh-opendistro/config/permanent_data.env
new file mode 100644
index 00000000..9c2556d8
--- /dev/null
+++ b/wazuh-opendistro/config/permanent_data.env
@@ -0,0 +1,67 @@
+# Permanent data mounted in volumes
+i=0
+PERMANENT_DATA[((i++))]="/var/ossec/api/configuration"
+PERMANENT_DATA[((i++))]="/var/ossec/etc"
+PERMANENT_DATA[((i++))]="/var/ossec/logs"
+PERMANENT_DATA[((i++))]="/var/ossec/queue"
+PERMANENT_DATA[((i++))]="/var/ossec/agentless"
+PERMANENT_DATA[((i++))]="/var/ossec/var/multigroups"
+PERMANENT_DATA[((i++))]="/var/ossec/integrations"
+PERMANENT_DATA[((i++))]="/var/ossec/active-response/bin"
+PERMANENT_DATA[((i++))]="/var/ossec/wodles"
+PERMANENT_DATA[((i++))]="/etc/filebeat"
+export PERMANENT_DATA
+
+# Files mounted in a volume that should not be permanent
+i=0
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/etc/internal_options.conf"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/integrations/pagerduty"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/integrations/slack"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/integrations/slack.py"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/integrations/virustotal"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/integrations/virustotal.py"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/active-response/bin/default-firewall-drop.sh"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/active-response/bin/disable-account.sh"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/active-response/bin/firewalld-drop.sh"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/active-response/bin/firewall-drop.sh"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/active-response/bin/host-deny.sh"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/active-response/bin/ip-customblock.sh"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/active-response/bin/ipfw_mac.sh"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/active-response/bin/ipfw.sh"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/active-response/bin/kaspersky.py"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/active-response/bin/kaspersky.sh"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/active-response/bin/npf.sh"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/active-response/bin/ossec-slack.sh"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/active-response/bin/ossec-tweeter.sh"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/active-response/bin/pf.sh"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/active-response/bin/restart-ossec.sh"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/active-response/bin/restart.sh"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/active-response/bin/route-null.sh"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/agentless/sshlogin.exp"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/agentless/ssh_pixconfig_diff"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/agentless/ssh_asa-fwsmconfig_diff"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/agentless/ssh_integrity_check_bsd"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/agentless/main.exp"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/agentless/su.exp"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/agentless/ssh_integrity_check_linux"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/agentless/register_host.sh"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/agentless/ssh_generic_diff"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/agentless/ssh_foundry_diff"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/agentless/ssh_nopass.exp"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/agentless/ssh.exp"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/wodles/aws/aws-s3"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/wodles/aws/aws-s3.py"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/wodles/azure/azure-logs"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/wodles/azure/azure-logs.py"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/wodles/docker/DockerListener"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/wodles/docker/DockerListener.py"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/wodles/gcloud/gcloud"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/wodles/gcloud/gcloud.py"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/wodles/gcloud/integration.py"
+PERMANENT_DATA_EXCP[((i++))]="/var/ossec/wodles/gcloud/tools.py"
+export PERMANENT_DATA_EXCP
+
+# Files mounted in a volume that should be deleted
+i=0
+PERMANENT_DATA_DEL[((i++))]="/var/ossec/queue/db/.template.db"
+export PERMANENT_DATA_DEL
diff --git a/wazuh-opendistro/config/permanent_data.sh b/wazuh-opendistro/config/permanent_data.sh
new file mode 100644
index 00000000..7dfaa647
--- /dev/null
+++ b/wazuh-opendistro/config/permanent_data.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# Wazuh App Copyright (C) 2020 Wazuh Inc. (License GPLv2)
+
+# Variables
+source /permanent_data.env
+
+WAZUH_INSTALL_PATH=/var/ossec
+DATA_TMP_PATH=${WAZUH_INSTALL_PATH}/data_tmp
+mkdir ${DATA_TMP_PATH}
+
+# Move exclusion files to EXCLUSION_PATH
+EXCLUSION_PATH=${DATA_TMP_PATH}/exclusion
+mkdir ${EXCLUSION_PATH}
+
+for exclusion_file in "${PERMANENT_DATA_EXCP[@]}"; do
+ # Create the directory for the exclusion file if it does not exist
+ DIR=$(dirname "${exclusion_file}")
+ if [ ! -e ${EXCLUSION_PATH}/${DIR} ]
+ then
+ mkdir -p ${EXCLUSION_PATH}/${DIR}
+ fi
+
+ mv ${exclusion_file} ${EXCLUSION_PATH}/${exclusion_file}
+done
+
+# Move permanent files to PERMANENT_PATH
+PERMANENT_PATH=${DATA_TMP_PATH}/permanent
+mkdir ${PERMANENT_PATH}
+
+for permanent_dir in "${PERMANENT_DATA[@]}"; do
+ # Create the directory for the permanent file if it does not exist
+ DIR=$(dirname "${permanent_dir}")
+ if [ ! -e ${PERMANENT_PATH}${DIR} ]
+ then
+ mkdir -p ${PERMANENT_PATH}${DIR}
+ fi
+
+ mv ${permanent_dir} ${PERMANENT_PATH}${permanent_dir}
+
+done
diff --git a/wazuh-opendistro/config/wazuh.repo b/wazuh-opendistro/config/wazuh.repo
new file mode 100644
index 00000000..15e1b822
--- /dev/null
+++ b/wazuh-opendistro/config/wazuh.repo
@@ -0,0 +1,7 @@
+[wazuh_repo]
+gpgcheck=1
+gpgkey=https://packages.wazuh.com/key/GPG-KEY-WAZUH
+enabled=1
+name=Wazuh repository
+baseurl=https://packages-dev.wazuh.com/pre-release/yum/
+protect=1