Skip to content

Commit

Permalink
ossec: send journalist about the number of submissions in the past 24h
Browse files Browse the repository at this point in the history
A cron job runs daily on the app server and updates the

   /var/lib/securedrop/submissions_today.txt

file which contains the number of submissions sent in the past 24h, as
created by the manage.py how_many_submissions_today command.

The OSSEC agence on the app server runs a command daily, displaying
the content of /var/lib/securedrop/submissions_today.txt. The output
of the command is sent to the OSSEC server.

A new rule is defined on the OSSEC server to send a mail to
journalist@localhost when the output is received from the OSSEC agent
running on the app server.

A new procmail rule is definied on the OSSEC server to encrypt mails
received by journalist@localhost and send them to the email defined by
the journalist_alert_email ansible variable.

A new set of ansible (optional) variables, similar to
ossec_alert_gpg_public_key, ossec_gpg_fpr, ossec_alert_email are
defined: journalist_alert_gpg_public_key, journalist_gpg_fpr,
journalist_alert_email. They are used to upload a journalist public
key to the OSSEC server and inserted into the send_encrypted_alarm.sh
script which handles mails received by procmail.

The modified send_encrypted_alarm.sh script takes one
argument (journalist or ossec) and dispatching the mail read from
stdin to the corresponding recipient.

Integration tests are implemented to verify the following:

  * manage.py how_many_submissions_today
  * the app OSSEC agent sends a mail to the journalist address
  * cover all branches of send_encrypted_alarm.sh
  • Loading branch information
Loic Dachary committed Jan 27, 2018
1 parent adc9c5b commit c3a8a82
Show file tree
Hide file tree
Showing 13 changed files with 292 additions and 13 deletions.
3 changes: 3 additions & 0 deletions install_files/ansible-base/group_vars/staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ apache_logging_level: "info"
ossec_alert_gpg_public_key: "test_admin_key.pub"
ossec_gpg_fpr: "53E1113AC1F25027BA5D475B1141E2BBB5E53711"
ossec_alert_email: "[email protected]"
journalist_alert_gpg_public_key: "test_admin_key.pub"
journalist_gpg_fpr: "53E1113AC1F25027BA5D475B1141E2BBB5E53711"
journalist_alert_email: "[email protected]"
smtp_relay: "smtp.faketld"
smtp_relay_port: "587"
sasl_username: "test"
Expand Down
3 changes: 3 additions & 0 deletions install_files/ansible-base/prod-specific.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ securedrop_app_gpg_fingerprint: ""
ossec_alert_gpg_public_key: ""
ossec_gpg_fpr: ""
ossec_alert_email: ""
journalist_alert_gpg_public_key: ""
journalist_gpg_fpr: ""
journalist_alert_email: ""
smtp_relay: ""
smtp_relay_port: ""
sasl_username: ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@
with_items: "{{ apparmor_profiles }}"
tags: apparmor

- name: Create cron.daily directory.
file:
state: directory
dest: "{{ securedrop_app_code_deb_dir }}/etc/cron.daily"

- name: Copy crontab.
copy:
src: cron.daily
dest: "{{ securedrop_app_code_deb_dir }}/etc/cron.daily/securedrop"
mode: 0755

- name: Build securedrop-app-code Debian package.
command: dpkg-deb --build {{ securedrop_app_code_deb_dir }}

Expand Down
14 changes: 10 additions & 4 deletions install_files/ansible-base/roles/ossec/tasks/configure_server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@

- name: Copy the OSSEC GPG public key for sending encrypted alerts.
copy:
src: "{{ ossec_alert_gpg_public_key }}"
src: "{{ item }}"
dest: /var/ossec
when: "'{{ item }}' != ''"
with_items:
- "{{ ossec_alert_gpg_public_key }}"
- "{{ journalist_alert_gpg_public_key }}"
tags:
- gpg

Expand All @@ -21,11 +25,13 @@
command: >
gpg
--homedir /var/ossec/.gnupg
--import /var/ossec/{{ ossec_alert_gpg_public_key }}
--import /var/ossec/{{ item }}
become: yes
become_user: "{{ ossec_group }}"
register: add_ossec_gpg_key_result
changed_when: "'imported: 1' in add_ossec_gpg_key_result.stderr"
when: "'{{ item }}' != ''"
with_items:
- "{{ ossec_alert_gpg_public_key }}"
- "{{ journalist_alert_gpg_public_key }}"
tags:
- gpg

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/bin/bash
# shellcheck disable=SC2086
# Handler script to encrypt OSSEC alerts prior to mailing.
# Called via the `.procmailrc` for user `ossec`.

Expand All @@ -16,34 +17,53 @@ set -o pipefail
# encryption fail.
ossec_alert_text="$(< /dev/stdin)"

# default to environment even if null
env | grep -q JOURNALIST_EMAIL || JOURNALIST_EMAIL='{{ journalist_alert_email }}'
env | grep -q OSSEC_EMAIL || OSSEC_EMAIL='{{ ossec_alert_email }}'

