mirror of
https://github.com/valitydev/wazuh-docker.git
synced 2024-11-06 01:35:18 +00:00
parent
de6d0ba8a9
commit
27dc788514
4
.gitmodules
vendored
Normal file
4
.gitmodules
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
[submodule "build_utils"]
|
||||
path = build_utils
|
||||
url = git@github.com:rbkmoney/build_utils.git
|
||||
branch = master
|
41
Jenkinsfile
vendored
Normal file
41
Jenkinsfile
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
#!groovy
|
||||
// -*- mode: groovy -*-
|
||||
|
||||
build('wazuh-docker', 'docker-host') {
|
||||
checkoutRepo()
|
||||
loadBuildUtils()
|
||||
|
||||
def pipeDefault
|
||||
def withWsCache
|
||||
runStage('load pipeline') {
|
||||
env.JENKINS_LIB = "build_utils/jenkins_lib"
|
||||
pipeDefault = load("${env.JENKINS_LIB}/pipeDefault.groovy")
|
||||
withWsCache = load("${env.JENKINS_LIB}/withWsCache.groovy")
|
||||
}
|
||||
|
||||
pipeDefault() {
|
||||
runStage('build wazuh image') {
|
||||
sh "cd wazuh && make build_image"
|
||||
}
|
||||
runStage('build kibana image') {
|
||||
sh "cd kibana && make build_image"
|
||||
}
|
||||
try {
|
||||
if (masterlikeBranch()) {
|
||||
runStage('push wazuh image') {
|
||||
sh "cd wazuh && make push_image"
|
||||
}
|
||||
runStage('push kibana image') {
|
||||
sh "cd kibana && make push_image"
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
runStage('rm wazuh local image') {
|
||||
sh 'cd wazuh && make rm_local_image'
|
||||
}
|
||||
runStage('rm kibana local image') {
|
||||
sh 'cd kibana && make rm_local_image'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
build_utils
Submodule
1
build_utils
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit ccf618949b95590d572157b248289428abeaa2e5
|
8
kibana/Dockerfile → kibana/Dockerfile.sh
Normal file → Executable file
8
kibana/Dockerfile → kibana/Dockerfile.sh
Normal file → Executable file
@ -1,5 +1,6 @@
|
||||
#!/bin/bash
|
||||
# Wazuh Docker Copyright (C) 2020 Wazuh Inc. (License GPLv2)
|
||||
|
||||
cat <<EOF
|
||||
FROM centos:7 as plugin_builder
|
||||
|
||||
ARG KIBANA_PLUGIN_VERSION="v3.12.3-6.8.1"
|
||||
@ -12,13 +13,13 @@ RUN rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 && \
|
||||
ADD ./config/build.sh /
|
||||
RUN chmod +x /build.sh && \
|
||||
mkdir /wazuh_app /source && \
|
||||
/build.sh ${KIBANA_PLUGIN_VERSION}
|
||||
/build.sh \${KIBANA_PLUGIN_VERSION}
|
||||
|
||||
FROM docker.elastic.co/kibana/kibana-oss:6.8.1
|
||||
USER kibana
|
||||
ARG ELASTIC_VERSION=6.8.1
|
||||
ARG WAZUH_VERSION=3.12.3
|
||||
ARG WAZUH_APP_VERSION="${WAZUH_VERSION}_${ELASTIC_VERSION}"
|
||||
ARG WAZUH_APP_VERSION="\${WAZUH_VERSION}_\${ELASTIC_VERSION}"
|
||||
|
||||
COPY --from=plugin_builder /wazuh_app/wazuh_kibana-*.zip /tmp/wazuh_kibana.zip
|
||||
|
||||
@ -90,3 +91,4 @@ USER kibana
|
||||
RUN NODE_OPTIONS="--max-old-space-size=2048" /usr/local/bin/kibana-docker --optimize
|
||||
|
||||
ENTRYPOINT ./entrypoint.sh
|
||||
EOF
|
33
kibana/Makefile
Normal file
33
kibana/Makefile
Normal file
@ -0,0 +1,33 @@
|
||||
SUBMODULES = build_utils
|
||||
SUBTARGETS = $(patsubst %,%/.git,$(SUBMODULES))
|
||||
|
||||
UTILS_PATH := ../build_utils
|
||||
TEMPLATES_PATH := .
|
||||
|
||||
# Name of the service
|
||||
SERVICE_NAME := wazuh-kibana
|
||||
# Service image default tag
|
||||
SERVICE_IMAGE_TAG ?= $(shell git rev-parse HEAD)
|
||||
# The tag for service image to be pushed with
|
||||
SERVICE_IMAGE_PUSH_TAG ?= $(SERVICE_IMAGE_TAG)
|
||||
|
||||
# Base image for the service
|
||||
BASE_IMAGE_NAME := empty
|
||||
BASE_IMAGE_TAG := empty
|
||||
BUILD_IMAGE_TAG := empty
|
||||
|
||||
CALL_ANYWHERE := all
|
||||
|
||||
CALL_W_CONTAINER := $(CALL_ANYWHERE)
|
||||
|
||||
-include $(UTILS_PATH)/make_lib/utils_container.mk
|
||||
-include $(UTILS_PATH)/make_lib/utils_image.mk
|
||||
|
||||
.PHONY: $(CALL_W_CONTAINER)
|
||||
|
||||
# CALL_ANYWHERE
|
||||
$(SUBTARGETS): %/.git: %
|
||||
git submodule update --init $<
|
||||
touch $@
|
||||
|
||||
submodules: $(SUBTARGETS)
|
@ -73,10 +73,10 @@ RUN mkdir -p /etc/service/wazuh && \
|
||||
COPY config/wazuh.runit.service /etc/service/wazuh/run
|
||||
COPY config/wazuh-api.runit.service /etc/service/wazuh-api/run
|
||||
COPY config/filebeat.runit.service /etc/service/filebeat/run
|
||||
COPY config/office365.py /var/ossec/bin/office365.py
|
||||
|
||||
RUN chmod +x /etc/service/wazuh-api/run && \
|
||||
chmod +x /etc/service/wazuh/run && \
|
||||
chmod +x /etc/service/filebeat/run
|
||||
RUN chmod +x /etc/service/wazuh-api/run /etc/service/wazuh/run \
|
||||
/etc/service/filebeat/run /var/ossec/bin/office365.py
|
||||
|
||||
# Run all services
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
85
wazuh/Dockerfile.sh
Executable file
85
wazuh/Dockerfile.sh
Executable file
@ -0,0 +1,85 @@
|
||||
#!/bin/bash
|
||||
# Wazuh Docker Copyright (C) 2020 Wazuh Inc. (License GPLv2)
|
||||
cat <<EOF
|
||||
FROM phusion/baseimage:bionic-1.0.0
|
||||
|
||||
ARG FILEBEAT_VERSION=6.8.1
|
||||
ARG WAZUH_VERSION=3.12.3-1
|
||||
|
||||
ENV WAZUH_FILEBEAT_MODULE=wazuh-filebeat-0.1.tar.gz
|
||||
|
||||
ENV API_USER="foo" \
|
||||
API_PASS="bar"
|
||||
|
||||
ARG TEMPLATE_VERSION="v3.12.3"
|
||||
|
||||
# Set repositories.
|
||||
RUN apt update && apt-get upgrade -y -o Dpkg::Options::="--force-confold" && \
|
||||
apt -y install curl apt-transport-https lsb-release gnupg2 software-properties-common && \
|
||||
set -x && echo "deb https://packages.wazuh.com/3.x/apt/ stable main" | tee /etc/apt/sources.list.d/wazuh.list && \
|
||||
curl -s https://packages.wazuh.com/key/GPG-KEY-WAZUH | apt-key add - && \
|
||||
curl --silent --location https://deb.nodesource.com/setup_10.x | bash - && \
|
||||
groupadd -g 1000 ossec && useradd -u 1000 -g 1000 -d /var/ossec ossec
|
||||
|
||||
RUN add-apt-repository universe && apt-get update && apt-get upgrade -y -o Dpkg::Options::="--force-confold" && \
|
||||
apt-get --no-install-recommends --no-install-suggests -y install openssl python-boto python-pip \
|
||||
apt-transport-https vim expect nodejs python-cryptography libsasl2-modules wazuh-manager=\${WAZUH_VERSION} \
|
||||
wazuh-api=\${WAZUH_VERSION} && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && rm -f \
|
||||
/var/ossec/logs/alerts/*/*/*.log && rm -f /var/ossec/logs/alerts/*/*/*.json && rm -f \
|
||||
/var/ossec/logs/archives/*/*/*.log && rm -f /var/ossec/logs/archives/*/*/*.json && rm -f \
|
||||
/var/ossec/logs/firewall/*/*/*.log && rm -f /var/ossec/logs/firewall/*/*/*.json
|
||||
|
||||
# Install Wazuh Filebeat Module
|
||||
|
||||
RUN mkdir -p /usr/share/filebeat/module/wazuh && \
|
||||
curl -s "https://packages.wazuh.com/3.x/filebeat/\${WAZUH_FILEBEAT_MODULE}" | tar -xvz -C /usr/share/filebeat/module && \
|
||||
chmod 755 -R /usr/share/filebeat/module/wazuh
|
||||
|
||||
RUN curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-oss-\${FILEBEAT_VERSION}-amd64.deb && \
|
||||
dpkg -i filebeat-oss-\${FILEBEAT_VERSION}-amd64.deb && rm -f filebeat-oss-\${FILEBEAT_VERSION}-amd64.deb
|
||||
|
||||
RUN curl -sL https://raw.githubusercontent.com/wazuh/wazuh/\$TEMPLATE_VERSION/extensions/elasticsearch/6.x/wazuh-template.json -o /etc/filebeat/wazuh-template.json && \
|
||||
sed -i 's@"wazuh":@"doc":@' /etc/filebeat/wazuh-template.json && \
|
||||
chmod go-w /etc/filebeat/wazuh-template.json
|
||||
|
||||
# Adding first run script and entrypoint
|
||||
COPY config/data_dirs.env /data_dirs.env
|
||||
COPY config/init.bash /init.bash
|
||||
RUN mkdir /entrypoint-scripts
|
||||
COPY config/entrypoint.sh /entrypoint.sh
|
||||
COPY config/00-wazuh.sh /entrypoint-scripts/00-wazuh.sh
|
||||
|
||||
# Sync calls are due to https://github.com/docker/docker/issues/9547
|
||||
RUN chmod 755 /entrypoint.sh && \
|
||||
chmod 755 /entrypoint-scripts/00-wazuh.sh
|
||||
|
||||
COPY config/filebeat.yml /etc/filebeat/
|
||||
RUN chmod go-w /etc/filebeat/filebeat.yml
|
||||
|
||||
# Setting volumes
|
||||
|
||||
VOLUME ["/etc/filebeat"]
|
||||
VOLUME ["/var/lib/filebeat"]
|
||||
VOLUME ["/var/log/filebeat/"]
|
||||
VOLUME ["/var/ossec/data/logs/"]
|
||||
VOLUME ["/wazuh-config-mount"]
|
||||
|
||||
# Services ports
|
||||
EXPOSE 514/udp 1514/udp 1514/tcp 1515/tcp 1516/tcp 55000/tcp
|
||||
|
||||
# Adding services
|
||||
RUN mkdir -p /etc/service/wazuh && \
|
||||
mkdir /etc/service/wazuh-api && \
|
||||
mkdir /etc/service/filebeat
|
||||
|
||||
COPY config/wazuh.runit.service /etc/service/wazuh/run
|
||||
COPY config/wazuh-api.runit.service /etc/service/wazuh-api/run
|
||||
COPY config/filebeat.runit.service /etc/service/filebeat/run
|
||||
COPY config/office365.py /var/ossec/bin/office365.py
|
||||
|
||||
RUN chmod +x /etc/service/wazuh-api/run /etc/service/wazuh/run \
|
||||
/etc/service/filebeat/run /var/ossec/bin/office365.py
|
||||
|
||||
# Run all services
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
EOF
|
33
wazuh/Makefile
Normal file
33
wazuh/Makefile
Normal file
@ -0,0 +1,33 @@
|
||||
SUBMODULES = build_utils
|
||||
SUBTARGETS = $(patsubst %,%/.git,$(SUBMODULES))
|
||||
|
||||
UTILS_PATH := ../build_utils
|
||||
TEMPLATES_PATH := .
|
||||
|
||||
# Name of the service
|
||||
SERVICE_NAME := wazuh
|
||||
# Service image default tag
|
||||
SERVICE_IMAGE_TAG ?= $(shell git rev-parse HEAD)
|
||||
# The tag for service image to be pushed with
|
||||
SERVICE_IMAGE_PUSH_TAG ?= $(SERVICE_IMAGE_TAG)
|
||||
|
||||
# Base image for the service
|
||||
BASE_IMAGE_NAME := empty
|
||||
BASE_IMAGE_TAG := empty
|
||||
BUILD_IMAGE_TAG := empty
|
||||
|
||||
CALL_ANYWHERE := all
|
||||
|
||||
CALL_W_CONTAINER := $(CALL_ANYWHERE)
|
||||
|
||||
-include $(UTILS_PATH)/make_lib/utils_container.mk
|
||||
-include $(UTILS_PATH)/make_lib/utils_image.mk
|
||||
|
||||
.PHONY: $(CALL_W_CONTAINER)
|
||||
|
||||
# CALL_ANYWHERE
|
||||
$(SUBTARGETS): %/.git: %
|
||||
git submodule update --init $<
|
||||
touch $@
|
||||
|
||||
submodules: $(SUBTARGETS)
|
150
wazuh/config/office365.py
Normal file
150
wazuh/config/office365.py
Normal file
@ -0,0 +1,150 @@
|
||||
#!/var/ossec/framework/python/bin/python3
|
||||
|
||||
# Copyright (C) 2015-2020, Wazuh Inc.
|
||||
# Created by Wazuh, Inc. <info@wazuh.com>.
|
||||
# This program is a free software; you can redistribute it and/or modify it under the terms of GPLv2
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import json
|
||||
import requests
|
||||
import logging
|
||||
import datetime
|
||||
from socket import socket, AF_UNIX, SOCK_DGRAM
|
||||
|
||||
################################################## Global variables ##################################################
|
||||
|
||||
# Microsoft resource
|
||||
resource = "https://manage.office.com"
|
||||
|
||||
# Office 365 management activity API available content types
|
||||
availableContentTypes = ["Audit.AzureActiveDirectory", "Audit.Exchange", "Audit.SharePoint", "Audit.General", "DLP.All"]
|
||||
|
||||
# Wazuh manager analisysd socket address
|
||||
socketAddr = '/var/ossec/queue/ossec/queue'
|
||||
|
||||
################################################## Common functions ##################################################
|
||||
|
||||
# Send event to Wazuh manager
|
||||
def send_event(msg):
|
||||
logging.debug('Sending {} to {} socket.'.format(msg, socketAddr))
|
||||
string = '1:office_365:{}'.format(msg)
|
||||
sock = socket(AF_UNIX, SOCK_DGRAM)
|
||||
sock.connect(socketAddr)
|
||||
sock.send(string.encode())
|
||||
sock.close()
|
||||
|
||||
# Perform HTTP request
|
||||
def make_request(method, url, headers, data=None):
|
||||
response = requests.request(method, url, headers=headers, data=data)
|
||||
|
||||
# If the request succeed
|
||||
if response.status_code >= 200 and response.status_code < 210:
|
||||
return response
|
||||
if method == "POST" and response.status_code == 400:
|
||||
return response
|
||||
else:
|
||||
raise Exception('Request ', method, ' ', url, ' failed with ', response.status_code, ' - ', response.text)
|
||||
|
||||
# Obtain a token for accessing the Office 365 management activity API
|
||||
def obtain_access_token(tenantId, clientId, clientSecret):
|
||||
# Add header and payload
|
||||
headers = {'Content-Type':'application/x-www-form-urlencoded'}
|
||||
payload = 'client_id={}&scope={}/.default&grant_type=client_credentials&client_secret={}'.format(clientId, resource, clientSecret)
|
||||
|
||||
# Request token
|
||||
response = make_request("POST", "https://login.microsoftonline.com/{}/oauth2/v2.0/token".format(tenantId), headers=headers, data=payload)
|
||||
logging.info("Microsoft token was successfully fetched.")
|
||||
|
||||
return json.loads(response.text)['access_token']
|
||||
|
||||
# Perform an API request to Office 365 management API
|
||||
def make_api_request(method, url, token):
|
||||
# Create a valid header using the token
|
||||
headers = {'Content-Type':'application/json', 'Authorization':'Bearer {0}'.format(token)}
|
||||
|
||||
# Make API request
|
||||
response = make_request(method, url, headers=headers)
|
||||
|
||||
# If this is a POST request just return
|
||||
if (method == "POST"):
|
||||
return None
|
||||
|
||||
json_data = json.loads(response.text)
|
||||
|
||||
# If NextPageUri is included in the header and it has content in it
|
||||
if 'NextPageUri' in response.headers.keys() and response.headers['NextPageUri']:
|
||||
logging.info("New data page detected in {}.".format(url))
|
||||
|
||||
# Request new page and append to existing data
|
||||
record = make_api_request(method, response.headers['NextPageUri'], token)
|
||||
json_data.extend(record)
|
||||
|
||||
return json_data
|
||||
|
||||
# Manage content type subscriptions
|
||||
def manage_content_type_subscriptions(contentTypes, clientId, token):
|
||||
# For every available content type
|
||||
for contentType in availableContentTypes:
|
||||
# If it was added as a parameter then start the subscription
|
||||
if contentType in contentTypes:
|
||||
make_api_request("POST", "{}/api/v1.0/{}/activity/feed/subscriptions/start?contentType={}".format(resource, clientId, contentType), token)
|
||||
logging.info("{} subscription was successfully started.".format(contentType))
|
||||
|
||||
################################################## Main workflow ##################################################
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Parse arguments
|
||||
parser = argparse.ArgumentParser(description='Wazuh - Office 365 activity information.')
|
||||
parser.add_argument('--contentTypes', metavar='contentTypes', type=str, nargs='+', required = True, help='Office 365 activity content type subscriptions.')
|
||||
parser.add_argument('--hours', metavar='hours', type=int, required = True, help='How many hours to fetch activity logs.')
|
||||
parser.add_argument('--tenantId', metavar='tenantId', type=str, required = True, help='Application tenant ID.')
|
||||
parser.add_argument('--clientId', metavar='clientId', type=str, required = True, help='Application client ID.')
|
||||
parser.add_argument('--clientSecret', metavar='clientSecret', type=str, required = True, help='Client secret.')
|
||||
parser.add_argument('--debug', action='store_true', required = False, help='Enable debug mode logging.')
|
||||
args = parser.parse_args()
|
||||
|
||||
# Start logging config
|
||||
if args.debug:
|
||||
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s: [%(levelname)s] %(message)s', datefmt="%Y-%m-%d %H:%M:%S",)
|
||||
else:
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s: [%(levelname)s] %(message)s', datefmt="%Y-%m-%d %H:%M:%S",)
|
||||
|
||||
# Disable warnings
|
||||
requests.packages.urllib3.disable_warnings()
|
||||
|
||||
try:
|
||||
# Obtain access token
|
||||
token = obtain_access_token(args.tenantId, args.clientId, args.clientSecret)
|
||||
|
||||
response =make_api_request("GET", "{}/api/v1.0/{}/activity/feed/subscriptions/list".format(resource, args.clientId), token)
|
||||
# Start/stop subscriptions depending on the content_types parameter
|
||||
manage_content_type_subscriptions(args.contentTypes, args.clientId, token)
|
||||
|
||||
# Build time range filter
|
||||
currentTime = datetime.datetime.now(datetime.timezone.utc)
|
||||
endTime = str(currentTime).replace(' ', 'T').rsplit('.', maxsplit=1)[0]
|
||||
startTime = str(currentTime - datetime.timedelta(hours=args.hours)).replace(' ', 'T').rsplit('.', maxsplit=1)[0]
|
||||
|
||||
# For every content_type in the content_types parameter
|
||||
for contentType in args.contentTypes:
|
||||
# If it is a valid content_type
|
||||
if contentType in availableContentTypes:
|
||||
# List the subscription content
|
||||
subscription_content = make_api_request("GET", "{}/api/v1.0/{}/activity/feed/subscriptions/content?contentType={}&startTime={}&endTime={}".format(resource, args.clientId, contentType, startTime, endTime), token)
|
||||
logging.info("{} subscription was successfully listed.".format(contentType))
|
||||
|
||||
# For every blob in the subscription
|
||||
for blob in subscription_content:
|
||||
# Request activity information
|
||||
data = make_api_request("GET", blob["contentUri"], token)
|
||||
logging.info("Blob in {} subscription was successfully fetched.".format(contentType))
|
||||
|
||||
# Loop every event and send it to the Wazuh manager
|
||||
for event in data:
|
||||
office_365_event = {}
|
||||
office_365_event['office_365'] = event
|
||||
send_event(json.dumps(office_365_event))
|
||||
|
||||
except Exception as e:
|
||||
logging.error("Error while retrieving Office 365 activity logs: {}.".format(e))
|
Loading…
Reference in New Issue
Block a user