Code development platform for open source projects from the European Union institutions :large_blue_circle: EU Login authentication by SMS has been phased out. To see alternatives please check here

Skip to content
Snippets Groups Projects
Verified Commit ccc6f016 authored by Mathieu LE CLEACH's avatar Mathieu LE CLEACH
Browse files

add: first commit

parent 46d96c8b
No related branches found
No related tags found
No related merge requests found
Showing
with 2210 additions and 1 deletion
.DS_Store
*.retry
venv/
\ No newline at end of file
---
stages:
- binary
- build
image: docker:stable-dind
services:
- docker:dind
before_script:
- apk add --no-cache
python3 python3-dev py3-pip gcc git curl build-base
autoconf automake py3-cryptography curl linux-headers
musl-dev libffi-dev openssl-dev openssh rsync
- curl https://sh.rustup.rs -sSf | sh -s -- -y
- source $HOME/.cargo/env
- docker info
- python3 --version
- python3 -m pip install ansible molecule-plugins[docker]
- ansible-galaxy collection install community.docker
- ansible --version
- molecule --version
test-binary-mode:
stage: binary
script:
- molecule test --scenario-name binary
test-build-mode:
stage: build
rules:
- if: '$CI_COMMIT_BEFORE_SHA == "0000000000000000000000000000000000000000"'
when: never
- if: '$CI_COMMIT_BRANCH != "main"'
when: never
- when: on_success
script:
- molecule test --scenario-name build
\ No newline at end of file
License 0 → 100644
This diff is collapsed.
Notice 0 → 100644
This diff is collapsed.
# ansible-auditd-laurel
An Ansible role to deploy auditd and laurel
Ansible role to deploy Auditd and Laurel plugin. By default the role will fetch the latest binary from [GitHub](https://github.com/threathunters-io/laurel/blob/master/INSTALL.md#or-use-one-of-the-provided-binaries) but has also the option to build it from source.
LAUREL is an event post-processing plugin for auditd(8) to improve its usability in modern security monitoring setups.
* https://github.com/threathunters-io/laurel
# Supported Operating Systems
- Debian 12
- Debian 11
- Debian 10
- RHEL / Rocky Linux 9
- RHEL / Rocky Linux 8
# Default Variables
The defaults variables are the following:
- `laurel_user` - This user user will run Laurel plugin;
- Default is `_laurel`
- `laurel_build_dir` - The directory where the build from sources takes place;
- Default is `/var/_install/laurel`
- `laurel_user_allowed_read` - Defines the user that will have the right to read the laurel's logs. The role will fail if the user does not exists.
- Default is `splunkfwd`
- `laurel_local_tmp` - Ansible fetches the latest release from GitHub on the Ansible Controller (locally)
- Default is `/tmp`
# Usage
You can call this role with the following play:
```
---
- hosts: laurel
become: yes
roles:
- role: ansible-auditd-laurel
```
You can override the following variable as well, with the following play:
```
---
- hosts: laurel
become: yes
roles:
- role: ansible-auditd-laurel
vars:
laurel_user: _user53
laurel_build_dir: /var/_install67/laurel
laurel_user_allowed_read: filebeat
laurel_local_tmp: /tmp
```
## Default: Retrieve last release from GitHub
By default, the role will fetch the latest Laurel release from GitHub. The Ansible Controller will fetch it once in the directory `laurel_local_tmp` and will copy the binaries in `laurel_build_dir`.
Please checkout the [network](#network) section to know more about the URLs reached.
Note: when using the default mode, there is no need to add any specific tag
## Build it from source
This role has the ability to build Laurel from source, to do so use the tags as the following:
```sh
ansible-playbook ... --tags build --skip-tags binary
```
# Network
- Default mode:
- `https://api.github.com/`
- `https://github.com/`
- Build mode:
- `https://github.com/`
- `https://sh.rustup.rs`
# Configuration Maintenance
This role allows you to push Auditd and/or Laurel configuration files and avoid to go through the whole installation process. It allows you to maintain the configuration files. The following steps describe how to proceed:
1. Modify the configuration file of Auditd (`templates/auditd.rules.j2`) or Laurel's configuration file (`templates/config.toml.j2`);
2. Launch your playbook with the tag `config` (`$ ansible-playbook laurel.yml -t config`).
# Auditd Configuration
We are providing an Auditd's configuration copy from Florian Roth's repo (https://github.com/Neo23x0/auditd).
You can replace this configuration with your own by editing the file [auditd.rules.j2](./templates/auditd.rules.j2).
# Laurel Configuration
The configuration provided for Laurel set the command line arguments concatenated into a single string by default.
You can edit the file [config.toml.j2](./templates/config.toml.j2) and replace the configuration with your own.
# Laurel Logs
Laurel's logs will be available in `/var/log/laurel/audit.log` in JSON format. Laurel will automatically rotate the logs as per the [settings](https://github.com/certeu/ansible-auditd-laurel/blob/main/templates/config.toml.j2#L14).
# Known Issues when building from source
Ansible will first try to install `cargo` (and `rustc` for the compilation) from the default distribution repositories. If the version of Rust is too old it won't reach the 2021 edition for the earliest update. If the build fails, Ansible will remove the `cargo` and `rustc` from the machine and will reach `sh.rustup.rs` and `static.rust-lang.org` to install the earliest version of Rust. This has been experienced using Debian 10 and 11.
# License
Licensed under the GPL.
\ No newline at end of file
---
laurel_user: _laurel
laurel_build_dir: /var/_install/laurel
laurel_user_allowed_read: splunkfwd
laurel_local_tmp: /tmp
\ No newline at end of file
- name: Converge
hosts: all
become: no
gather_facts: yes
tasks:
- name: "Include ansible-auditd-laurel"
include_role:
name: "ansible-auditd-laurel"
vars:
laurel_local_tmp: "/tmp"
test: true
\ No newline at end of file
---
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: "rocky8"
image: "rockylinux:8"
command: /sbin/init
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
cgroupns_mode: host
privileged: yes
pre_build_image: yes
- name: "debian12"
image: "debian:12"
dockerfile: ../common/Dockerfile-deb12
command: /sbin/init
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
cgroupns_mode: host
privileged: yes
pre_build_image: no
provisioner:
name: ansible
scenario:
test_sequence:
- destroy
- create
- prepare
- converge
- destroy
verifier:
name: ansible
---
- name: Prepare
hosts: all
tasks:
- name: Ensure the user splunkfwd is created
ansible.builtin.user:
name: splunkfwd
system: true
\ No newline at end of file
- name: Converge
hosts: all
become: no
gather_facts: yes
tasks:
- name: "Include ansible-auditd-laurel"
include_role:
name: "ansible-auditd-laurel"
vars:
laurel_local_tmp: "/tmp"
test: true
tags:
- build
\ No newline at end of file
---
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: "rocky8"
image: "rockylinux:8"
dockerfile: ../common/Dockerfile-rocky8
command: /sbin/init
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
cgroupns_mode: host
privileged: yes
pre_build_image: no
- name: "debian12"
image: "debian:12"
dockerfile: ../common/Dockerfile-deb12
command: /sbin/init
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
cgroupns_mode: host
privileged: yes
pre_build_image: no
provisioner:
name: ansible
options:
tags: build
skip-tags: binary
scenario:
test_sequence:
- destroy
- create
- prepare
- converge
- destroy
verifier:
name: ansible
---
- name: Prepare
hosts: all
tasks:
- name: Ensure the user splunkfwd is created
ansible.builtin.user:
name: splunkfwd
system: true
tags:
- always
\ No newline at end of file
FROM debian:12
RUN apt-get update && apt-get install -y init python3 procps rsync && apt-get clean all
\ No newline at end of file
FROM rockylinux:8
RUN dnf install git -y
\ No newline at end of file
---
- name: Configure Auditd and Laurel
tags:
- build
- install
- config
block:
- name: Check if /etc/audit directory exists
stat:
path: /etc/audit
register: auditd_path
- debug: var=auditd_path.stat.path
when: auditd_path.stat.path == "/etc/audit"
- name: Check if /etc/audisp directory exists
stat:
path: /etc/audisp
register: audit_path
when: auditd_path.stat.path != "/etc/audit"
- debug: var=audit_path.stat.path
- name: Display the value of auditd_path
debug:
var: auditd_path.stat.path
- name: Ensure Auditd rules are set
ansible.builtin.template:
src: auditd.rules.j2
dest: "{{ auditd_path.stat.path }}/rules.d/audit.rules"
owner: root
group: root
mode: '0640'
when: test is not defined
- name: Ensures Laurel config path exists
ansible.builtin.file:
path: /etc/laurel/
owner: "{{ laurel_user }}"
group: "{{ laurel_user }}"
state: directory
mode: '0640'
- name: Ensure Laurel config is set
ansible.builtin.template:
src: config.toml.j2
dest: /etc/laurel/config.toml
owner: "{{ laurel_user }}"
group: "{{ laurel_user }}"
mode: '0640'
- name: Ensures Auditd plugin path exists
ansible.builtin.file:
path: "{{ auditd_path.stat.path }}/plugins.d/"
owner: root
group: root
state: directory
mode: '0740'
- name: Register Laurel as auditd plugin
ansible.builtin.template:
src: laurel.conf.j2
dest: "{{ auditd_path.stat.path }}/plugins.d/laurel.conf"
owner: root
group: root
mode: '0740'
- name: Test (switching local events to no)
lineinfile:
path: /etc/audit/auditd.conf
regexp: '^local_events ='
line: 'local_events = no'
when: test is defined
- name: Enable Auditd service
ansible.builtin.systemd:
name: auditd
state: started
enabled: yes
- name: Configure SELinux for Laurel
tags:
- install
- binary
when: ansible_facts.selinux.status == 'enabled'
block:
- name: Ensure SE Linux policy headers are present
ansible.builtin.package:
name: selinux-policy-devel
state: present
- name: Git clone Laurel repo locally
connection: local
become: false
ansible.builtin.git:
repo: https://github.com/threathunters-io/laurel.git
dest: "{{ laurel_local_tmp }}/laurel"
version: "{{ json_reponse.json.tag_name }}"
when: test is not defined
- name: Git clone Laurel repo (TEST)
ansible.builtin.git:
repo: https://github.com/threathunters-io/laurel.git
dest: "{{ laurel_local_tmp }}/laurel"
version: "{{ json_reponse.json.tag_name }}"
when: test is defined
- name: Ensure the directory for SELinux is created
ansible.builtin.file:
path: "{{ laurel_build_dir }}/selinux"
state: directory
owner: root
group: root
mode: 0644
recurse: yes
- name: Find files in the laurel/contrib/selinux/
connection: local
become: false
ansible.builtin.find:
paths: "{{ laurel_local_tmp }}/laurel/contrib/selinux/"
recurse: yes
file_type: file
register: found_files
- name: Copy SELinux files
ansible.builtin.copy:
src: "{{ item.path }}"
dest: "{{ laurel_build_dir }}/selinux/{{ item.path | basename }}"
with_items: "{{ found_files.files }}"
when: test is not defined
- name: Compile SELinux policy
ansible.builtin.shell: make
args:
chdir: "{{ laurel_build_dir }}/selinux"
- name: Install the policy into the running kernel
ansible.builtin.shell: semodule -i laurel.pp
args:
chdir: "{{ laurel_build_dir }}/selinux"
- name: Restores the default SELinux security contexts
ansible.builtin.shell: restorecon -v -R -F /usr/local/sbin/laurel /etc/laurel /var/log/laurel
args:
chdir: "{{ laurel_build_dir }}/selinux"
- name: Configure SELinux for Laurel (when if build selected)
tags:
- never
- build
when: ansible_facts.selinux.status == 'enabled'
block:
- name: Ensure SE Linux policy headers are present
ansible.builtin.package:
name: selinux-policy-devel
state: present
- name: Compile SELinux policy
ansible.builtin.shell: make
args:
chdir: "{{ laurel_build_dir }}/contrib/selinux"
- name: Compile SELinux policy (when building)
ansible.builtin.shell: make
args:
chdir: "{{ laurel_build_dir }}/contrib/selinux"
- name: Install the policy into the running kernel
ansible.builtin.shell: semodule -i contrib/selinux/laurel.pp
args:
chdir: "{{ laurel_build_dir }}"
- name: Restores the default SELinux security contexts
ansible.builtin.shell: restorecon -v -R -F /usr/local/sbin/laurel /etc/laurel /var/log/laurel
args:
chdir: "{{ laurel_build_dir }}"
- name: Loading Auditd rules and test if Laurel is running
tags:
- build
- install
- config
block:
- name: Restart Auditd service
ansible.builtin.systemd:
name: auditd
state: restarted
when: ansible_os_family == 'Debian'
- name: Restart Auditd service
ansible.builtin.service:
name: auditd
state: restarted
use: service
when: ansible_os_family == 'RedHat'
- name: Ensure Auditd read the applied rules
ansible.builtin.shell: "auditctl -R {{ auditd_path.stat.path }}/rules.d/audit.rules"
when: test is not defined
- name: Ensure Auditd load the rules
ansible.builtin.shell: augenrules --load
when: test is not defined
- name: Verify if the rules are being properly loaded
ansible.builtin.shell: auditctl -l
register: audit_rules
failed_when: "'No rules' in audit_rules.stdout"
when: test is not defined
- name: Tell auditd to re-evaluate its configuration
ansible.builtin.shell: pkill -HUP auditd
- name: Verify Laurel is running
ansible.builtin.shell: ps aux | grep laurel
register: laurel_run
failed_when: "'/usr/local/sbin/laurel' not in laurel_run.stdout"
---
- name: Install Auditd and dependencies
tags:
- install
block:
- name: Ensure that laurel_user_allowed_read variable exists
fail:
msg: "laurel_user_allowed_read is a mandatory var to execute the playbook. Variables must be set globally (group_vars) or passed as extra variable -e"
when: laurel_user_allowed_read is not defined
- name: Verify that user actually exists
ansible.builtin.getent:
database: passwd
key: "{{ laurel_user_allowed_read }}"
- name: Ensure Auditd is installed
ansible.builtin.package:
name: "{{ laurel_deps_packages }}"
state: present
tags:
- always
- name: Ensure dependencies for Laurel are present to fetch Laurel (Debian)
ansible.builtin.apt:
name: "{{ laurel_deps_packages_binary }}"
state: present
update_cache: yes
when: ansible_os_family == 'Debian'
tags:
- binary
- name: Ensure dependencies for Laurel are present to fetch Laurel (RedHat)
ansible.builtin.package:
name: "{{ laurel_deps_packages_binary }}"
state: present
when: ansible_os_family == 'RedHat'
tags:
- binary
- name: Ensure dependencies for Laurel are present for build (Debian)
ansible.builtin.apt:
name: "{{ laurel_build_packages }}"
state: present
update_cache: yes
when: ansible_os_family == 'Debian'
tags:
- never
- build
- name: Ensure dependencies for Laurel are present for build (RedHat)
ansible.builtin.package:
name: "{{ laurel_build_packages }}"
state: present
when: ansible_os_family == 'RedHat'
tags:
- never
- build
- name: Ensure the user is created "{{ laurel_user }}"
ansible.builtin.user:
name: "{{ laurel_user }}"
system: true
home: /var/log/laurel
- name: Fetch Laurel binary from GitHub
tags:
- install
- binary
block:
- name: Retrieve the last version from Laurel
connection: local
become: false
ansible.builtin.uri:
url: https://api.github.com/repos/threathunters-io/laurel/releases/latest
register: json_reponse
- name: Download the latest build (based on musl version) locally
connection: local
become: false
ansible.builtin.get_url:
url: "https://github.com/threathunters-io/laurel/releases/download/{{ json_reponse.json.tag_name }}/laurel-{{ json_reponse.json.tag_name }}-x86_64-musl.tar.gz"
dest: "{{ laurel_local_tmp }}/laurel-{{ json_reponse.json.tag_name }}.tar.gz"
when: test is not defined
- name: Download the latest build (based on musl version) on target
become: false
ansible.builtin.get_url:
url: "https://github.com/threathunters-io/laurel/releases/download/{{ json_reponse.json.tag_name }}/laurel-{{ json_reponse.json.tag_name }}-x86_64-musl.tar.gz"
dest: "{{ laurel_local_tmp }}/laurel-{{ json_reponse.json.tag_name }}.tar.gz"
force: true
when: test is defined
- name: Ensure the directory for Laurel installation is created
ansible.builtin.file:
path: "{{ laurel_build_dir }}"
state: directory
owner: root
group: root
mode: 0644
recurse: yes
- name: Copy Laurel binary
ansible.builtin.copy:
src: "{{ laurel_local_tmp }}/laurel-{{ json_reponse.json.tag_name }}.tar.gz"
dest: "{{ laurel_build_dir }}/laurel-{{ json_reponse.json.tag_name }}.tar.gz"
owner: root
group: root
force: true
remote_src: true
when: test is defined
- name: Send Laurel binary
ansible.builtin.copy:
src: "{{ laurel_local_tmp }}/laurel-{{ json_reponse.json.tag_name }}.tar.gz"
dest: "{{ laurel_build_dir }}/laurel-{{ json_reponse.json.tag_name }}.tar.gz"
owner: root
group: root
force: true
when: test is not defined
- name: Decompress Laurel binary
ansible.builtin.shell: "tar xzf laurel-{{ json_reponse.json.tag_name }}.tar.gz laurel"
args:
chdir: "{{ laurel_build_dir }}"
- name: Copy and set attribute
ansible.builtin.shell: "install -m755 laurel /usr/local/sbin/laurel"
args:
chdir: "{{ laurel_build_dir }}"
- name: Build Laurel
tags:
- never
- build
block:
- name: Test - Git clone Laurel repo
ansible.builtin.git:
repo: https://github.com/threathunters-io/laurel.git
dest: "{{ laurel_local_tmp }}/laurel"
when: test is defined
- name: Git clone Laurel repo locally
connection: local
become: false
ansible.builtin.git:
repo: https://github.com/threathunters-io/laurel.git
dest: "{{ laurel_local_tmp }}/laurel"
when: test is not defined
- name: Ensure the directory for Laurel installation is created
ansible.builtin.file:
path: "{{ laurel_build_dir }}"
state: directory
owner: root
group: root
mode: 0644
recurse: yes
- name: Test - Copy laurel repo
ansible.builtin.copy:
src: "{{ laurel_local_tmp }}/laurel/"
dest: "{{ laurel_build_dir }}"
owner: root
group: root
mode: '0750'
remote_src: yes
when: test is defined
- name: Copy laurel repo
ansible.builtin.copy:
src: "{{ laurel_local_tmp }}/laurel/"
dest: "{{ laurel_build_dir }}"
owner: root
group: root
mode: '0750'
when: test is not defined
- name: Build Laurel using Cargo
ansible.builtin.shell: cargo build --release
args:
chdir: "{{ laurel_build_dir }}"
- name: Copy laurel binary
ansible.builtin.copy:
src: "{{ laurel_build_dir }}/target/release/laurel"
dest: /usr/local/sbin/laurel
owner: root
group: root
mode: '0750'
remote_src: true
rescue:
- name: Failed to build Laurel using cargo from the packet manager going for install from https://sh.rustup.rs (Rust)
ansible.builtin.pause:
seconds: 2
- name: Remove Rustc and Cargo
ansible.builtin.package:
name:
- rustc
- cargo
state: absent
- name: Download script from Rust
ansible.builtin.get_url:
url: https://sh.rustup.rs
dest: /tmp/rustinstall.sh
- name: Install Rust Compiler
ansible.builtin.shell: sh rustinstall.sh -q -y
args:
chdir: /tmp/
- name: Build Laurel using Cargo
ansible.builtin.shell: /root/.cargo/bin/cargo build --release
args:
chdir: "{{ laurel_build_dir }}"
- name: Add the user "{{ laurel_user }}"
ansible.builtin.user:
name: "{{ laurel_user }}"
system: true
home: /var/log/laurel
- name: Copy laurel binary
ansible.builtin.copy:
src: "{{ laurel_build_dir }}/target/release/laurel"
dest: /usr/local/sbin/laurel
owner: root
group: root
mode: '0750'
remote_src: true
---
# OS variables
- name: Include os family-specific variables
ansible.builtin.include_vars: "{{ ansible_os_family }}.yml"
tags:
- always
# Install deps and build Laurel
- name: Install Laurel (build by default but has the ability to download the binary from the GitHub)
ansible.builtin.import_tasks: laurel_install.yml
# Configure Auditd and Laurel
- name: Configure Auditd and Laurel
ansible.builtin.import_tasks: laurel_config.yml
\ No newline at end of file
This diff is collapsed.
# Write log files relative to this directory
directory = "/var/log/laurel"
# Drop privileges from root to this user
user = "{{ laurel_user }}"
# The periodical time window in seconds for status information to be printed to Syslog.
# Status report includes the running version, config and parsing stats.
# Default is 0 --> no status reports.
statusreport-period = 0
[auditlog]
# Base file name for the JSONL-based log file. Set to "-" to log to stdout. In this case
# other log file related settings will be ignored.
file = "audit.log"
# Rotate when log file reaches this size (in bytes)
size = 5000000
# When rotating, keep this number of generations around
generations = 10
# Grant read permissions on the log files to these users, using
# POSIX ACLs
read-users = [ "{{ laurel_user_allowed_read }}" ]
# Add a prefix to every output line. The CEE cookie can be used to
# instruct consumers to parse the JSON document, cf.
# https://www.rsyslog.com/doc/master/configuration/modules/mmjsonparse.html
# line-prefix = "@cee: "
# [debug]
# dump-state-period = 120
# [debug.log]
# file = "debug.log"
[transform]
# "array" (the default) causes EXECVE a0, a1, a2 … arguments to be
# output as a list of strings, "ARGV". This is the default, it allows
# analysts to reliably reproduce what was executed.
#
# "string" causes arguments to be concatenated into a single string,
# separated by space characters, "ARGV_STR". This form allows for
# easier grepping, but it is impossible to tell if space characters in
# the resulting string are a separator or were part of an individual
# argument in the original command line.
#execve-argv = [ "string" ]
execve-argv = [ "array", "string" ]
# Trim excessively long EXECVE.ARGV and EXECVE.ARGV_STR entries.
# Excess is cut from the middle of the argument list and a marker
# indicating how many arguments / bytes have been cut is inserted.
# execve-argv-limit-bytes = 10000
[translate]
# Perform translations of numeric values that can also be done by
# auditd if configured with log_format=ENRICHED.
# arch, syscall, sockaddr structures
universal = false
# UID, GID values
user-db = false
[enrich]
# List of environment variables to log for every EXECVE event
execve-env = [ "LD_PRELOAD", "LD_LIBRARY_PATH" ]
# Add container context to SYSCALL-based events
container = true
[label-process]
# Audit records that contain certain keys can be reused as a label
# attached to the process.
#
# This is useful in combination with audit rules such as:
# -w <path> -p x -k <key>
# e.g.: -w /usr/bin/dpkg -p x -k software_mgmt
label-keys = [ "software_mgmt" ]
# Labels can be attached to processes that run certain programs. The
# file program file path (SYSCALL.exe or /proc/pid/exe) is matched
# against regular expressions. This is useful for programs that cannot
# be identified through auditd file watches (-w <path> -p x -k <key>).
label-exe.'^/opt/.*/bin/java$' = 'java'
label-exe.'^/usr/lib/jvm/.*/bin/java$' = 'java'
label-exe.'^/snap/amazon-ssm-agent/\d+/' = 'amazon-ssm-agent'
# Process Labels can be propagated to spawned child processes. This is
# useful for marking an entire subtree of children that have been
# spawned within certain contexts (e.g. system management tools,
# container runtimes, ssh servers, cron, etc.).
propagate-labels = [ "software_mgmt", "amazon-ssm-agent" ]
[filter]
# When audit records with attached keys are being generated,
# LAUREL will discard these.
# filter-keys = ["filter-this"]
# In addition to key based filtering it is also possible to configure label based
# filtering. This alows the possibility to filter based on parent processes.
# filter-labels = ["software_mgmt"]
\ No newline at end of file
active = yes
direction = out
type = always
path = /usr/local/sbin/laurel
args = --config /etc/laurel/config.toml
format = string
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment