diff --git a/README.md b/README.md index 900c259..b1a4250 100644 --- a/README.md +++ b/README.md @@ -1,74 +1,89 @@ -# Role Name +# AIDE [![ansible-lint.yml](https://github.com/linux-system-roles/aide/actions/workflows/ansible-lint.yml/badge.svg)](https://github.com/linux-system-roles/aide/actions/workflows/ansible-lint.yml) [![ansible-test.yml](https://github.com/linux-system-roles/aide/actions/workflows/ansible-test.yml/badge.svg)](https://github.com/linux-system-roles/aide/actions/workflows/ansible-test.yml) [![markdownlint.yml](https://github.com/linux-system-roles/aide/actions/workflows/markdownlint.yml/badge.svg)](https://github.com/linux-system-roles/aide/actions/workflows/markdownlint.yml) [![shellcheck.yml](https://github.com/linux-system-roles/aide/actions/workflows/shellcheck.yml/badge.svg)](https://github.com/linux-system-roles/aide/actions/workflows/shellcheck.yml) [![tft.yml](https://github.com/linux-system-roles/aide/actions/workflows/tft.yml/badge.svg)](https://github.com/linux-system-roles/aide/actions/workflows/tft.yml) [![tft_citest_bad.yml](https://github.com/linux-system-roles/aide/actions/workflows/tft_citest_bad.yml/badge.svg)](https://github.com/linux-system-roles/aide/actions/workflows/tft_citest_bad.yml) [![woke.yml](https://github.com/linux-system-roles/aide/actions/workflows/woke.yml/badge.svg)](https://github.com/linux-system-roles/aide/actions/workflows/woke.yml) -Ansible role for managing Advanced Intrusion Detection Environment (AIDE). +This is an ansible role that installs and configures the [Advanced Intrusion Detection Environment (AIDE)](https://aide.github.io). For Day 2 tasks it can run integrity checks and update the AIDE database. + +## What does this role do for you? + +* It ensures that the `aide` package is installed on the remote nodes +* As an optional task it can generate the `/etc/aide.conf` file and template it out to the remote nodes +* It initializes the AIDE database +* The AIDE databases from the remote nodes are stored in a central directory on the controller node +* It runs AIDE integrity checks on the remote nodes +* It updates the AIDE databases and stores them on the controller node + +## What does this role not do for you? + +* It does not explain how to create a good AIDE configuration that suits your requirements; that task remains for you to accomplish ## Requirements -Any prerequisites that may not be covered by Ansible itself or the role should -be mentioned here. This includes platform dependencies not managed by the -role, hardware requirements, external collections, etc. There should be a -distinction between *control node* requirements (like collections) and -*managed node* requirements (like special hardware, platform provisioning). +This role has no special requirements as it uses `ansible.builtin` modules +only. + +## Role Variables + +### aide_db_template -### Collection requirements +This variable takes a string to specify a path where the custom template for aide.conf is located. -For instance, if the role depends on some collections and has a -`meta/collection-requirements.yml` file for installing those dependencies, and -in order to manage `rpm-ostree` systems, it should be mentioned here that the - user should run +To be sure that everething is correct, template needs to start with following snippet: -```bash -ansible-galaxy collection install -vv -r meta/collection-requirements.yml +``` jinja +{{ ansible_managed | comment }} +{{ "system_role:aide" | comment(prefix="", postfix="") }} ``` -on the *control node* before using the role. +Default: `null` -## Role Variables +Type: `string` -A description of all input variables (i.e. variables that are defined in -`defaults/main.yml`) for the role should go here as these form an API of the -role. Each variable should have its own section e.g. +### aide_db_fetch_dir -### aide_foo +This variable takes a string to specify the directory on the Ansible Control +Node (ACN) where the role will store the AIDE database fetched from the remote +nodes. The default value is `files` which is expected to be a directory in the +same directory as the playbook. -This variable is required. It is a string that lists the foo of the role. -There is no default value. +In case you like to store the fetched AIDE database files somewhere else you +need to specify a different path here. -### aide_bar +Default: `files` -This variable is optional. It is a boolean that tells the role to disable bar. -The default value is `true`. +Type: `string -Variables that are not intended as input, like variables defined in -`vars/main.yml`, variables that are read from other roles and/or the global -scope (ie. hostvars, group vars, etc.) can be also mentioned here but keep in -mind that as these are probably not part of the role API they may change during -the lifetime. +### aide_init -Example of setting the variables: +Initializes the AIDE database. -```yaml -aide_foo: "oof" -aide_bar: false -``` +Default: `false` -## Variables Exported by the Role +Type: `bool` -This section is optional. Some roles may export variables for playbooks to -use later. These are analogous to "return values" in Ansible modules. For -example, if a role performs some action that will require a system reboot, but -the user wants to defer the reboot, the role might set a variable like -`aide_reboot_needed: true` that the playbook can use to reboot at a more -convenient time. +### aide_fetch_db -Example: +Fetches database from the remote nodes to store it on the controller node -### aide_reboot_needed +Default: `false` -Default `false` - if `true`, this means a reboot is needed to apply the changes -made by the role +Type: `bool` + +### aide_check + +Runs an integrity check on the remote nodes + +Default: `false` + +Type: `bool` + +### aide_update + +Updates the AIDE database and stores it on the controller node + +Default: `false` + +Type: `bool` ## Example Playbook @@ -76,27 +91,31 @@ Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: ```yaml -- name: Manage the aide subsystem - hosts: all - vars: - aide_foo: "foo foo!" - aide_bar: false - roles: - - linux-system-roles.aide +# SPDX-License-Identifier: MIT +--- +- name: Example aide role invocation + hosts: targets + tasks: + - name: Include role aide + vars: + aide_db_fetch_dir: files + aide_install: true + aide_generate_config: true + aide_init: true + aide_check: false + aide_update: false + ansible.builtin.include_role: + name: linux-system-roles.aide ``` -More examples can be provided in the [`examples/`](examples) directory. These -can be useful, especially for documentation. - -## rpm-ostree - -See README-ostree.md +More examples can be found in the [`examples/`](examples) directory. ## License -Whenever possible, please prefer MIT. +MIT. ## Author Information -An optional section for the role authors to include contact information, or a -website (HTML is not allowed). +* Radovan Sroka +* Joerg Kastning +* Based on [Tronde/aide](https://github.com/Tronde/aide) ansible role diff --git a/ansible_pytest_extra_requirements.txt b/ansible_pytest_extra_requirements.txt new file mode 100644 index 0000000..6bafb6f --- /dev/null +++ b/ansible_pytest_extra_requirements.txt @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MIT + +# ansible and dependencies for all supported platforms +ansible ; python_version > "2.6" +idna<2.8 ; python_version < "2.7" +PyYAML<5.1 ; python_version < "2.7" diff --git a/contributing.md b/contributing.md index 4bc2ae1..4695c44 100644 --- a/contributing.md +++ b/contributing.md @@ -1,4 +1,4 @@ -# Contributing to the aide Linux System Role +# Contributing to the Aide Linux System Role ## Where to start diff --git a/defaults/main.yml b/defaults/main.yml index a5858b6..f04914f 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -3,6 +3,20 @@ # Here is the right place to put the role's input variables. # This file also serves as a documentation for such a variables. +# Path to template file +aide_db_template: null + # Examples of role input variables: -aide_foo: foo -aide_bar: true +aide_db_fetch_dir: files + +# Enable initialization of the database phase +aide_init: false + +# Fetch db +aide_fetch_db: false + +# Enable check database phase +aide_check: false + +# Enable database update phase +aide_update: false diff --git a/examples/aide-custom.conf.j2 b/examples/aide-custom.conf.j2 new file mode 100644 index 0000000..e0ce4cf --- /dev/null +++ b/examples/aide-custom.conf.j2 @@ -0,0 +1,319 @@ +{{ ansible_managed | comment }} +{{ "system_role:aide" | comment(prefix="", postfix="") }} +# Example configuration file for AIDE. + +@@define DBDIR /var/lib/aide +@@define LOGDIR /var/log/aide + +{% if ansible_facts['os_family'] == 'RedHat' and + ansible_facts['distribution_major_version'] in ['8','9'] %} +# The location of the database to be read. +database=file:@@{DBDIR}/aide.db.gz +{% else %} +# The location of the database to be read. +database_in=file:@@{DBDIR}/aide.db.gz +{% endif %} + +# The location of the database to be written. +#database_out=sql:host:port:database:login_name:passwd:table +#database_out=file:aide.db.new +database_out=file:@@{DBDIR}/aide.db.new.gz + +# Whether to gzip the output to database +gzip_dbout=yes + +{% if ansible_facts['os_family'] == 'RedHat' and + ansible_facts['distribution_major_version'] in ['8','9'] %} +# Default. +verbose=5 +{% else %} +# Default. +log_level=warning +report_level=changed_attributes +{% endif %} + +report_url=file:@@{LOGDIR}/aide.log +report_url=stdout +#report_url=stderr +#NOT IMPLEMENTED report_url=mailto:root@foo.com +#NOT IMPLEMENTED report_url=syslog:LOG_AUTH + +# These are the default rules. +# +#p: permissions +#i: inode: +#n: number of links +#u: user +#g: group +#s: size +#b: block count +#m: mtime +#a: atime +#c: ctime +#S: check for growing size +#acl: Access Control Lists +#selinux SELinux security context +#xattrs: Extended file attributes +#md5: md5 checksum +#sha1: sha1 checksum +#sha256: sha256 checksum +#sha512: sha512 checksum +#rmd160: rmd160 checksum +#tiger: tiger checksum + +#haval: haval checksum (MHASH only) +#gost: gost checksum (MHASH only) +#crc32: crc32 checksum (MHASH only) +#whirlpool: whirlpool checksum (MHASH only) + +#R: p+i+n+u+g+s+m+c+acl+selinux+xattrs+md5 +#L: p+i+n+u+g+acl+selinux+xattrs +#E: Empty group +#>: Growing logfile p+u+g+i+n+S+acl+selinux+xattrs + +# You can create custom rules like this. +# With MHASH... +# ALLXTRAHASHES = sha1+rmd160+sha256+sha512+whirlpool+tiger+haval+gost+crc32 +ALLXTRAHASHES = sha1+rmd160+sha256+sha512+tiger +# Everything but access time (Ie. all changes) +EVERYTHING = R+ALLXTRAHASHES + +# Sane +# NORMAL = R+sha512 +NORMAL = p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha512 + +# For directories, don't bother doing hashes +DIR = p+i+n+u+g+acl+selinux+xattrs + +# Access control only +PERMS = p+u+g+acl+selinux+xattrs + +# Logfile are special, in that they often change +LOG = p+u+g+n+S+acl+selinux+xattrs + +# Content + file type. +CONTENT = sha512+ftype + +# Extended content + file type + access. +CONTENT_EX = sha512+ftype+p+u+g+n+acl+selinux+xattrs + +# Some files get updated automatically, so the inode/ctime/mtime change +# but we want to know when the data inside them changes +DATAONLY = p+n+u+g+s+acl+selinux+xattrs+sha512 + +# Next decide what directories/files you want in the database. + +/boot CONTENT_EX +/opt CONTENT + +# Admins dot files constantly change, just check perms +/root/\..* PERMS +!/root/.xauth* +# Otherwise get all of /root. +/root CONTENT_EX + +# These are too volatile +!/usr/src +!/usr/tmp +!/root/.ansible* + +# Otherwise get all of /usr. +/usr CONTENT_EX + +# trusted databases +/etc/hosts$ CONTENT_EX +/etc/host.conf$ CONTENT_EX +/etc/hostname$ CONTENT_EX +/etc/issue$ CONTENT_EX +/etc/issue.net$ CONTENT_EX +/etc/protocols$ CONTENT_EX +/etc/services$ CONTENT_EX +/etc/localtime$ CONTENT_EX +/etc/alternatives CONTENT_EX +/etc/sysconfig CONTENT_EX +/etc/mime.types$ CONTENT_EX +/etc/terminfo CONTENT_EX +/etc/exports$ CONTENT_EX +/etc/fstab$ CONTENT_EX +/etc/passwd$ CONTENT_EX +/etc/group$ CONTENT_EX +/etc/gshadow$ CONTENT_EX +/etc/shadow$ CONTENT_EX +/etc/subgid$ CONTENT_EX +/etc/subuid$ CONTENT_EX +/etc/security/opasswd$ CONTENT_EX +/etc/skel CONTENT_EX +/etc/sssd CONTENT_EX +/etc/machine-id$ CONTENT_EX +/etc/swid CONTENT_EX +/etc/system-release-cpe$ CONTENT_EX +/etc/shells$ CONTENT_EX +/etc/tmux.conf$ CONTENT_EX +/etc/xattr.conf$ CONTENT_EX + +# networking +/etc/firewalld CONTENT_EX +!/etc/NetworkManager/system-connections +/etc/NetworkManager CONTENT_EX +/etc/networks$ CONTENT_EX +/etc/dhcp CONTENT_EX +/etc/wpa_supplicant CONTENT_EX +/etc/resolv.conf$ DATAONLY +/etc/nscd.conf$ CONTENT_EX + +# logins and accounts +/etc/login.defs$ CONTENT_EX +/etc/libuser.conf$ CONTENT_EX +/var/log/faillog$ PERMS +/var/log/lastlog$ PERMS +/var/run/faillock PERMS +/etc/pam.d CONTENT_EX +/etc/security CONTENT_EX +/etc/securetty$ CONTENT_EX +/etc/polkit-1 CONTENT_EX +/etc/sudo.conf$ CONTENT_EX +/etc/sudoers$ CONTENT_EX +/etc/sudoers.d CONTENT_EX + +# Shell/X startup files +/etc/profile$ CONTENT_EX +/etc/profile.d CONTENT_EX +/etc/bashrc$ CONTENT_EX +/etc/bash_completion.d CONTENT_EX +/etc/zprofile$ CONTENT_EX +/etc/zshrc$ CONTENT_EX +/etc/zlogin$ CONTENT_EX +/etc/zlogout$ CONTENT_EX +/etc/X11 CONTENT_EX + +# Pkg manager +/etc/dnf CONTENT_EX +/etc/yum.conf$ CONTENT_EX +/etc/yum CONTENT_EX +/etc/yum.repos.d CONTENT_EX + +# This gets new/removes-old filenames daily +!/var/log/sa +# As we are checking it, we've truncated yesterdays size to zero. +!/var/log/aide.log + +# auditing +# AIDE produces an audit record, so this becomes perpetual motion. +/var/log/audit PERMS +/etc/audit CONTENT_EX +/etc/libaudit.conf$ CONTENT_EX +/etc/aide.conf$ CONTENT_EX + +# System logs +/etc/rsyslog.conf$ CONTENT_EX +/etc/rsyslog.d CONTENT_EX +/etc/logrotate.conf$ CONTENT_EX +/etc/logrotate.d CONTENT_EX +/etc/systemd/journald.conf$ CONTENT_EX +/var/log LOG+ANF+ARF +/var/run/utmp LOG + +# secrets +/etc/pkcs11 CONTENT_EX +/etc/pki CONTENT_EX +/etc/crypto-policies CONTENT_EX +/etc/certmonger CONTENT_EX +/var/lib/systemd/random-seed$ PERMS + +# init system +/etc/systemd CONTENT_EX +/etc/rc.d CONTENT_EX +/etc/tmpfiles.d CONTENT_EX + +# boot config +/etc/default CONTENT_EX +/etc/grub.d CONTENT_EX +/etc/dracut.conf$ CONTENT_EX +/etc/dracut.conf.d CONTENT_EX + +# glibc linker +/etc/ld.so.cache$ CONTENT_EX +/etc/ld.so.conf$ CONTENT_EX +/etc/ld.so.conf.d CONTENT_EX +/etc/ld.so.preload$ CONTENT_EX + +# kernel config +/etc/sysctl.conf$ CONTENT_EX +/etc/sysctl.d CONTENT_EX +/etc/modprobe.d CONTENT_EX +/etc/modules-load.d CONTENT_EX +/etc/depmod.d CONTENT_EX +/etc/udev CONTENT_EX +/etc/crypttab$ CONTENT_EX + +#### Daemons #### + +# cron jobs +/etc/at.allow$ CONTENT +/etc/at.deny$ CONTENT +/etc/anacrontab$ CONTENT_EX +/etc/cron.allow$ CONTENT_EX +/etc/cron.deny$ CONTENT_EX +/etc/cron.d CONTENT_EX +/etc/cron.daily CONTENT_EX +/etc/cron.hourly CONTENT_EX +/etc/cron.monthly CONTENT_EX +/etc/cron.weekly CONTENT_EX +/etc/crontab$ CONTENT_EX +/var/spool/cron/root CONTENT + +# time keeping +/etc/chrony.conf$ CONTENT_EX +/etc/chrony.keys$ CONTENT_EX + +# mail +/etc/aliases$ CONTENT_EX +/etc/aliases.db$ CONTENT_EX +/etc/postfix CONTENT_EX + +# ssh +/etc/ssh/sshd_config$ CONTENT_EX +/etc/ssh/ssh_config$ CONTENT_EX + +# stunnel +/etc/stunnel CONTENT_EX + +# printing +/etc/cups CONTENT_EX +/etc/cupshelpers CONTENT_EX +/etc/avahi CONTENT_EX + +# web server +/etc/httpd CONTENT_EX + +# dns +/etc/named CONTENT_EX +/etc/named.conf$ CONTENT_EX +/etc/named.iscdlv.key$ CONTENT_EX +/etc/named.rfc1912.zones$ CONTENT_EX +/etc/named.root.key$ CONTENT_EX + +# xinetd +/etc/xinetd.conf$ CONTENT_EX +/etc/xinetd.d CONTENT_EX + +# IPsec +/etc/ipsec.conf$ CONTENT_EX +/etc/ipsec.secrets$ CONTENT_EX +/etc/ipsec.d CONTENT_EX + +# USB guard +/etc/usbguard CONTENT_EX + +# Ignore some files +!/etc/mtab$ +!/etc/.*~ + +# Now everything else +/etc PERMS + +# With AIDE's default verbosity level of 5, these would give lots of +# warnings upon tree traversal. It might change with future version. +# +#=/lost\+found DIR +#=/home DIR diff --git a/examples/custom-template.yml b/examples/custom-template.yml new file mode 100644 index 0000000..318b551 --- /dev/null +++ b/examples/custom-template.yml @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: MIT +--- +- name: Example aide role invocation + hosts: targets + tasks: + - name: Include role aide + vars: + aide_db_template: /tmp/aide-custom.conf.j2 + aide_db_fetch_dir: files + aide_init: true + aide_fetch_db: true + aide_check: true + aide_update: true + ansible.builtin.include_role: + name: linux-system-roles.aide diff --git a/examples/default.yml b/examples/default.yml new file mode 100644 index 0000000..8bcc5b2 --- /dev/null +++ b/examples/default.yml @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: MIT +--- +- name: Example aide role invocation + hosts: targets + tasks: + - name: Include role aide + vars: + aide_db_fetch_dir: files + aide_init: false + aide_fetch_db: false + aide_check: false + aide_update: false + ansible.builtin.include_role: + name: linux-system-roles.aide diff --git a/examples/deploy.yml b/examples/deploy.yml new file mode 100644 index 0000000..589c241 --- /dev/null +++ b/examples/deploy.yml @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: MIT +--- +- name: Example aide role invocation + hosts: targets + tasks: + - name: Include role aide + vars: + aide_db_fetch_dir: files + aide_init: true + aide_fetch_db: false + aide_check: false + aide_update: false + ansible.builtin.include_role: + name: linux-system-roles.aide diff --git a/examples/just_check.yml b/examples/just_check.yml new file mode 100644 index 0000000..45f6253 --- /dev/null +++ b/examples/just_check.yml @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: MIT +--- +- name: Example aide role invocation + hosts: targets + tasks: + - name: Include role aide + vars: + aide_db_fetch_dir: files + aide_init: false + aide_fetch_db: false + aide_check: true + aide_update: false + ansible.builtin.include_role: + name: linux-system-roles.aide diff --git a/examples/just_update.yml b/examples/just_update.yml new file mode 100644 index 0000000..d337390 --- /dev/null +++ b/examples/just_update.yml @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: MIT +--- +- name: Example aide role invocation + hosts: targets + tasks: + - name: Include role aide + vars: + aide_db_fetch_dir: files + aide_init: false + aide_fetch_db: false + aide_check: false + aide_update: true + ansible.builtin.include_role: + name: linux-system-roles.aide diff --git a/examples/simple.yml b/examples/simple.yml deleted file mode 100644 index 10359eb..0000000 --- a/examples/simple.yml +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: MIT ---- -- name: Example aide role invocation - hosts: all - vars: - aide_foo: example variable value - aide_bar: false - roles: - - linux-system-roles.aide diff --git a/meta/main.yml b/meta/main.yml index a8a1444..298a07e 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -1,20 +1,73 @@ # SPDX-License-Identifier: MIT --- galaxy_info: - author: John Doe - description: Basic template for Linux system roles - company: John Doe, Inc. + # Replace with role's author name: + author: Joerg Kastning + # Replace with the real description of what is role's purpose: + description: Install, configure and operate AIDE + # Replace with the company the role's author is member of: + company: Red Hat Inc. + + # If the issue tracker for your role is not on github, uncomment the next + # line and provide a value + # issue_tracker_url: http://example.com/issue/tracker + + # Some suggested licenses: + # - BSD (default) + # - MIT + # - GPLv2 + # - GPLv3 + # - Apache + # - CC-BY license: MIT + min_ansible_version: "2.9" + + # Optionally specify the branch Galaxy will use when accessing the GitHub + # repo for this role. During role install, if no tags are available, Galaxy + # will use this branch. During import Galaxy will access files on this + # branch. If Travis integration is configured, only notifications for this + # branch will be accepted. Otherwise, in all cases, the repo's default branch + # (usually main) will be used. + # github_branch: + + # + # platforms is a list of platforms, and each platform has a name and a list + # of versions. + # + # platforms: + # - name: Fedora + # versions: + # - all + # - "25" + # - name: SomePlatform + # versions: + # - all + # - "1.0" + # - "7" + # - "99.99" platforms: + # Replace the below with your platform list: - name: Fedora versions: - all - name: EL versions: + - "8" - "9" + galaxy_tags: + - el8 - el9 - el10 - fedora + # List tags for your role here, one per line. A tag is a keyword that + # describes and categorizes the role. Users find roles by searching for tags. + # Be sure to remove the '[]' above, if you add tags to this list. + # + # NOTE: A tag is limited to a single word comprised of alphanumeric + # characters. Maximum 20 tags per role. + dependencies: [] +# List your role dependencies here, one per line. Be sure to remove the '[]' +# above, if you add dependencies to this list. diff --git a/tasks/main.yml b/tasks/main.yml index e756be5..cc7484e 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -5,23 +5,102 @@ # Examples of some tasks: - name: Ensure required packages are installed - package: + ansible.builtin.package: name: "{{ __aide_packages }}" state: present use: "{{ (__aide_is_ostree | d(false)) | ternary('ansible.posix.rhel_rpm_ostree', omit) }}" - name: Ensure required services are enabled and started - service: + ansible.builtin.service: name: "{{ item }}" state: started enabled: true loop: "{{ __aide_services }}" -- name: Generate /etc/{{ __aide_foo_config }} - template: - src: "{{ __aide_foo_config }}.j2" - dest: /etc/{{ __aide_foo_config }} - backup: true +- name: Generate "/etc/{{ __aide_config }}" + ansible.builtin.template: + src: "{{ aide_db_template }}" + dest: "/etc/{{ __aide_config }}" mode: "0400" - notify: Handler for aide to restart services + when: aide_db_template is not none + +# - name: Print Header +# ansible.builtin.shell: head /etc/aide.conf || true + +- name: Initialize AIDE database + when: aide_init | bool + block: + - name: Initialize AIDE database + ansible.builtin.command: + cmd: aide --init + changed_when: true + + - name: Copy AIDE reference database + ansible.builtin.copy: + remote_src: true + src: "{{ __aide_db_new_name }}" + dest: "{{ __aide_db_name }}" + owner: root + group: root + mode: "0440" + force: true + when: not aide_fetch_db | bool + + - name: Remove remote AIDE database file + ansible.builtin.file: + path: "{{ __aide_db_new_name }}" + state: absent + when: not aide_fetch_db | bool + +- name: Fetch AIDE database + when: aide_fetch_db | bool + block: + - name: Fetch AIDE database + ansible.builtin.fetch: + src: "{{ __aide_db_new_name }}" + dest: "{{ aide_db_fetch_dir }}" + + - name: Remove remote AIDE database file + ansible.builtin.file: + path: "{{ __aide_db_new_name }}" + state: absent + +- name: Check AIDE integrity + when: aide_check | bool + block: + - name: Copy AIDE reference database + ansible.builtin.copy: + src: "{{ aide_db_fetch_dir }}/{{ inventory_hostname }}\ + {{ __aide_db_new_name }}" + dest: "{{ __aide_db_name }}" + owner: root + group: root + mode: "0440" + when: aide_fetch_db | bool + + - name: Check against AIDE reference database + ansible.builtin.command: + cmd: aide --check + changed_when: true + +- name: Update AIDE database and fetch it + when: aide_update | bool + block: + - name: Update AIDE database + ansible.builtin.command: + cmd: aide --update + register: __aide_update_result + failed_when: "'AIDE found NO differences between database and filesystem. Looks okay!!'\ + not in __aide_update_result.stdout" + changed_when: true + + - name: Fetch AIDE database + ansible.builtin.fetch: + src: "{{ __aide_db_new_name }}" + dest: "{{ aide_db_fetch_dir }}" + + - name: Remove remote AIDE database file + ansible.builtin.file: + path: "{{ __aide_db_new_name }}" + state: absent diff --git a/tasks/set_vars.yml b/tasks/set_vars.yml index c1ef3f6..48d2fc2 100644 --- a/tasks/set_vars.yml +++ b/tasks/set_vars.yml @@ -1,12 +1,12 @@ --- - name: Ensure ansible_facts used by role setup: - gather_subset: "{{ __template_required_facts_subsets }}" - when: __template_required_facts | + gather_subset: "{{ __aide_required_facts_subsets }}" + when: __aide_required_facts | difference(ansible_facts.keys() | list) | length > 0 - name: Determine if system is ostree and set flag - when: not __template_is_ostree is defined + when: not __aide_is_ostree is defined block: - name: Check if system is ostree stat: @@ -15,7 +15,7 @@ - name: Set flag to indicate system is ostree set_fact: - __template_is_ostree: "{{ __ostree_booted_stat.stat.exists }}" + __aide_is_ostree: "{{ __ostree_booted_stat.stat.exists }}" - name: Set platform/version specific variables include_vars: "{{ __vars_file }}" diff --git a/templates/foo.conf.j2 b/templates/foo.conf.j2 deleted file mode 100644 index 5fc204b..0000000 --- a/templates/foo.conf.j2 +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: MIT -# -# Example of a template of configuration file -# -{{ ansible_managed | comment }} -{{ "system_role:template" | comment(prefix="", postfix="") }} -[foo] -foo = {{ template_foo }} -bar = {{ template_bar }} diff --git a/tests/files/aide-custom.conf.j2 b/tests/files/aide-custom.conf.j2 new file mode 100644 index 0000000..e0ce4cf --- /dev/null +++ b/tests/files/aide-custom.conf.j2 @@ -0,0 +1,319 @@ +{{ ansible_managed | comment }} +{{ "system_role:aide" | comment(prefix="", postfix="") }} +# Example configuration file for AIDE. + +@@define DBDIR /var/lib/aide +@@define LOGDIR /var/log/aide + +{% if ansible_facts['os_family'] == 'RedHat' and + ansible_facts['distribution_major_version'] in ['8','9'] %} +# The location of the database to be read. +database=file:@@{DBDIR}/aide.db.gz +{% else %} +# The location of the database to be read. +database_in=file:@@{DBDIR}/aide.db.gz +{% endif %} + +# The location of the database to be written. +#database_out=sql:host:port:database:login_name:passwd:table +#database_out=file:aide.db.new +database_out=file:@@{DBDIR}/aide.db.new.gz + +# Whether to gzip the output to database +gzip_dbout=yes + +{% if ansible_facts['os_family'] == 'RedHat' and + ansible_facts['distribution_major_version'] in ['8','9'] %} +# Default. +verbose=5 +{% else %} +# Default. +log_level=warning +report_level=changed_attributes +{% endif %} + +report_url=file:@@{LOGDIR}/aide.log +report_url=stdout +#report_url=stderr +#NOT IMPLEMENTED report_url=mailto:root@foo.com +#NOT IMPLEMENTED report_url=syslog:LOG_AUTH + +# These are the default rules. +# +#p: permissions +#i: inode: +#n: number of links +#u: user +#g: group +#s: size +#b: block count +#m: mtime +#a: atime +#c: ctime +#S: check for growing size +#acl: Access Control Lists +#selinux SELinux security context +#xattrs: Extended file attributes +#md5: md5 checksum +#sha1: sha1 checksum +#sha256: sha256 checksum +#sha512: sha512 checksum +#rmd160: rmd160 checksum +#tiger: tiger checksum + +#haval: haval checksum (MHASH only) +#gost: gost checksum (MHASH only) +#crc32: crc32 checksum (MHASH only) +#whirlpool: whirlpool checksum (MHASH only) + +#R: p+i+n+u+g+s+m+c+acl+selinux+xattrs+md5 +#L: p+i+n+u+g+acl+selinux+xattrs +#E: Empty group +#>: Growing logfile p+u+g+i+n+S+acl+selinux+xattrs + +# You can create custom rules like this. +# With MHASH... +# ALLXTRAHASHES = sha1+rmd160+sha256+sha512+whirlpool+tiger+haval+gost+crc32 +ALLXTRAHASHES = sha1+rmd160+sha256+sha512+tiger +# Everything but access time (Ie. all changes) +EVERYTHING = R+ALLXTRAHASHES + +# Sane +# NORMAL = R+sha512 +NORMAL = p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha512 + +# For directories, don't bother doing hashes +DIR = p+i+n+u+g+acl+selinux+xattrs + +# Access control only +PERMS = p+u+g+acl+selinux+xattrs + +# Logfile are special, in that they often change +LOG = p+u+g+n+S+acl+selinux+xattrs + +# Content + file type. +CONTENT = sha512+ftype + +# Extended content + file type + access. +CONTENT_EX = sha512+ftype+p+u+g+n+acl+selinux+xattrs + +# Some files get updated automatically, so the inode/ctime/mtime change +# but we want to know when the data inside them changes +DATAONLY = p+n+u+g+s+acl+selinux+xattrs+sha512 + +# Next decide what directories/files you want in the database. + +/boot CONTENT_EX +/opt CONTENT + +# Admins dot files constantly change, just check perms +/root/\..* PERMS +!/root/.xauth* +# Otherwise get all of /root. +/root CONTENT_EX + +# These are too volatile +!/usr/src +!/usr/tmp +!/root/.ansible* + +# Otherwise get all of /usr. +/usr CONTENT_EX + +# trusted databases +/etc/hosts$ CONTENT_EX +/etc/host.conf$ CONTENT_EX +/etc/hostname$ CONTENT_EX +/etc/issue$ CONTENT_EX +/etc/issue.net$ CONTENT_EX +/etc/protocols$ CONTENT_EX +/etc/services$ CONTENT_EX +/etc/localtime$ CONTENT_EX +/etc/alternatives CONTENT_EX +/etc/sysconfig CONTENT_EX +/etc/mime.types$ CONTENT_EX +/etc/terminfo CONTENT_EX +/etc/exports$ CONTENT_EX +/etc/fstab$ CONTENT_EX +/etc/passwd$ CONTENT_EX +/etc/group$ CONTENT_EX +/etc/gshadow$ CONTENT_EX +/etc/shadow$ CONTENT_EX +/etc/subgid$ CONTENT_EX +/etc/subuid$ CONTENT_EX +/etc/security/opasswd$ CONTENT_EX +/etc/skel CONTENT_EX +/etc/sssd CONTENT_EX +/etc/machine-id$ CONTENT_EX +/etc/swid CONTENT_EX +/etc/system-release-cpe$ CONTENT_EX +/etc/shells$ CONTENT_EX +/etc/tmux.conf$ CONTENT_EX +/etc/xattr.conf$ CONTENT_EX + +# networking +/etc/firewalld CONTENT_EX +!/etc/NetworkManager/system-connections +/etc/NetworkManager CONTENT_EX +/etc/networks$ CONTENT_EX +/etc/dhcp CONTENT_EX +/etc/wpa_supplicant CONTENT_EX +/etc/resolv.conf$ DATAONLY +/etc/nscd.conf$ CONTENT_EX + +# logins and accounts +/etc/login.defs$ CONTENT_EX +/etc/libuser.conf$ CONTENT_EX +/var/log/faillog$ PERMS +/var/log/lastlog$ PERMS +/var/run/faillock PERMS +/etc/pam.d CONTENT_EX +/etc/security CONTENT_EX +/etc/securetty$ CONTENT_EX +/etc/polkit-1 CONTENT_EX +/etc/sudo.conf$ CONTENT_EX +/etc/sudoers$ CONTENT_EX +/etc/sudoers.d CONTENT_EX + +# Shell/X startup files +/etc/profile$ CONTENT_EX +/etc/profile.d CONTENT_EX +/etc/bashrc$ CONTENT_EX +/etc/bash_completion.d CONTENT_EX +/etc/zprofile$ CONTENT_EX +/etc/zshrc$ CONTENT_EX +/etc/zlogin$ CONTENT_EX +/etc/zlogout$ CONTENT_EX +/etc/X11 CONTENT_EX + +# Pkg manager +/etc/dnf CONTENT_EX +/etc/yum.conf$ CONTENT_EX +/etc/yum CONTENT_EX +/etc/yum.repos.d CONTENT_EX + +# This gets new/removes-old filenames daily +!/var/log/sa +# As we are checking it, we've truncated yesterdays size to zero. +!/var/log/aide.log + +# auditing +# AIDE produces an audit record, so this becomes perpetual motion. +/var/log/audit PERMS +/etc/audit CONTENT_EX +/etc/libaudit.conf$ CONTENT_EX +/etc/aide.conf$ CONTENT_EX + +# System logs +/etc/rsyslog.conf$ CONTENT_EX +/etc/rsyslog.d CONTENT_EX +/etc/logrotate.conf$ CONTENT_EX +/etc/logrotate.d CONTENT_EX +/etc/systemd/journald.conf$ CONTENT_EX +/var/log LOG+ANF+ARF +/var/run/utmp LOG + +# secrets +/etc/pkcs11 CONTENT_EX +/etc/pki CONTENT_EX +/etc/crypto-policies CONTENT_EX +/etc/certmonger CONTENT_EX +/var/lib/systemd/random-seed$ PERMS + +# init system +/etc/systemd CONTENT_EX +/etc/rc.d CONTENT_EX +/etc/tmpfiles.d CONTENT_EX + +# boot config +/etc/default CONTENT_EX +/etc/grub.d CONTENT_EX +/etc/dracut.conf$ CONTENT_EX +/etc/dracut.conf.d CONTENT_EX + +# glibc linker +/etc/ld.so.cache$ CONTENT_EX +/etc/ld.so.conf$ CONTENT_EX +/etc/ld.so.conf.d CONTENT_EX +/etc/ld.so.preload$ CONTENT_EX + +# kernel config +/etc/sysctl.conf$ CONTENT_EX +/etc/sysctl.d CONTENT_EX +/etc/modprobe.d CONTENT_EX +/etc/modules-load.d CONTENT_EX +/etc/depmod.d CONTENT_EX +/etc/udev CONTENT_EX +/etc/crypttab$ CONTENT_EX + +#### Daemons #### + +# cron jobs +/etc/at.allow$ CONTENT +/etc/at.deny$ CONTENT +/etc/anacrontab$ CONTENT_EX +/etc/cron.allow$ CONTENT_EX +/etc/cron.deny$ CONTENT_EX +/etc/cron.d CONTENT_EX +/etc/cron.daily CONTENT_EX +/etc/cron.hourly CONTENT_EX +/etc/cron.monthly CONTENT_EX +/etc/cron.weekly CONTENT_EX +/etc/crontab$ CONTENT_EX +/var/spool/cron/root CONTENT + +# time keeping +/etc/chrony.conf$ CONTENT_EX +/etc/chrony.keys$ CONTENT_EX + +# mail +/etc/aliases$ CONTENT_EX +/etc/aliases.db$ CONTENT_EX +/etc/postfix CONTENT_EX + +# ssh +/etc/ssh/sshd_config$ CONTENT_EX +/etc/ssh/ssh_config$ CONTENT_EX + +# stunnel +/etc/stunnel CONTENT_EX + +# printing +/etc/cups CONTENT_EX +/etc/cupshelpers CONTENT_EX +/etc/avahi CONTENT_EX + +# web server +/etc/httpd CONTENT_EX + +# dns +/etc/named CONTENT_EX +/etc/named.conf$ CONTENT_EX +/etc/named.iscdlv.key$ CONTENT_EX +/etc/named.rfc1912.zones$ CONTENT_EX +/etc/named.root.key$ CONTENT_EX + +# xinetd +/etc/xinetd.conf$ CONTENT_EX +/etc/xinetd.d CONTENT_EX + +# IPsec +/etc/ipsec.conf$ CONTENT_EX +/etc/ipsec.secrets$ CONTENT_EX +/etc/ipsec.d CONTENT_EX + +# USB guard +/etc/usbguard CONTENT_EX + +# Ignore some files +!/etc/mtab$ +!/etc/.*~ + +# Now everything else +/etc PERMS + +# With AIDE's default verbosity level of 5, these would give lots of +# warnings upon tree traversal. It might change with future version. +# +#=/lost\+found DIR +#=/home DIR diff --git a/tests/tasks/check_not_present_header.yml b/tests/tasks/check_not_present_header.yml new file mode 100644 index 0000000..3362e18 --- /dev/null +++ b/tests/tasks/check_not_present_header.yml @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: MIT +--- +- name: Get file + slurp: + path: "{{ __file }}" + register: __content + when: not __file_content is defined + +- name: Check for presence of ansible managed header, fingerprint + assert: + that: + - ansible_managed not in content + - __fingerprint not in content + vars: + content: "{{ (__file_content | d(__content)).content | b64decode }}" + ansible_managed: "{{ lookup('template', 'get_ansible_managed.j2') }}" diff --git a/tests/tests_custom_template.yml b/tests/tests_custom_template.yml new file mode 100644 index 0000000..999a22b --- /dev/null +++ b/tests/tests_custom_template.yml @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: MIT +--- +- name: Ensure that the role runs with default parameters + hosts: all + gather_facts: false # test that role works in this case + roles: + - role: linux-system-roles.aide + vars: + aide_db_template: files/aide-custom.conf.j2 + aide_install: true + aide_init: true + tasks: + - name: Check header for ansible_managed, fingerprint + include_tasks: tasks/check_header.yml + vars: + __file: /etc/aide.conf + __fingerprint: system_role:aide diff --git a/tests/tests_default.yml b/tests/tests_default.yml index b82e8f2..8385f8b 100644 --- a/tests/tests_default.yml +++ b/tests/tests_default.yml @@ -6,8 +6,21 @@ roles: - linux-system-roles.aide tasks: - - name: Check header for ansible_managed, fingerprint - include_tasks: tasks/check_header.yml - vars: - __file: /etc/foo.conf - __fingerprint: system_role:aide + - name: Check if file exists + block: + - name: Check if the file exists + ansible.builtin.stat: + path: "/etc/aide.conf" + register: file_check + + - name: Assert that the file exists + ansible.builtin.assert: + that: + - file_check.stat.exists + fail_msg: "The file does not exist." + + - name: Check header for not present ansible_managed, fingerprint + include_tasks: tasks/check_not_present_header.yml + vars: + __file: /etc/aide.conf + __fingerprint: system_role:aide diff --git a/tests/tests_deploy.yml b/tests/tests_deploy.yml new file mode 100644 index 0000000..5fcce4a --- /dev/null +++ b/tests/tests_deploy.yml @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: MIT +--- +- name: Ensure that the role runs with default parameters + hosts: all + gather_facts: false # test that role works in this case + roles: + - role: linux-system-roles.aide + vars: + aide_init: true + tasks: + - name: Check header for ansible_managed, fingerprint + include_tasks: tasks/check_not_present_header.yml + vars: + __file: /etc/aide.conf + __fingerprint: system_role:aide diff --git a/vars/AlmaLinux_10.yml b/vars/AlmaLinux_10.yml deleted file mode 120000 index f830d5f..0000000 --- a/vars/AlmaLinux_10.yml +++ /dev/null @@ -1 +0,0 @@ -RedHat_10.yml \ No newline at end of file diff --git a/vars/AlmaLinux_8.yml b/vars/AlmaLinux_8.yml deleted file mode 120000 index ad7713d..0000000 --- a/vars/AlmaLinux_8.yml +++ /dev/null @@ -1 +0,0 @@ -RedHat_8.yml \ No newline at end of file diff --git a/vars/AlmaLinux_9.yml b/vars/AlmaLinux_9.yml deleted file mode 120000 index 0eb3795..0000000 --- a/vars/AlmaLinux_9.yml +++ /dev/null @@ -1 +0,0 @@ -RedHat_9.yml \ No newline at end of file diff --git a/vars/CentOS_10.yml b/vars/CentOS_10.yml deleted file mode 120000 index f830d5f..0000000 --- a/vars/CentOS_10.yml +++ /dev/null @@ -1 +0,0 @@ -RedHat_10.yml \ No newline at end of file diff --git a/vars/CentOS_7.yml b/vars/CentOS_7.yml deleted file mode 120000 index 105e630..0000000 --- a/vars/CentOS_7.yml +++ /dev/null @@ -1 +0,0 @@ -RedHat_7.yml \ No newline at end of file diff --git a/vars/CentOS_8.yml b/vars/CentOS_8.yml deleted file mode 120000 index ad7713d..0000000 --- a/vars/CentOS_8.yml +++ /dev/null @@ -1 +0,0 @@ -RedHat_8.yml \ No newline at end of file diff --git a/vars/CentOS_9.yml b/vars/CentOS_9.yml deleted file mode 120000 index 0eb3795..0000000 --- a/vars/CentOS_9.yml +++ /dev/null @@ -1 +0,0 @@ -RedHat_9.yml \ No newline at end of file diff --git a/vars/Fedora.yml b/vars/Fedora.yml deleted file mode 100644 index a783f79..0000000 --- a/vars/Fedora.yml +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: MIT ---- -# Put internal variables here with Fedora specific values. - -# Example: -__template_packages: [] -__template_services: [] diff --git a/vars/RedHat_10.yml b/vars/RedHat_10.yml deleted file mode 100644 index c1a73a0..0000000 --- a/vars/RedHat_10.yml +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: MIT ---- -# Put internal variables here with Red Hat Enterprise Linux 10 specific values. - -# Example: -__template_packages: [] -__template_services: [] diff --git a/vars/RedHat_7.yml b/vars/RedHat_7.yml deleted file mode 100644 index 3815df4..0000000 --- a/vars/RedHat_7.yml +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: MIT ---- -# Put internal variables here with Red Hat Enterprise Linux 7 specific values. - -# Example: -__template_packages: [] -__template_services: [] diff --git a/vars/RedHat_8.yml b/vars/RedHat_8.yml deleted file mode 100644 index 954bf90..0000000 --- a/vars/RedHat_8.yml +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: MIT ---- -# Put internal variables here with Red Hat Enterprise Linux 8 specific values. - -# Example: -__template_packages: [] -__template_services: [] diff --git a/vars/RedHat_9.yml b/vars/RedHat_9.yml deleted file mode 100644 index b367bff..0000000 --- a/vars/RedHat_9.yml +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: MIT ---- -# Put internal variables here with Red Hat Enterprise Linux 9 specific values. - -# Example: -__template_packages: [] -__template_services: [] diff --git a/vars/Rocky_10.yml b/vars/Rocky_10.yml deleted file mode 120000 index f830d5f..0000000 --- a/vars/Rocky_10.yml +++ /dev/null @@ -1 +0,0 @@ -RedHat_10.yml \ No newline at end of file diff --git a/vars/Rocky_8.yml b/vars/Rocky_8.yml deleted file mode 120000 index ad7713d..0000000 --- a/vars/Rocky_8.yml +++ /dev/null @@ -1 +0,0 @@ -RedHat_8.yml \ No newline at end of file diff --git a/vars/Rocky_9.yml b/vars/Rocky_9.yml deleted file mode 120000 index 0eb3795..0000000 --- a/vars/Rocky_9.yml +++ /dev/null @@ -1 +0,0 @@ -RedHat_9.yml \ No newline at end of file diff --git a/vars/main.yml b/vars/main.yml index 3c51452..13c2628 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -5,9 +5,11 @@ # value in a platform/version specific file in vars/ # Examples of non-distribution specific (generic) internal variables: -__aide_foo_config: foo.conf -__aide_packages: [] +__aide_config: aide.conf +__aide_packages: ['aide'] __aide_services: [] +__aide_db_name: /var/lib/aide/aide.db.gz +__aide_db_new_name: /var/lib/aide/aide.db.new.gz # ansible_facts required by the role __aide_required_facts: - distribution @@ -35,5 +37,6 @@ __aide_rh_distros_fedora: "{{ __aide_rh_distros + ['Fedora'] }}" __aide_is_rh_distro: "{{ ansible_distribution in __aide_rh_distros }}" # Use this in conditionals to check if distro is Red Hat or clone, or Fedora -__aide_is_rh_distro_fedora: "{{ ansible_distribution in __aide_rh_distros_fedora }}" +__aide_is_rh_distro_fedora: \ + "{{ ansible_distribution in __aide_rh_distros_fedora }}" # END - DO NOT EDIT THIS BLOCK - rh distros variables