Examples
The contract (env, argv, skip rules) lives in
Reference and in hooks.d/README. These are extra
recipes. Save each file in /etc/user-notifier/hooks.d/, then
chmod +x.
Syslog
#!/bin/sh
logger -t user-notifier -- "${NOTIFY_TYPE} ${NOTIFY_STATE} ${NOTIFY_HOST} ${NOTIFY_DETAILS}"
Save as 40-syslog.
Mail root
#!/bin/sh
printf '%s\n' "${NOTIFY_DETAILS}" \
| mail -s "user-notifier ${NOTIFY_TYPE} ${NOTIFY_STATE} on ${NOTIFY_HOST}" root
Save as 60-mail. Needs a working local mail command.
Sudo only
Skip everything except privilege escalation:
#!/bin/sh
case "${NOTIFY_TYPE}" in
sudo|su) ;;
*) exit 0 ;;
esac
logger -t user-notifier -- "${NOTIFY_TYPE} ${NOTIFY_STATE} ${NOTIFY_DETAILS}"
Save as 30-sudo-only.
Second webhook
50-slack reads SLACK_WEBHOOK_URL. For another channel, hard-code a
second URL in its own hook (keep the secret in a 0640 file, not in
git):
#!/usr/bin/env python3
import json
import os
import urllib.request
url = open("/etc/user-notifier/ops.webhook", encoding="utf-8").read().strip()
if not url:
raise SystemExit(0)
payload = {
"channel": "#ops",
"username": "AuditBot",
"text": f"{os.environ.get('NOTIFY_TYPE')} {os.environ.get('NOTIFY_DETAILS')}",
}
req = urllib.request.Request(
url,
data=json.dumps(payload).encode("utf-8"),
headers={"Content-Type": "application/json"},
method="POST",
)
urllib.request.urlopen(req, timeout=15)
Save as 55-ops-slack.