Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement workflow for automatic ECS templates generation #586

Merged
merged 46 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
d5046b2
Add initial ecs Dockerfile
QU3B1M Dec 10, 2024
318117a
Add basic entrypoint script
QU3B1M Dec 10, 2024
b1fd175
Add dependencies installation to Dockerfile
QU3B1M Dec 10, 2024
b47243d
Remove unused variables
QU3B1M Dec 10, 2024
25d16d3
Remove upload related code on generate.sh tool
QU3B1M Dec 10, 2024
ba80cb5
Fix compatibility issues with latest python version
QU3B1M Dec 10, 2024
f49adbd
Remove unnecesary script
QU3B1M Dec 10, 2024
38972b1
Rename ECS source directory
QU3B1M Dec 10, 2024
ef1dd31
Implement docker compose to ecs generator tool
QU3B1M Dec 11, 2024
8827723
Working docker compose file for ECS generator
QU3B1M Dec 11, 2024
76fade9
Add doscstrings to Dockerfile
QU3B1M Dec 12, 2024
368315d
Add script to execute the ECS generator tool
QU3B1M Dec 12, 2024
c25a034
Update ecs generator launcher script
QU3B1M Dec 13, 2024
118cdbe
Mitigate warnings on container down and stop actions
QU3B1M Dec 13, 2024
c4d323c
Rename ecs util to mapping-generator
QU3B1M Dec 13, 2024
c7f4c1b
Implement generate-ecs-mapping GHA workflow to auto-generate PRs with…
QU3B1M Dec 13, 2024
60cf765
Update GHA plugins version
QU3B1M Dec 13, 2024
c1ca5e9
Validate ECS generation workflow
QU3B1M Dec 13, 2024
46e9135
Fix generator.sh path on Dockerfile and update GHA to work with multi…
QU3B1M Dec 13, 2024
396bc41
Define specific version for the ubuntu runner
QU3B1M Dec 26, 2024
a4a2050
Merge branch 'master' into ci/540-ecs-index-automatic-generation
QU3B1M Dec 26, 2024
85f0323
Update ecs generator with latest changes
QU3B1M Dec 26, 2024
a091a15
Reove duplicated generate.sh tool
QU3B1M Dec 26, 2024
da1a00f
Update tool location paths
QU3B1M Dec 26, 2024
663aab8
Update GHA to use the new tool
QU3B1M Jan 6, 2025
300b673
Upload resulting templates as artifacts
QU3B1M Jan 6, 2025
14d2184
Fix typo in ecs/README.md
AlexRuiz7 Jan 7, 2025
67a71bd
Remove hardcoded ECS version
QU3B1M Jan 7, 2025
73a0b1d
Add docstrings to functions
QU3B1M Jan 7, 2025
6fbfe0d
Move repository check conditional to be job-level
QU3B1M Jan 8, 2025
494372b
Test workflow
AlexRuiz7 Jan 8, 2025
6d2465c
Fix short description
AlexRuiz7 Jan 8, 2025
2efdd4b
Fix attempt of relative path
AlexRuiz7 Jan 8, 2025
1d99213
Update vulnerability.yml to validate ecs workflow
QU3B1M Jan 8, 2025
1a4f26f
Test changes on inventory-hardware subset.yml
QU3B1M Jan 8, 2025
4bce70d
Update for Wazuh Indexer bot
AlexRuiz7 Jan 22, 2025
6eb8f62
Undo changes to to trigger the build
AlexRuiz7 Jan 22, 2025
c6d9996
Update configure_git() condition
AlexRuiz7 Jan 23, 2025
720bdeb
Trigger automation
AlexRuiz7 Jan 23, 2025
00607bb
Create ssh folder
AlexRuiz7 Jan 23, 2025
46b8775
Fix template artifact upload
QU3B1M Jan 23, 2025
9bf9136
Fix ECS template backup directory
QU3B1M Jan 23, 2025
3dd6434
Resolve the full path of the output directory
QU3B1M Jan 23, 2025
2a2c849
Add ECS generator badge to README
QU3B1M Jan 23, 2025
49e4993
Fix body formatting
QU3B1M Jan 23, 2025
9606f11
Revert changes to ECS defintions
QU3B1M Jan 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions .github/workflows/generate-ecs-mappings.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
name: ECS Generator

on:
push:
paths:
- 'ecs/**'
QU3B1M marked this conversation as resolved.
Show resolved Hide resolved

jobs:
run-ecs-generator:
runs-on: ubuntu-latest
QU3B1M marked this conversation as resolved.
Show resolved Hide resolved

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 2

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Set up Docker Compose
run: sudo apt-get install docker-compose

- name: Extract ECS Modules and Run ECS Generator
id: run-ecs-generator
run: |
# Fetch base branch
git fetch origin +refs/heads/master:refs/remotes/origin/master

# Extract the ECS module names from the modified files
modified_files=$(git diff --name-only origin/master)
updated_modules=()
for file in $modified_files; do
if [[ $file == ecs/* ]]; then
ecs_module=$(echo $file | cut -d'/' -f2)
if [[ ! " ${updated_modules[*]} " =~ " ${ecs_module} " ]]; then
updated_modules+=("$ecs_module")
fi
fi
done

# Filter out modules that do not have corresponding JSON files
declare -A module_to_file=(
[agent]="index-template-agent.json"
[alerts]="index-template-alerts.json"
[commands]="index-template-commands.json"
[hardware]="index-template-hardware.json"
[hotfixes]="index-template-hotfixes.json"
[fim]="index-template-fim.json"
[networks]="index-template-networks.json"
[packages]="index-template-packages.json"
[ports]="index-template-ports.json"
[processes]="index-template-processes.json"
[scheduled-commands]="index-template-scheduled-commands.json"
[system]="index-template-system.json"
[vulnerabilities]="index-template-vulnerabilities.json"
)

relevant_modules=()
for ecs_module in "${updated_modules[@]}"; do
if [[ -n "${module_to_file[$ecs_module]}" ]]; then
relevant_modules+=("$ecs_module")
fi
done

if [[ ${#relevant_modules[@]} -gt 0 ]]; then
export REPO_PATH=$(pwd)
for ecs_module in "${relevant_modules[@]}"; do
# Run the ECS generator script for each relevant module
bash docker/ecs/mapping-generator.sh run "$ecs_module"
echo "Processed ECS module: $ecs_module"
done
echo "relevant_modules=${relevant_modules[*]}" >> $GITHUB_ENV
else
echo "No relevant modifications detected in ecs/ directory."
exit 0
fi

- name: Tear down ECS Generator
if: always()
run: bash docker/ecs/mapping-generator.sh down

- name: Upload artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: ecs-template
path: ecs/**/mappings/v8.11.0/generated/elasticsearch/legacy/template.json

- name: Checkout target repository
uses: actions/checkout@v4
with:
repository: wazuh/wazuh-indexer-plugins
token: ${{ secrets.GITHUB_TOKEN }}
path: wazuh-indexer-plugins

- name: Copy generated files to target repository
run: |
# Map ECS modules to target JSON filenames
declare -A module_to_file=(
[agent]="index-template-agent.json"
[alerts]="index-template-alerts.json"
[commands]="index-template-commands.json"
[hardware]="index-template-hardware.json"
[hotfixes]="index-template-hotfixes.json"
[fim]="index-template-fim.json"
[networks]="index-template-networks.json"
[packages]="index-template-packages.json"
[ports]="index-template-ports.json"
[processes]="index-template-processes.json"
[scheduled-commands]="index-template-scheduled-commands.json"
[system]="index-template-system.json"
[vulnerabilities]="index-template-vulnerabilities.json"
)

for ecs_module in ${relevant_modules[@]}; do
target_file=${module_to_file[$ecs_module]}
if [[ -z "$target_file" ]]; then
echo "No corresponding file for module $ecs_module"
continue
fi

mkdir -p wazuh-indexer-plugins/plugins/setup/src/main/resources/
cp ecs/$ecs_module/mappings/v8.11.0/generated/elasticsearch/legacy/template.json wazuh-indexer-plugins/plugins/setup/src/main/resources/$target_file
done

- name: Commit and push changes
run: |
cd wazuh-indexer-plugins
git config --global user.email "[email protected]"
git config --global user.name "GitHub Actions"

branch_name="update-ecs-templates"

# Check if branch exists
if git ls-remote --heads origin $branch_name | grep $branch_name; then
git checkout $branch_name
else
git checkout -b $branch_name
fi

git add .
git commit -m "Update ECS templates for modified modules: $relevant_modules"
git push origin $branch_name

- name: Create Pull Request
uses: peter-evans/create-pull-request@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "Update ECS templates for modified modules: $relevant_modules"
branch: update-ecs-templates
title: "Update ECS templates for modified modules: $relevant_modules"
body: "This PR updates the ECS templates for the following modules: $relevant_modules."
base: master
30 changes: 30 additions & 0 deletions docker/ecs/images/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
FROM python:3.10

# Update the package list and upgrade all packages
RUN apt-get update && \
apt-get upgrade -y && \
# Install dependencies
apt-get install -y git jq && \
# Cleanup
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
# Clone elastic ECS repository and install required Python libraries
git clone https://github.com/elastic/ecs.git && \
pip install -r ecs/scripts/requirements.txt && \
# Create the directory for the ecs definitions (this will be used as a volume)
mkdir -p /source/ecs

# Ensure the generate.sh script is in the correct location
ADD docker/ecs/images/generator.sh /ecs/generator.sh

# Define the directory as a volume to allow for external mounting
VOLUME /source/ecs

# Ensure the generate.sh script is executable
RUN chmod +x /ecs/generator.sh

# Set the working directory to the ECS repository
WORKDIR /ecs

# Define the entry point for the container to execute the generate.sh script
ENTRYPOINT ["/bin/bash", "/ecs/generator.sh"]
96 changes: 96 additions & 0 deletions docker/ecs/images/generator.sh
QU3B1M marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/bin/bash

set -euo pipefail

# SPDX-License-Identifier: Apache-2.0
# The OpenSearch Contributors require contributions made to
# this file be licensed under the Apache-2.0 license or a
# compatible open source license.

# Default values
ECS_VERSION="${ECS_VERSION:-v8.11.0}"
ECS_SOURCE=/source

# Function to display usage information
show_usage() {
echo "Usage: $0"
echo "Environment Variables:"
echo " * ECS_MODULE: Module to generate mappings for"
echo " * ECS_VERSION: (Optional) ECS version to generate mappings for (default: v8.11.0)"
echo "Example: docker run -e ECS_MODULE=alerts -e ECS_VERSION=v8.11.0 ecs-generator"
}

# Ensure ECS_MODULE is provided
if [ -z "${ECS_MODULE:-}" ]; then
show_usage
exit 1
fi

# Function to remove multi-fields from the generated index template
remove_multi_fields() {
local in_file="$1"
local out_file="$2"

jq 'del(
.mappings.properties.host.properties.os.properties.full.fields,
.mappings.properties.host.properties.os.properties.name.fields,
.mappings.properties.vulnerability.properties.description.fields
)' "$in_file" > "$out_file"
QU3B1M marked this conversation as resolved.
Show resolved Hide resolved
}

# Function to generate mappings
generate_mappings() {
local ecs_module="$1"
local indexer_path="$2"
local ecs_version="$3"

local in_files_dir="$indexer_path/ecs/$ecs_module/fields"
local out_dir="$indexer_path/ecs/$ecs_module/mappings/$ecs_version"

# Ensure the output directory exists
mkdir -p "$out_dir"

# Generate mappings
python scripts/generator.py --strict --ref "$ecs_version" \
--include "$in_files_dir/custom/" \
--subset "$in_files_dir/subset.yml" \
--template-settings "$in_files_dir/template-settings.json" \
--template-settings-legacy "$in_files_dir/template-settings-legacy.json" \
--mapping-settings "$in_files_dir/mapping-settings.json" \
--out "$out_dir"

# Replace unsupported types
echo "Replacing unsupported types in generated mappings"
find "$out_dir" -type f -exec sed -i 's/constant_keyword/keyword/g' {} \;
find "$out_dir" -type f -exec sed -i 's/flattened/flat_object/g' {} \;
find "$out_dir" -type f -exec sed -i 's/scaled_float/float/g' {} \;
find "$out_dir" -type f -exec sed -i '/scaling_factor/d' {} \;

local in_file="$out_dir/generated/elasticsearch/legacy/template.json"
local out_file="$out_dir/generated/elasticsearch/legacy/template-tmp.json"

# Delete the "tags" field from the index template
echo "Deleting the \"tags\" field from the index template"
jq 'del(.mappings.properties.tags)' "$in_file" > "$out_file"
mv "$out_file" "$in_file"

# Remove multi-fields from the generated index template
echo "Removing multi-fields from the index template"
remove_multi_fields "$in_file" "$out_file"
mv "$out_file" "$in_file"

# Transform legacy index template for OpenSearch compatibility
jq '{
"index_patterns": .index_patterns,
"priority": .order,
"template": {
"settings": .settings,
"mappings": .mappings
}
}' "$in_file" > "$out_dir/generated/elasticsearch/legacy/opensearch-template.json"

echo "Mappings saved to $out_dir"
}