# Primary "send email to Admin" functionality.
function send_encrypted_alert() {
local recipient="$1"
local gpg_fpr
local alert_email
if [[ "$recipient" = "journalist" ]] ; then
gpg_fpr='{{ journalist_gpg_fpr }}'
alert_email="$JOURNALIST_EMAIL"
if [[ "$alert_email" = "" ]] ; then
echo "journalist alert email unset, no notification sent"
return
fi
else
gpg_fpr='{{ ossec_gpg_fpr }}'
alert_email="$OSSEC_EMAIL"
fi

local encrypted_alert_text
# Try to encrypt the alert message. We'll inspect the exit status of the
# pipeline to decide whether to send the alert text, or the default
# failure message.
encrypted_alert_text="$(printf "%s" "${ossec_alert_text}" | \
/usr/bin/formail -I '' | \
/usr/bin/gpg --homedir /var/ossec/.gnupg --trust-model always -ear '{{ ossec_gpg_fpr }}')"
/usr/bin/gpg --homedir /var/ossec/.gnupg --trust-model always -ear $gpg_fpr)"

# Error handling.
if [[ -z "${encrypted_alert_text}" || $? -ne 0 ]]; then
send_plaintext_fail_message
send_plaintext_fail_message "$alert_email"
else
echo "${encrypted_alert_text}" | \
/usr/bin/mail -s "$(echo "${SUBJECT}" | sed -r 's/([0-9]{1,3}\.){3}[0-9]{1,3}\s?//g' )" '{{ ossec_alert_email }}'
/usr/bin/mail -s "$(echo "${SUBJECT}" | sed -r 's/([0-9]{1,3}\.){3}[0-9]{1,3}\s?//g' )" "$alert_email"
fi
}

# Failover alerting function, in case the primary function failed.
# Usually a failure is related to GPG balking on the encryption step;
# that may be due to a missing pubkey or something reason.
function send_plaintext_fail_message() {
local alert_email="$1"
printf "Failed to encrypt OSSEC alert. Investigate the mailing configuration on the Monitor Server." | \
/usr/bin/formail -I "" | \
/usr/bin/mail -s "$(echo "${SUBJECT}" | sed -r 's/([0-9]{1,3}\.){3}[0-9]{1,3}\s?//g' )" '{{ ossec_alert_email }}'
/usr/bin/mail -s "$(echo "${SUBJECT}" | sed -r 's/([0-9]{1,3}\.){3}[0-9]{1,3}\s?//g' )" "$alert_email"
}

# Encrypt the OSSEC notification and pass to mailer for sending.
send_encrypted_alert
send_encrypted_alert "$@"
1 change: 1 addition & 0 deletions install_files/ansible-base/roles/postfix/files/aliases
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
root: ossec
journalist: ossec
6 changes: 5 additions & 1 deletion install_files/ansible-base/roles/postfix/files/procmailrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ LOGFILE=/var/log/procmail.log
SUBJECT=`formail -xSubject:`
:0 c
*^To:.*root.*
|/var/ossec/send_encrypted_alarm.sh
|/var/ossec/send_encrypted_alarm.sh ossec

:0 c
*^To:.*journalist.*
|/var/ossec/send_encrypted_alarm.sh journalist
8 changes: 8 additions & 0 deletions install_files/securedrop-ossec-agent/var/ossec/etc/ossec.conf
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@

<ignore>/var/lib/securedrop/db.sqlite</ignore>

<ignore>/var/lib/securedrop/submissions_today.txt</ignore>

<ignore>/var/securedrop/store</ignore>

<ignore>/var/ossec/queue</ignore>
Expand Down Expand Up @@ -101,6 +103,12 @@
<command>last -n 5</command>
</localfile>

<localfile>
<log_format>full_command</log_format>
<command>head -1 /var/lib/securedrop/submissions_today.txt | grep '^[0-9]*$'</command>
<frequency>86400</frequency>
</localfile>

<localfile>
<log_format>syslog</log_format>
<location>/var/log/kern.log</location>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@
<do_not_delay />
</email_alerts>

<email_alerts>
<email_to>journalist@localhost</email_to>
<group>multiple_drops</group>
<do_not_delay />
</email_alerts>

<email_alerts>
<email_to>root@localhost</email_to>
<group>low_diskspace</group>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,11 @@
<options>no_email_alert</options>
</rule>
</group>

<group name="multiple_drops">
<rule id="400600" level="7" >
<if_sid>530</if_sid>
<match>ossec: output: 'head -1 /var/lib/securedrop/submissions_today.txt</match>
<description>Number of submissions received in the past 24h.</description>
</rule>
</group>
6 changes: 3 additions & 3 deletions testinfra/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
import yaml


target_host = os.environ['SECUREDROP_TESTINFRA_TARGET_HOST']
assert target_host != ""
target_host = os.environ.get('SECUREDROP_TESTINFRA_TARGET_HOST')


def securedrop_import_testinfra_vars(hostname, with_header=False):
Expand All @@ -37,4 +36,5 @@ def securedrop_import_testinfra_vars(hostname, with_header=False):


def pytest_namespace():
return securedrop_import_testinfra_vars(target_host, with_header=True)
if target_host:
return securedrop_import_testinfra_vars(target_host, with_header=True)
Loading

0 comments on commit c3a8a82

Please sign in to comment.