# Generate mappings
generate_mappings "$ECS_MODULE" "$ECS_SOURCE" "$ECS_VERSION"
79 changes: 79 additions & 0 deletions docker/ecs/mapping-generator.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!/bin/bash

# Run the ECS generator tool container.
# Requirements:
# - Docker
# - Docker Compose

set -e

# The container is built only if needed, the tool can be executed several times
# for different modules in the same build since the script runs as entrypoint



# ====
# Checks that the script is run from the intended location
# ====
function navigate_to_project_root() {
local repo_root_marker
local script_path
repo_root_marker=".github"
script_path=$(dirname "$(realpath "$0")")

while [[ "$script_path" != "/" ]] && [[ ! -d "$script_path/$repo_root_marker" ]]; do
script_path=$(dirname "$script_path")
done

if [[ "$script_path" == "/" ]]; then
echo "Error: Unable to find the repository root."
exit 1
fi

cd "$script_path"
}

# ====
# Displays usage information
# ====
function usage() {
echo "Usage: $0 {run|down|stop} <ECS_MODULE> [REPO_PATH]"
exit 1
}

function main() {
local compose_filename="docker/ecs/mapping-generator.yml"
local compose_command
local module
local repo_path

navigate_to_project_root

compose_command="docker compose -f $compose_filename"

case $1 in
run)
if [[ "$#" -lt 2 || "$#" -gt 3 ]]; then
usage
fi
module="$2"
repo_path="${3:-$(pwd)}"

# Start the container with the required env variables
ECS_MODULE="$module" REPO_PATH="$repo_path" $compose_command up
# The containers are stopped after each execution
$compose_command stop
;;
down)
$compose_command down
;;
stop)
$compose_command stop
;;
*)
usage
;;
esac
}

main "$@"
11 changes: 11 additions & 0 deletions docker/ecs/mapping-generator.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
services:
ecs-mapping-generator:
image: wazuh-ecs-generator
container_name: wazuh-ecs-generator
build:
context: ./../..
dockerfile: ${REPO_PATH:-.}/docker/ecs/images/Dockerfile
volumes:
- ${REPO_PATH:-.}/ecs:/source/ecs
environment:
- ECS_MODULE=${ECS_MODULE:-default_module}
2 changes: 1 addition & 1 deletion ecs/alerts/fields/mapping-settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"dynamic": "strict",
"date_detection": false
}
}
Loading