<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Grant Cohoe]]></title>
  <link href="http://www.grantcohoe.com/atom.xml" rel="self"/>
  <link href="http://www.grantcohoe.com/"/>
  <updated>2013-05-12T15:56:06-04:00</updated>
  <id>http://www.grantcohoe.com/</id>
  <author>
    <name><![CDATA[Grant Cohoe]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[STARRS Installation Guide]]></title>
    <link href="http://www.grantcohoe.com/blog/2013/04/24/starrs-installation-guide/"/>
    <updated>2013-04-24T11:06:00-04:00</updated>
    <id>http://www.grantcohoe.com/blog/2013/04/24/starrs-installation-guide</id>
    <content type="html"><![CDATA[<h1>Introduction</h1>

<h2>Purpose</h2>

<p>The purpose of this guide is to help an IT administrator install and configure the <a href="http://grantcohoe.com/projects/starrs">STARRS</a> network asset tracking application for a basic site.</p>

<h2>Audience</h2>

<p>The intended audience of this guide is IT administrators with Linux experience (specifically Red Hat) and a willingness to use open-source software.</p>

<h2>Commitment</h2>

<p>The install process should take around an hour provided appropriate resources.</p>

<h1>Description</h1>

<h2>Definition</h2>

<p>STARRS is a self-service network resource tracking and registration web application used to monitor resource utilization (such as IP addresses, DNS records, computers, etc). For more details, view the project description <a href="http://grantcohoe.com/projects/starrs">here</a>.</p>

<h2>Physical</h2>

<p>STARRS requires a database host and web server to operate. It is recommended to use a single virtual appliance for all STARRS functionality.</p>

<h2>Process</h2>

<ul>
<li>The virtual appliance is provisioned (out of scope of this guide)</li>
<li>Core software is installed</li>
<li>Dependent software packages are downloaded and installed</li>
<li>STARRS is acquired, configured, and installed</li>
<li>The web server is configured to allow access</li>
</ul>


<h1>Installation</h1>

<h2>Virtual Appliance</h2>

<p>STARRS was tested only on RHEL-based Linux distributions. Anything RHEL6.0+ is compatible. There are no major requirements for the virtual appliance and a minimal software install will suffice. In this example we will be using a Scientific Linux 6.4 virtual machine.</p>

<h2>Connectivity</h2>

<p>Ensure that you are able to log into your remote system as any administrative user (in this example, root) and have internet access.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@starrs-test ~]# cat /etc/redhat-release
</span><span class='line'>Scientific Linux release 6.4 (Carbon)</span></code></pre></td></tr></table></div></figure>


<h2>System Security</h2>

<h3>Firewall</h3>

<p>Firewalls can get in the way of allowing web access to the server. Only perform these steps if you have a system firewall installed and intend on using it. In this example we will use the RHEL default <code>iptables</code>.</p>

<ol>
<li>Add a rule to the system firewall to allow HTTP and HTTPS traffic to the server.</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT
</span><span class='line'>iptables -I INPUT 1 -p tcp --dport 443 -j ACCEPT</span></code></pre></td></tr></table></div></figure>


<ol>
<li>Save the firewall configuration (no restart required)</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>service iptables save</span></code></pre></td></tr></table></div></figure>


<p>NOTE: If you have IPv6 enabled on your system, make sure to apply firewall rules to the IPv6 firewall as well.</p>

<h3>SELinux</h3>

<p>Any RHEL administrator has dealt with SELinux at some point in their career. There are system-wide settings that allow/deny actions by programs running on the server. Disabling SELinux is not a solution.</p>

<ol>
<li>Allow Apache/httpd to connect to database engines</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>setsebool -P httpd_can_network_connect=on
</span><span class='line'>setsebool -P httpd_can_network_connect_db=on</span></code></pre></td></tr></table></div></figure>


<h2>Core Software</h2>

<p>STARRS heavily depends on the PostgreSQL database engine for operation. PgSQL must be at version 9.0 or higher, which is NOT available from the standard RHELish repositories. PgSQL will also require the PL/Perl and PL/Python support packages (also NOT located in the repos). You will need to add new software repositories to your appliance.</p>

<h3>Utilities</h3>

<p>These programs will be needed at some point or another in the installation process.</p>

<ol>
<li>Install the following packages through yum.</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>yum install cpan wget git make perl-YAML -y</span></code></pre></td></tr></table></div></figure>


<ol>
<li>We will also need the development tools group of packages installed.</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>yum groupinstall "Development tools" -y</span></code></pre></td></tr></table></div></figure>


<h3>PostgreSQL Database Engine</h3>

<ol>
<li><p>On your own computer, open up <a href="http://yum.postgresql.org/">yum.postgresql.org</a> and click on the latest available PostgreSQL Release link. In this case we will be using 9.2.</p></li>
<li><p>Locate the approprate repository link for your operating system (Fedora, CentOS, SL, etc) and architecture (i386, x86_64, etc). In this case we will be using <code>Scientific Linux 6 - i386</code>.</p></li>
<li><p>Download the package from the link you located onto the virtual appliance into any convenient directory.</p></li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>wget http://yum.postgresql.org/9.2/redhat/rhel-6-i386/pgdg-sl92-9.2-8.noarch.rpm</span></code></pre></td></tr></table></div></figure>


<ol>
<li>Install the PostgreSQL repository package file that was downloaded with <code>yum</code>. Answer yes if asked for verification.</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>yum install pgdg-sl92-9.2-8.noarch.rpm</span></code></pre></td></tr></table></div></figure>


<ol>
<li>You need to ensure that the base PostgreSQL packages are hidden from future package searches and updated. Add an exclude line to your base OS repository file located in <code>/etc/yum.repos.d/</code>. This will prevent any PgSQL packages from being used out of the base packages.</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># This example uses the sl.repo file. This will depend on your variant of OS (CentOS-base.repo for CentOS).
</span><span class='line'>[sl]
</span><span class='line'>name=Scientific Linux $releasever - $basearch
</span><span class='line'>...
</span><span class='line'>exclude=postgresql*
</span><span class='line'>
</span><span class='line'>[sl-security]</span></code></pre></td></tr></table></div></figure>


<ol>
<li>Install the required PgSQL packages using the Yum package manager.</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>yum install postgresql92 postgresql92-plperl postgresql92-server</span></code></pre></td></tr></table></div></figure>


<ol>
<li>Initialize the PgSQL database server</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@starrs-test ~]# service postgresql-9.2 initdb
</span><span class='line'>Initializing database:                                     [  OK  ]
</span><span class='line'>[root@starrs-test ~]#</span></code></pre></td></tr></table></div></figure>


<ol>
<li>Make PgSQL start on system boot</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>chkconfig postgresql-9.2 on</span></code></pre></td></tr></table></div></figure>


<ol>
<li>Start the PgSQL service</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@starrs-test ~]# service postgresql-9.2 start
</span><span class='line'>Starting postgresql-9.2 service:                           [  OK  ]
</span><span class='line'>[root@starrs-test ~]#</span></code></pre></td></tr></table></div></figure>


<ol>
<li><code>su</code> to the Postgres account and assign a password to the postgres user account using the query below. Exit back to root when done. This password should be kept secure!</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@starrs-test ~]# su postgres -
</span><span class='line'>bash-4.1$ psql
</span><span class='line'>could not change directory to "/root"
</span><span class='line'>psql (9.2.4)
</span><span class='line'>Type "help" for help.
</span><span class='line'>
</span><span class='line'>postgres=# ALTER USER postgres WITH PASSWORD 'supersecurepasswordhere';
</span><span class='line'>ALTER ROLE
</span><span class='line'>postgres=# \q
</span><span class='line'>bash-4.1$ exit
</span><span class='line'>exit
</span><span class='line'>[root@starrs-test ~]#</span></code></pre></td></tr></table></div></figure>


<p>The STARRS installer requires passwordless access to the postgres account. This is achievable by creating a <code>.pgpass</code> file in the root home directory.</p>

<ol>
<li>Create a file at <code>~/.pgpass</code> like such:</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>localhost:5432:*:postgres:supersecurepasswordhere
</span><span class='line'>localhost:5432:*:starrs_admin:adminpass
</span><span class='line'>localhost:5432:*:starrs_client:clientpass</span></code></pre></td></tr></table></div></figure>


<p>You can replace the passwords with whatever you want. Note the passwords for later.</p>

<ol>
<li>This file should be readable only by the user that created it. Change permissions accordingly.</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>chmod 600 .pgpass</span></code></pre></td></tr></table></div></figure>


<ol>
<li>You now need to allow users to login to the database server from the server itself. Open the <code>/var/lib/pgsql/9.2/data/pg_hba.conf</code> and change all methods to <code>md5</code> like so:</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># TYPE  DATABASE        USER            ADDRESS                 METHOD
</span><span class='line'>
</span><span class='line'># "local" is for Unix domain socket connections only
</span><span class='line'>local   all             all                                     md5
</span><span class='line'># IPv4 local connections:
</span><span class='line'>host    all             all             127.0.0.1/32            md5
</span><span class='line'># IPv6 local connections:
</span><span class='line'>host    all             all             ::1/128                 md5</span></code></pre></td></tr></table></div></figure>


<p>This will enable login from Localhost only. If you need remote access, only allow the specific IP addresses or subnets that you need. Security is good.</p>

<ol>
<li>Reload the postgres service to bring in the changes</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>service postgresql-9.2 reload</span></code></pre></td></tr></table></div></figure>


<ol>
<li>Create admin and client accounts for STARRS.</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@starrs-test ~]# psql -h localhost -U postgres
</span><span class='line'>psql (9.2.4)
</span><span class='line'>Type "help" for help.
</span><span class='line'>
</span><span class='line'>postgres=# create user starrs_admin with password 'adminpass';
</span><span class='line'>CREATE ROLE
</span><span class='line'>postgres=# create user starrs_client with password 'clientpass';
</span><span class='line'>CREATE ROLE
</span><span class='line'>postgres=# \q
</span><span class='line'>[root@starrs-test ~]#</span></code></pre></td></tr></table></div></figure>


<ol>
<li>Verify that you can log into the database server without being prompted for a password.</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@starrs-test ~]# psql -h localhost -U postgres
</span><span class='line'>psql (9.2.4)
</span><span class='line'>Type "help" for help.
</span><span class='line'>
</span><span class='line'>postgres=# \q
</span><span class='line'>
</span><span class='line'>[root@starrs-test ~]#</span></code></pre></td></tr></table></div></figure>


<p>If you get prompted for a password, <b>STOP!</b> You need to have this working in order to proceed. Make sure you typed everything in the file correctly and its permissions are set.</p>

<h2>Dependencies</h2>

<p>STARRS has many other software dependencies in order to function. These are mostly Perl modules that extend the capabilities of the language. These modules are (CPAN and package are provided however not all packages may be available):</p>

<ul>
<li>Net::IP (perl-Net-IP)</li>
<li>Net::LDAP (perl-LDAP)</li>
<li>Net::DNS (perl-Net-DNS)</li>
<li>Net::SNMP (perl-Net-SNMP)</li>
<li>Net::SMTP (perl-Mail-Sender)</li>
<li>Crypt::DES (perl-Crypt-DES)</li>
<li>VMware::vCloud</li>
<li>Data::Validate::Domain</li>
</ul>


<p>NOTE: The first time you run CPAN you will be asked some basic setup questions. Answering the defaults are fine for most installations.</p>

<ol>
<li>Install each of these modules. Some of them are available as packages in yum.</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>yum install perl-Net-IP perl-LDAP perl-Net-DNS perl-Mail-Sender perl-Net-SNMP perl-Crypt-DES -y
</span><span class='line'>cpan -i Data::Validate::Domain
</span><span class='line'>cpan -i VMware::vCloud</span></code></pre></td></tr></table></div></figure>


<h2>Download/Configure STARRS</h2>

<p>STARRS comes in two parts: The backend (database) and the Web interface. Each one is stored in it&#8217;s own repository on Github. You will need to download both in order to use the application. Right now we will focus on the backend.</p>

<ol>
<li>You will need a directory to store the downloaded repos in. I recommend using <code>/opt</code>. Clone (download) the current versions of the repositories using Git into that directory.</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@starrs-test ~]# cd /opt/
</span><span class='line'>[root@starrs-test opt]# git clone https://github.com/cohoe/starrs -q
</span><span class='line'>[root@starrs-test opt]# ls
</span><span class='line'>starrs
</span><span class='line'>[root@starrs-test opt]#</span></code></pre></td></tr></table></div></figure>


<ol>
<li>Open the installer file at <code>/opt/starrs/Setup/Installer.pl</code>. You will need to edit the values in the Settings section of the file to match your specific installation. Example:</li>
</ol>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='perl'><span class='line'><span class="c1"># Settings</span>
</span><span class='line'><span class="k">my</span> <span class="nv">$dbsuperuser</span> <span class="o">=</span> <span class="s">&quot;postgres&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">my</span> <span class="nv">$dbadminuser</span> <span class="o">=</span> <span class="s">&quot;starrs_admin&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">my</span> <span class="nv">$dbadminpass</span> <span class="o">=</span> <span class="s">&quot;adminpass&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">my</span> <span class="nv">$dbclientuser</span> <span class="o">=</span> <span class="s">&quot;starrs_client&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">my</span> <span class="nv">$dbclientpass</span> <span class="o">=</span> <span class="s">&quot;clientpass&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">my</span> <span class="nv">$sample</span> <span class="o">=</span> <span class="nb">undef</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="k">my</span> <span class="nv">$dbhost</span> <span class="o">=</span> <span class="s">&quot;localhost&quot;</span><span class="p">;</span>
</span><span class='line'><span class="k">my</span> <span class="nv">$dbport</span> <span class="o">=</span> <span class="mi">5432</span><span class="p">;</span>
</span><span class='line'><span class="k">my</span> <span class="nv">$dbname</span> <span class="o">=</span> <span class="s">&quot;starrs&quot;</span><span class="p">;</span>
</span></code></pre></td></tr></table></div></figure>


<p>dbsuperuser is the root postgres account (usually just &#8216;postgres&#8217;).
dbadminuser is the STARRS admin user you created above.
dbclientuser is the STARRS client user you created above.
sample will populate sample data into the database. Set to anything other than <code>undef</code> to enable sample content.</p>

<ol>
<li>Run the install script</li>
</ol>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>perl /opt/starrs/Setup/Installer.pl
</span></code></pre></td></tr></table></div></figure>


<p>A lot of text will flash across the screen. This is expected. If you see errors, then something is wrong and you should revisit the setup instructions.</p>

<p>You can verify that STARRS is functioning by running some simple queries.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>[root@starrs-test starrs]# psql -h localhost -U postgres starrs
</span><span class='line'>psql (9.2.4)
</span><span class='line'>Type &quot;help&quot; for help.
</span><span class='line'>
</span><span class='line'>starrs=# SELECT api.initialize(&#39;root&#39;);
</span><span class='line'>NOTICE:  table &quot;user_privileges&quot; does not exist, skipping
</span><span class='line'>CONTEXT:  SQL statement &quot;DROP TABLE IF EXISTS &quot;user_privileges&quot;&quot;
</span><span class='line'>PL/pgSQL function api.initialize(text) line 19 at SQL statement
</span><span class='line'>    initialize
</span><span class='line'>------------------
</span><span class='line'> Greetings admin!
</span><span class='line'>(1 row)
</span><span class='line'>
</span><span class='line'>starrs=# SELECT * FROM api.get_systems(NULL);
</span><span class='line'> system_name | owner | group | comment | date_created | date_modified | type | os_name | last_modifier | platform_name | asset | datacenter | location
</span><span class='line'>-------------+-------+-------+---------+--------------+---------------+------+---------+---------------+---------------+-------+------------+----------
</span><span class='line'>(0 rows)
</span><span class='line'>
</span><span class='line'>starrs=# \q
</span><span class='line'>[root@starrs-test starrs]#
</span></code></pre></td></tr></table></div></figure>


<p>If you see &#8220;Greetings admin!&#8221; and you can perform the queries without error, then your backend is all set up and is ready for the web interface.</p>

<h3>Apache2/httpd</h3>

<p>The STARRS web interface requires a web server to be installed. Only Apache has been tested. If you have a new system then you might not have Apache (or in RHELish, httpd) installed.</p>

<ol>
<li>If you do not have Apache/httpd installed, install it.</li>
</ol>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>yum install httpd php php-pgsql -y
</span></code></pre></td></tr></table></div></figure>


<ol>
<li><p>Navigate to the <code>/etc/httpd/conf.d</code> directory.</p></li>
<li><p>Remove the <code>welcome.conf</code> that exists there.</p></li>
</ol>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>cd /etc/httpd/conf.d/
</span><span class='line'>rm -rf welcome.conf
</span></code></pre></td></tr></table></div></figure>


<ol>
<li>Enable httpd to start on boot</li>
</ol>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>chkconfig httpd on
</span></code></pre></td></tr></table></div></figure>


<ol>
<li>Start the httpd service. (Warning messages are fine, as long as the service starts you should be fine)</li>
</ol>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>[root@starrs-test ~]# service httpd start
</span><span class='line'>Starting httpd: httpd: apr_sockaddr_info_get() failed for starrs-test.grantcohoe.com
</span><span class='line'>httpd: Could not reliably determine the server&#39;s fully qualified domain name, using 127.0.0.1 for ServerName
</span><span class='line'>                                                           [  OK  ]
</span><span class='line'>[root@starrs-test ~]#
</span></code></pre></td></tr></table></div></figure>


<h3>PHP Configuration</h3>

<p>A minor change to the system PHP configuration allows the use of short tags for cleaner code. This feature must be enabled in the <code>/etc/php.ini</code> file.</p>

<ol>
<li>In the php.ini file, set <code>short_open_tag = on</code></li>
</ol>


<h3>Web Interface</h3>

<p>You will be cloning the starrs-web into the Apache web root directory to simply deployment.</p>

<ol>
<li>Change directory to <code>/var/www/html/</code> and clone the repository. <b>Note the . at the end of the clone command.</b></li>
</ol>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>[root@starrs-test ~]# cd /var/www/html/
</span><span class='line'>[root@starrs-test html]# git clone https://github.com/cohoe/starrs-web -q .
</span></code></pre></td></tr></table></div></figure>


<ol>
<li><p>Copy the <code>application/config/database.php.example</code> to <code>application/config/database.php</code></p></li>
<li><p>Edit the copied/renamed database file and enter your database connection settings. Example:</p></li>
</ol>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="x">$db[&#39;default&#39;][&#39;hostname&#39;] = &#39;localhost&#39;;</span>
</span><span class='line'><span class="x">$db[&#39;default&#39;][&#39;username&#39;] = &#39;starrs_admin&#39;;</span>
</span><span class='line'><span class="x">$db[&#39;default&#39;][&#39;password&#39;] = &#39;adminpass&#39;;</span>
</span><span class='line'><span class="x">$db[&#39;default&#39;][&#39;database&#39;] = &#39;starrs&#39;;</span>
</span></code></pre></td></tr></table></div></figure>


<ol>
<li><p>Copy the <code>application/config/impulse.php.example</code> to <code>application/config/impulse.php</code></p></li>
<li><p>For this web environment, the defaults in this file are fine. In this file you can change which environment variable to get the current user from.</p></li>
<li><p>Apache needs to be given some special instructions to serve up the application correctly. Create a file at <code>/etc/httpd/conf.d/starrs.conf</code> with the following contents:</p></li>
</ol>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="x">&lt;Directory &quot;/var/www/html&quot;&gt;</span>
</span><span class='line'><span class="x">        AllowOverride all</span>
</span><span class='line'><span class="x">        AuthType basic</span>
</span><span class='line'><span class="x">        AuthName &quot;STARRS Sample Auth (root:admin)&quot;</span>
</span><span class='line'><span class="x">        AuthBasicProvider file</span>
</span><span class='line'><span class="x">        AuthUserFile    &quot;/etc/httpd/conf.d/starrs-auth.db&quot;</span>
</span><span class='line'><span class="x">        require valid-user</span>
</span><span class='line'><span class="x">&lt;/Directory&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<ol>
<li>Since we reference an authenication database, you will need to create this file (<code>starrs-auth.db</code>).</li>
</ol>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="x">htpasswd -b -c /etc/httpd/conf.d/starrs-auth.db root admin</span>
</span></code></pre></td></tr></table></div></figure>


<ol>
<li>Restart Apache to apply the changes. (A reload is not sufficient enough)</li>
</ol>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="x">service httpd restart</span>
</span></code></pre></td></tr></table></div></figure>


<h1>Testing</h1>

<p>At this point you should have a fully functioning STARRS installation. Navigate to your server in a web browser and you should be prompted for login credentials. As we established in the authentication database file, the username is root and the password is admin. If you get the STARRS main page, then success! Otherwise start looking through log files to figure out what is wrong.</p>

<p>Detailed troubleshooting is out of the scope of this guide. System Administrator cleverness is a rare skill, but is the most useful thing when trying to figure out what happened. Shoot me an email if you really feel something is wrong.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Backups for Photo Majors]]></title>
    <link href="http://www.grantcohoe.com/blog/2013/04/19/backups-for-photo-majors/"/>
    <updated>2013-04-19T22:38:00-04:00</updated>
    <id>http://www.grantcohoe.com/blog/2013/04/19/backups-for-photo-majors</id>
    <content type="html"><![CDATA[<p>Data backups are something every single person should do. This presentation is with specific regard to non-technical users who want a little bit of information and some suggestions on what to do.</p>

<p>This presentation was never given explicitly, but it was used for a Public Speaking class.</p>

<p><a href="https://docs.google.com/presentation/d/1KrbMAtqd_ZyigKV7VY26oJvudbnKTz9vMYqHEB8pkRo/edit?usp=sharing">Slides on Google Drive</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Impact of Disk Alignment in Virtualized Environments]]></title>
    <link href="http://www.grantcohoe.com/blog/2013/04/19/impact-of-disk-alignment-in-virtualized-environments/"/>
    <updated>2013-04-19T22:35:00-04:00</updated>
    <id>http://www.grantcohoe.com/blog/2013/04/19/impact-of-disk-alignment-in-virtualized-environments</id>
    <content type="html"><![CDATA[<p>This presentation discusses the impact of disk alignment with specific regard to virtual environments. Performance can be greatly hurt by misaligned partitions both on the VM and host and all layers in between.</p>

<p>Presented at <a href="http://barcamproc.org">Barcamp Rochester</a> in Spring 2013</p>

<p><a href="http://archive.grantcohoe.com/presentations/alignment.pptx">Slides Here</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CSH Wireless Network Deployment]]></title>
    <link href="http://www.grantcohoe.com/blog/2013/04/12/csh-wireless-network-deployment/"/>
    <updated>2013-04-12T17:58:00-04:00</updated>
    <id>http://www.grantcohoe.com/blog/2013/04/12/csh-wireless-network-deployment</id>
    <content type="html"><![CDATA[<p>We wanted to deploy our own wireless network across the floor. I decided to make the project happen.</p>

<h1>Requirements</h1>

<h2>Spectrum Use</h2>

<p><strong>We can only use three channels in the 5 GHz spectrum.</strong> RIT has a massive unified wireless deployment across all of campus. Policy states that third-parties (students, staff, etc) cannot operate wireless access points within range of the RIT network to prevent signal overlap and interference. This is not an issue in the 5 GHz spectrum, where there are many more non-overlaping channels. This limits potential clients to only those with dual-band wireless radios.</p>

<h2>Authentication</h2>

<p><strong>No client-side software can be required.</strong> This is a requirement set by us to allow ease of access by users. Most operating systems support PEAP/MsCHAPv2 (via RADIUS) out of the box and require no extra configuration to make them work. Unfortunately this requires a bit more system infrastructure to make it work. Our authentication backend (MIT Kerberos) does not support this type of user authentication so we need to do some hax to make it.</p>

<h2>Speed</h2>

<p><strong>We need to be faster than RIT.</strong> There is absolutely no reason to use CSH wireless over RITs unless we can be faster. By using Channel Bonding in two key areas, we can achieve this requirement and double the speed of RIT wireless. We also need to be able to do fast-reassociation between access points so that users can walk up and down floor and not lose connectivity.</p>

<h1>Setup</h1>

<h2>Access Points</h2>

<p>First we had to figure out where and how to deploy our range of APs. Since we have relatively few resources we used a combination of what we had lying around, purchased, and donated harware.</p>

<ul>
<li>3x Cisco 1230</li>
<li>1x Cisco 1142</li>
<li>1x Cisco 1131</li>
<li>1x Cisco 1252</li>
</ul>


<p>Looking at the map of the floor, I wanted to place the channel-bonded APs in the areas with the largest concentration of users (the Lounge and the User Center). The others would be dispersed across the other public rooms on floor.</p>

<p>[[ IMAGE HERE ]]</p>

<h2>Wireless Domain Services</h2>

<p>Cisco WDS is essentially a poor-mans controller. WDS allows you to do authentication once across your wireless domain and do relatively seamless handoff between access points. I had an extra 1230 laying around without antennas so I parked it in my server room and configured it to act as the WDS master. When a client attempts to authenticate to an AP, the auth data is sent to the WDS server where it is then processed and a response sent to the AP to let them in or not. If the client roams to another AP then the WDS server promises the new AP that the client is OK and skips the authentication phase.</p>

<p>This is the only device that will ever talk to the RADIUS server, so all of the configuration for that is only needed once.</p>

<p>NOTE: In this example the WDS server is at IP address 192.168.0.250 and the RADIUS server is at 192.168.0.100.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>aaa new-model
</span><span class='line'>!
</span><span class='line'>!
</span><span class='line'>aaa group server radius rad_local
</span><span class='line'> server 192.168.0.250 auth-port 1812 acct-port 1813
</span><span class='line'>!
</span><span class='line'>aaa group server radius rad_eap
</span><span class='line'> server 192.168.0.100 auth-port 1812 acct-port 1813
</span><span class='line'>!
</span><span class='line'>aaa authentication login eap_local group rad_local
</span><span class='line'>aaa authentication login eap_methods group rad_eap
</span><span class='line'>!
</span><span class='line'>radius-server local
</span><span class='line'>  no authentication mac
</span><span class='line'>  nas 192.168.0.250 key 7 SUPERSECRETKEYHERE 
</span><span class='line'>  user wds-authman nthash 7 AUTHMANPASS 
</span><span class='line'>!
</span><span class='line'>radius-server host 192.168.0.250 auth-port 1812 acct-port 1813 key 7 SUPERSECRETRADIUSKEYHERE 
</span><span class='line'>radius-server host 192.168.0.100 auth-port 1812 acct-port 1813 key 7 SUPERSECRETRADIUSOTHERKEYHERE 
</span><span class='line'>!
</span><span class='line'>!
</span><span class='line'>wlccp ap username wds-authman password 7 AUTHMANPASS 
</span><span class='line'>wlccp authentication-server infrastructure eap_local
</span><span class='line'>wlccp authentication-server client eap eap_methods
</span><span class='line'>  ssid prettyflyforawifi
</span><span class='line'>wlccp authentication-server client leap eap_local
</span><span class='line'>  ssid prettyflyforawifi
</span><span class='line'>wlccp wds mode wds-only
</span><span class='line'>wlccp wds priority 255 interface BVI1</span></code></pre></td></tr></table></div></figure>


<p>The access points need to use the AP username defined above to talk to the WDS server. RADIUS configuration here should be optional.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>aaa new-model
</span><span class='line'>!
</span><span class='line'>aaa group server radius rad_eap
</span><span class='line'> server 192.168.0.100 auth-port 1812 acct-port 1813
</span><span class='line'>!
</span><span class='line'>aaa authentication login default local
</span><span class='line'>aaa authentication login eap_methods group rad_eap
</span><span class='line'>dot11 ssid prettyflyforawifi 
</span><span class='line'>   authentication open eap eap_methods
</span><span class='line'>   authentication network-eap eap_methods
</span><span class='line'>   authentication key-management wpa
</span><span class='line'>   guest-mode
</span><span class='line'>!
</span><span class='line'>radius-server host 192.168.0.100 auth-port 1812 acct-port 1813 key 7 SUPERSECRETRADIUSKEY 
</span><span class='line'>!
</span><span class='line'>wlccp ap username wds-authman password 7 AUTHMANPASS 
</span><span class='line'>wlccp ap wds ip address 192.168.0.250</span></code></pre></td></tr></table></div></figure>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Cross-Platform Authentication Services]]></title>
    <link href="http://www.grantcohoe.com/blog/2013/02/27/cross-platform-authentication-services/"/>
    <updated>2013-02-27T22:47:00-05:00</updated>
    <id>http://www.grantcohoe.com/blog/2013/02/27/cross-platform-authentication-services</id>
    <content type="html"><![CDATA[<p>You are a nerd. You like doing nerd-y things. You run an entirely *nix-based network. But like all nerds, you have that one pesky Windows machine that you want to have available for your users. Or you just want the same SSO password from your Kerberos KDC. Regardless, you want Windows to talk to MIT Kerberos. Believe it or not, this is SUPPORTED!</p>

<h2>Process Overview</h2>

<p><img src="http://www.grantcohoe.com/images/blog/cross-auth-process.png" alt="" title=""  /></p>

<br>


<p>We start with the user entering their credentials. These are entered in the standard Windows logon screen (which I dearly miss from Windows 2003). From there, the client is configured to have it&#8217;s default domain (realm in this case) to be the MIT Kerberos realm that your machine is a member of. This would be the equivalent of an Active Directory domain.</p>

<p>From here, your workstation acts just like any other Kerberized host. It uses it&#8217;s host principal (derived from what it thinks its hostname is) and configured password to authenticate to the KDC. Once it has verified it&#8217;s identity, it then goes to authenticate you. And if your password is correct, Windows lets you in!</p>

<p>The question is: who does it let you in as? A Kerberos principal is nothing more than a name. It is not an account, or any object that actually contains information for the system. You must map Kerberos principals to accounts. These accounts are created in Windows as either local users or via Active Directory (a whole other can of worms). Usually, you will want to create a one-to-one mapping between principal and account (<code>grant@GRANTCOHOE.COM</code> principal = Windows account &#8220;grant&#8221;).</p>

<h2>KDC Setup</h2>

<p>On your KDC, open up <code>kadmin</code> with your administrative principal and create a host principal for the new machine. It needs to have a password that you know, so use your favorite password generating source.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>miranda ~ # kadmin -p cohoe/admin
</span><span class='line'>Authenticating as principal cohoe/admin with password.
</span><span class='line'>Password for cohoe/admin@GRANTCOHOE.COM:
</span><span class='line'>kadmin:  ank host/caprica.grantcohoe.com@GRANTCOHOE.COM
</span><span class='line'>WARNING: no policy specified for host/caprica.grantcohoe.com@GRANTCOHOE.COM; defaulting to no policy
</span><span class='line'>Enter password for principal "host/caprica.grantcohoe.com@GRANTCOHOE.COM":
</span><span class='line'>Re-enter password for principal "host/caprica.grantcohoe.com@GRANTCOHOE.COM":
</span><span class='line'>Principal "host/caprica.grantcohoe.com@GRANTCOHOE.COM" created.
</span><span class='line'>kadmin:  quit
</span><span class='line'>miranda ~ #</span></code></pre></td></tr></table></div></figure>


<p>That&#8217;s it for the KDC. On to the Windows machine!</p>

<h2>Windows 7 Client</h2>

<p>Windows 7 (as well as Server 2008 I believe) include the basic utilities required to support MIT Kerberos. This was available for XP and Server 2003 as &#8220;Microsoft Support Tools&#8221;. The utility we will be using is called <code>ksetup</code>. It allows for configuration of foreign-realm authentication systems.</p>

<p>So to set your machine to authenticate to your already existing MIT Kerberos KDC, open up a command prompt and do the following:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>ksetup /setdomain GRANTCOHOE.COM
</span><span class='line'>ksetup /addkdc GRANTCOHOE.COM kerberos.grantcohoe.com
</span><span class='line'>ksetup /setmachpassword passwordfromearlier
</span><span class='line'>ksetup /mapuser * *</span></code></pre></td></tr></table></div></figure>


<p>After that, you need to set a Group Policy setting to automatically pick the right domain for you to login to. Open up the Group Policy Editor (gpedit.msc) and navigate to Local Computer Policy->Computer Configuration->Administrative Templates->System->Login->Assign a default domain for logon. Set this to your realm (GRANTCOHOE.COM in my case).</p>

<p>Do a nice reboot of your system, and you should be ready to go!</p>

<h2>Active Directory</h2>

<p>Active Directory can be configured to trust a foreign Kerberos realm. It will NOT synchronize information with anything, but if you just need a bunch of users to log into something and no data with it, the process is not too terrible. Rather than duplicate the information, you can find the guide that I used here: <a href="http://pig.made-it.com/kerberos-trust.html">Microsoft trusting MIT Kerberos</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Stanford Webauth on Enterprise Linux]]></title>
    <link href="http://www.grantcohoe.com/blog/2013/02/13/stanford-webauth-on-enterprise-linux/"/>
    <updated>2013-02-13T12:38:00-05:00</updated>
    <id>http://www.grantcohoe.com/blog/2013/02/13/stanford-webauth-on-enterprise-linux</id>
    <content type="html"><![CDATA[<h2>Background</h2>

<p>Lets say you are in a domain, and you wish to access several different web services. How often do you find you have to enter the same username and password over and over again to get to each website? Wouldn&#8217;t it be nice if you could just enter it once and automagically have access to all the web services you need? Well guess what? You can!</p>

<p>It all works off of MIT Kerberos. Kerberos is a mechanism that centralizes your authentication to one service and allows for Single Sign-On. The concept of SSO is fairly simple: Enter your credentials once and that&#8217;s it. It save you from typing them over and over again and protects against certain attacks.</p>

<p>WebAuth was developed at Stanford University and brings &#8220;kerberization&#8221; to web services. All you need is some modules, a KDC, and a webserver.</p>

<p>In this guide, we will be utilizing the Kerberos realm/domain name of EXAMPLE.COM. We will also be using two servers:</p>

<ul>
<li>gmcsrvx2.example.com: The Webauth WebKDC</li>
<li>gmcsrvx3.example.com: A secondary web server</li>
<li>webauth.example.com: A DNS CNAME to gmcsrvx2.example.com</li>
</ul>


<p>Note that you will need a pre-existing Kerberos KDC in your network.</p>

<p>There are three components of the WebAuth system. WebAuth typically refers to the component that provides authorized access to certain content. The WebKDC is the process that handles communication with the Kerberos KDC and distributes tickets out to the client machines. The WebLogin pages are the login/logoff/password change pages that are presented to the user to enter their credentials. Certain binary packages provided by Stanford do not contain components of the WebAuth system. This is why we are going to build it from source.</p>

<h2>Server Setup</h2>

<h3>Packages</h3>

<p>Each machine you plan to install WebAuth on needs the following packages:</p>

<ul>
<li>httpd-devel</li>
<li>krb5-devel</li>
<li>curl-devel</li>
<li>mod_ssl</li>
<li>mod_fcgid</li>
<li>perl-FCGI</li>
<li>perl-Template-Toolkit</li>
<li>perl-Crypt-SSLeay</li>
<li>cpan</li>
</ul>


<p>Enterprise Linux does not include several required Perl modules for this to work. You are going to need to install them via CPAN. If you have never run CPAN before, do it once just to get the preliminary setup working.</p>

<ul>
<li>CGI::Application::Plugin::TT</li>
<li>CGI::Application::Plugin::AutoRunmode</li>
<li>CGI::Application::Plugin::Forward</li>
<li>CGI::Application::Plugin::Redirect</li>
</ul>


<p>You also need Remctl, an interface to Kerberos. For EL6 we are using remctl 2.11 available from the Fedora 15 repositories.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>wget http://mirror.rit.edu/fedora/linux/releases/15/Everything/i386/os/Packages/remctl-2.11-12.fc15.i686.rpm
</span><span class='line'>wget http://mirror.rit.edu/fedora/linux/releases/15/Everything/i386/os/Packages/remctl-devel-2.11-12.fc15.i686.rpm
</span><span class='line'>yum localinstall remctl*</span></code></pre></td></tr></table></div></figure>


<h3>Firewall</h3>

<p>Open up ports 80 (HTTP) and 443 (HTTPS) since we will be doing web stuff.</p>

<h3>NTP</h3>

<p>Since you will be doing Kerberos stuff, you need a synchronized clock. If you do not know how to do this, see my guide on <a href="http://www.grantcohoe.com/guides/system/ntp">Setting up NTP</a>.</p>

<h3>Kerberos</h3>

<p>Your machine needs to be a Kerberos client (meaning valid DNS, krb5.conf, and host prinicpal in its /etc/krb5.keytab). We will be using three keytabs for this application:</p>

<h4>/etc/krb5.keytab</h4>

<ul>
<li>host/gmcsrvx2.example.com@EXAMPLE.COM</li>

<h4>/etc/webauth/webauth.keytab</h4></li>
<li>webauth/gmcsrvx2.example.com@EXAMPLE.COM</li>

<h4>/etc/webkdc/webkdc.keytab</h4></li>
<li>service/webkdc@EXAMPLE.COM</li>
NOTE: If you wrote these in your home directory and cp&#8217;d them into their respective paths, check your SELinux contexts.</li>
</ul>


<h3>SSL Certificates</h3>

<p>You need an SSL certificate matching the hostname of each server (gmcsrvx2.example.com, gmcsrvx3.example.com, webauth.example.com) avaiable for your Apache configuration.</p>

<p><em>IMPORTANT</em>:You also need to ensure that your CA is trusted by Curl (the system). If in doubt, cat your CA cert into <code>/etc/pki/tls/certs/ca-bundle.crt</code>. You will get really odd errors if you do not do this.</p>

<h3>Shared Libraries</h3>

<p>We will be installing WebAuth into <code>/usr/local</code> and this need its libraries to be linked in the system.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>echo '/usr/local/lib' &gt;&gt; /etc/ld.so.conf.d/locallib.conf</span></code></pre></td></tr></table></div></figure>


<p>We will need to run <code>ldconfig</code> to load in the WebAuth libraries later on.</p>

<h2>Compile and Install WebAuth</h2>

<p>The latest version at the time of this writing is webauth-4.1.1 and is avaiable from <a href="http://webauth.stanford.edu/download.html">Stanford University</a>. Grab the source tarball since the packages do not include features that you will need in a brand new installation.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@gmcsrvx2 ~]# tar xfz webauth-4.1.1.tar.gz
</span><span class='line'>[root@gmcsrvx2 ~]# cd webauth-4.1.1
</span><span class='line'>[root@gmcsrvx2 webauth-4.1.1]# ./configure --enable-webkdc
</span><span class='line'>checking for a BSD-compatible install... /usr/bin/install -c
</span><span class='line'>checking whether build environment is sane... yes
</span><span class='line'>checking for a thread-safe mkdir -p... /bin/mkdir -p
</span><span class='line'>....
</span><span class='line'>....
</span><span class='line'>config.status: executing depfiles commands
</span><span class='line'>config.status: executing libtool commands
</span><span class='line'>config.status: executing include/webauth/defines.h commands
</span><span class='line'>[root@gmcsrvx2 webauth-4.1.1]# </span></code></pre></td></tr></table></div></figure>


<p>Assuming everything is all good, go ahead and build it.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@gmcsrvx2 webauth-4.1.1]# make
</span><span class='line'>make  all-am
</span><span class='line'>make[1]: Entering directory `/root/webauth-4.1.1'
</span><span class='line'>....
</span><span class='line'>....
</span><span class='line'>Manifying blib/man3/WebKDC::WebKDCException.3pm
</span><span class='line'>make[2]: Leaving directory `/root/webauth-4.1.1/perl'
</span><span class='line'>make[1]: Leaving directory `/root/webauth-4.1.1'
</span><span class='line'>[root@gmcsrvx2 webauth-4.1.1]# </span></code></pre></td></tr></table></div></figure>


<p>And assuming everything is happy, make install:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@gmcsrvx2 webauth-4.1.1]# make install
</span><span class='line'>make[1]: Entering directory `/root/webauth-4.1.1'
</span><span class='line'>test -z "/usr/local/lib" || /bin/mkdir -p "/usr/local/lib"
</span><span class='line'>....
</span><span class='line'>....
</span><span class='line'>test -z "/usr/local/include/webauth" || /bin/mkdir -p "/usr/local/include/webauth"
</span><span class='line'> /usr/bin/install -c -m 644 include/webauth/basic.h include/webauth/keys.h include/webauth/tokens.h include/webauth/util.h include/webauth/webkdc.h '/usr/local/include/webauth'
</span><span class='line'>make[1]: Leaving directory `/root/webauth-4.1.1'
</span><span class='line'>[root@gmcsrvx2 webauth-4.1.1]# </span></code></pre></td></tr></table></div></figure>


<p>Now ensure that the new libraries get loaded by running <code>ldconfig</code>. This looks at the files in that ld.so.conf.d directory and adds them to the library path. MAKE SURE YOU DO THIS!!!</p>

<p>The Apache modules for WebAuth have been compiled into <code>/usr/local/libexec/apache2/modules</code>:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@gmcsrvx2 ~]# ls /usr/local/libexec/apache2/modules/
</span><span class='line'>mod_webauth.la  mod_webauthldap.la  mod_webauthldap.so  mod_webauth.so  mod_webkdc.la  mod_webkdc.so</span></code></pre></td></tr></table></div></figure>


<h2>mod_webauth Configuration</h2>

<p>Make sure you have the proper keytab set up at <code>/etc/webauth/webauth.keytab</code>. This file can technically be located anywhere as long as you configure the module accordingly.</p>

<p>Next you need to create a local state directory for WebAuth. Usually this is <code>/var/lib/webauth</code>. The path can be changed as long as you set it in the following configuration file.</p>

<p>The Apache module needs a configuration file to be included in the Apache server configuration. On Enterprise Linux, this can be located in <code>/etc/httpd/conf.d/mod_webauth.conf</code>:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># Load the module that you compiled.
</span><span class='line'>LoadModule webauth_module     /usr/local/libexec/apache2/modules/mod_webauth.so
</span><span class='line'>
</span><span class='line'># Some fancy WebAuth stuff
</span><span class='line'>WebAuthKeyRingAutoUpdate      on
</span><span class='line'>WebAuthKeyringKeyLifetime     30d
</span><span class='line'>
</span><span class='line'># The path to some critical files. These should be secured. 
</span><span class='line'>WebAuthKeyring                /var/lib/webauth/keyring
</span><span class='line'>WebAuthServiceTokenCache      /var/lib/webauth/service_token_cache
</span><span class='line'>WebAuthCredCacheDir           /var/lib/webauth/cred_cache
</span><span class='line'>
</span><span class='line'># The path to the keytab that webauth will use to authenticate with your KDC
</span><span class='line'>WebAuthKeytab                 /etc/webauth/webauth.keytab
</span><span class='line'>
</span><span class='line'># The URL to point to if you need to login. MAKE SURE THIS IS CORRECT!
</span><span class='line'>WebAuthLoginURL               "https://webauth.example.com/login"
</span><span class='line'>WebAuthWebKdcURL              "https://webauth.example.com/webkdc-service/"
</span><span class='line'>
</span><span class='line'># The Kerberos principal to use when authenticating with the keytab above
</span><span class='line'>WebAuthWebKdcPrincipal        service/webkdc
</span><span class='line'>
</span><span class='line'># SSL is a good thing. Plaintext passwords are bad. Secure this server.
</span><span class='line'>WebAuthSSLRedirect            On
</span><span class='line'>WebAuthWebKdcSSLCertFile      /etc/pki/example.com/example-ca.crt</span></code></pre></td></tr></table></div></figure>


<p>Again, adjust paths to suit your tastes. The <code>WebAuthWebKdcSSLCertFile</code> should be your public CA certificate that you probably cat&#8217;d earlier.</p>

<h2>mod_webkdc Configuration</h2>

<p>Make sure you have the proper keytab set up at <code>/etc/webkdc/webkdc.keytab</code>. This file can technically be located anywhere as long as you configure the module accordingly.</p>

<p>Next you need to create a local state directory for the WebKDC. Usually this is <code>/var/lib/webkdc</code>. The path can be changed as long as you set it in the configuration files.</p>

<p>The WebKDC utilizes an ACL to allow only certain hosts to get tickets. This goes in <code>/etc/webkdc/token.acl</code>:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># These lines allow all principals that under the webauth service to generate a token
</span><span class='line'>krb5:webauth/*@EXAMPLE.COM id
</span><span class='line'>krb5:webauth/gmcsrvx2.example.com@EXAMPLE.COM cred krb5 krbtgt/EXAMPLE.COM@EXAMPLE.COM</span></code></pre></td></tr></table></div></figure>


<p>For the WebLogin pages, another configuration file is used to specify the information for it (in <code>/etc/webkdc/webkdc.conf</code>). This is seperate from the Apache module configuration loaded by the webserver.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='perl'><span class='line'><span class="c1"># The KEYRING_PATH should match what you put in your httpd config</span>
</span><span class='line'><span class="nv">$KEYRING_PATH</span> <span class="o">=</span> <span class="s">&quot;/var/lib/webkdc/keyring&quot;</span><span class="p">;</span>
</span><span class='line'><span class="nv">$URL</span> <span class="o">=</span> <span class="s">&quot;https://webauth.example.com/webkdc-service/&quot;</span><span class="p">;</span>
</span><span class='line'><span class="c1"># You can make custom skins for the weblogin page. Change the path here</span>
</span><span class='line'><span class="nv">$TEMPLATE_PATH</span> <span class="o">=</span> <span class="s">&quot;./generic/templates&quot;</span><span class="p">;</span>
</span></code></pre></td></tr></table></div></figure>


<p>NOTE: You CANNOT change the location of this file or the WebKDC module will freak out.</p>

<p>Note that certain directives must match the Apache configuration. We will make that now in <code>/etc/httpd/conf.d/mod_webkdc.conf</code>:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'># Load the module that you compiled.
</span><span class='line'>LoadModule webkdc_module /usr/local/libexec/apache2/modules/mod_webkdc.so
</span><span class='line'>
</span><span class='line'># Some fancy WebKdc stuff
</span><span class='line'>WebKdcServiceTokenLifetime    30d
</span><span class='line'>
</span><span class='line'># The path to some critical files. These should be secured.
</span><span class='line'>WebKdcKeyring                 /var/lib/webkdc/keyring
</span><span class='line'>
</span><span class='line'># The path to the keytab and access control list that the webkdc will use to authenticate with your KDC
</span><span class='line'>WebKdcKeytab                  /etc/webkdc/webkdc.keytab
</span><span class='line'>WebKdcTokenAcl                /etc/webkdc/token.acl
</span><span class='line'>
</span><span class='line'># Debugging information is wonderful. Turn this off when you get everything working.
</span><span class='line'>WebKdcDebug                   On
</span></code></pre></td></tr></table></div></figure>


<p>Ensure that your paths match what you set up earlier.</p>

<h2>mod_webauthldap Configuration</h2>

<p>This step should only be done if you have an LDAP server operating in your network and can accept SASL binds. You can make certain LDAP attributes available in the web environment as server variables for your web applications. This is configured in <code>/etc/httpd/conf.d/mod_webauthldap.conf</code>:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'># Load the module that you compiled
</span><span class='line'>LoadModule webauthldap_module /usr/local/libexec/apache2/modules/mod_webauthldap.so
</span><span class='line'>
</span><span class='line'># Webauth Keytab &amp; credential cache file
</span><span class='line'>WebAuthLdapKeytab /etc/webauth/webauth.keytab
</span><span class='line'>WebAuthLdapTktCache /var/lib/webauth/krb5cc_ldap
</span><span class='line'>
</span><span class='line'># LDAP Host Information
</span><span class='line'>WebAuthLdapHost ldap.example.com
</span><span class='line'>WebAuthLdapBase ou=users,dc=example,dc=com
</span><span class='line'>WebAuthLdapAuthorizationAttribute privilegeAttribute
</span><span class='line'>WebAuthLdapDebug on
</span><span class='line'>
</span><span class='line'>&lt;Location /&gt;
</span><span class='line'>        WebAuthLdapAttribute givenName
</span><span class='line'>        WebAuthLdapAttribute sn
</span><span class='line'>        WebAuthLdapAttribute cn
</span><span class='line'>        WebAuthLdapAttribute mail
</span><span class='line'>&lt;/Location&gt;
</span></code></pre></td></tr></table></div></figure>


<h2>Misc Permissions</h2>

<p>Most of the files that you created do not have the appropriate permissions to be read/written by the webserver. Lets fix that.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>[root@gmcsrvx2 ~ ]# chcon -t bin_t /usr/local/share/weblogin/*.fcgi
</span><span class='line'>[root@gmcsrvx2 ~ ]# chown -R apache:apache /usr/local/share/weblogin
</span><span class='line'>[root@gmcsrvx2 ~ ]# chcon -R -t httpd_sys_rw_content_t /usr/local/share/weblogin/generic
</span><span class='line'>[root@gmcsrvx2 ~ ]# chown root:apache /etc/webkdc/webkdc.keytab
</span><span class='line'>[root@gmcsrvx2 ~ ]# chmod 640 /etc/webkdc/webkdc.keytab
</span><span class='line'>[root@gmcsrvx2 ~ ]# chown root:apache /etc/webauth/webauth.keytab
</span><span class='line'>[root@gmcsrvx2 ~ ]# chmod 640 /etc/webauth/webauth.keytab
</span><span class='line'>[root@gmcsrvx2 ~ ]# chown -R apache:apache /var/lib/webkdc
</span><span class='line'>[root@gmcsrvx2 ~ ]# chown -R apache:apache /var/lib/webauth
</span><span class='line'>[root@gmcsrvx2 ~ ]# chmod 700 /var/lib/webkdc
</span><span class='line'>[root@gmcsrvx2 ~ ]# chmod 700 /var/lib/webauth
</span></code></pre></td></tr></table></div></figure>


<h2>Apache VHosts</h2>

<p>I created a VHost for both &#8220;webauth.example.com&#8221; and &#8220;gmcsrvx2.example.com&#8221;, with the latter requiring user authentication to view. I name these after the hostname they are serving in <code>/etc/httpd/conf.d/webauth.conf</code>, Just throw a simple Hello World into the DocumentRoot that you configure for your testing host. Note that you must have NameVirtualHost-ing setup for both ports 80 and 443.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>&lt;VirtualHost *:80&gt;
</span><span class='line'>  ServerName webauth.example.com
</span><span class='line'>  ServerAlias webauth
</span><span class='line'>  # Send them to somewhere useful if they request the root of this VHost
</span><span class='line'>  RedirectMatch   permanent ^/$ https://gmcsrvx2.example.com/
</span><span class='line'>  # Send non-HTTPS traffic to HTTPS since we are dealing with passwords
</span><span class='line'>  RedirectMatch   permanent ^/(.+)$ https://webauth.example.com/$1
</span><span class='line'>&lt;/VirtualHost&gt;
</span><span class='line'>
</span><span class='line'>&lt;VirtualHost *:443&gt;
</span><span class='line'>  # Name to respond to
</span><span class='line'>  ServerName webauth.example.com
</span><span class='line'>  ServerAlias webauth
</span><span class='line'>
</span><span class='line'>  # Root directory
</span><span class='line'>  DocumentRoot /usr/local/share/weblogin
</span><span class='line'>
</span><span class='line'>  # SSL
</span><span class='line'>  SSLEngine On
</span><span class='line'>  SSLCertificateFile /etc/pki/example.com/webauth/host-cert.pem
</span><span class='line'>  SSLCertificateKeyFile /etc/pki/example.com/webauth/host-key.pem
</span><span class='line'>  SSLCACertificateFile /etc/pki/example.com/example-ca.crt
</span><span class='line'>
</span><span class='line'>  # Web Login directory needs some special love
</span><span class='line'>  &lt;Directory &quot;/usr/local/share/weblogin&quot;&gt;
</span><span class='line'>          AllowOverride none
</span><span class='line'>          Options ExecCGI
</span><span class='line'>          AddHandler fcgid-script .fcgi
</span><span class='line'>          Order allow,deny
</span><span class='line'>          Allow from all
</span><span class='line'>  &lt;/Directory&gt;
</span><span class='line'>
</span><span class='line'>  # This allows you to not need to put the file extension on the scripts
</span><span class='line'>  ScriptAlias /login &quot;/usr/local/share/weblogin/login.fcgi&quot;
</span><span class='line'>  ScriptAlias /logout &quot;/usr/local/share/weblogin/logout.fcgi&quot;
</span><span class='line'>  ScriptAlias /pwchange &quot;/usr/local/share/weblogin/pwchange.fcgi&quot;
</span><span class='line'>
</span><span class='line'>  # More special options to make things load right based on your template
</span><span class='line'>  Alias /images &quot;/usr/local/share/weblogin/generic/images&quot;
</span><span class='line'>  Alias /help.html &quot;/usr/local/share/weblogin/generic/help.heml&quot;
</span><span class='line'>  Alias /style.css &quot;/usr/local/share/weblogin/generic/style.css&quot;
</span><span class='line'>
</span><span class='line'>  # This is the actual web KDC
</span><span class='line'>  &lt;Location /webkdc-service&gt;
</span><span class='line'>          SetHandler webkdc
</span><span class='line'>  &lt;/Location&gt;
</span><span class='line'>&lt;/VirtualHost&gt;
</span></code></pre></td></tr></table></div></figure>


<p>And the host file at <code>/etc/httpd/conf.d/gmcsrvx2.conf</code>:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>&lt;VirtualHost *:80&gt;
</span><span class='line'>  ServerName gmcsrvx2.example.com
</span><span class='line'>  ServerAlias gmcsrvx2
</span><span class='line'>  DocumentRoot /var/www/html
</span><span class='line'>  RedirectMatch   permanent ^/(.+)$ https://gmcsrvx2.example.com/$1
</span><span class='line'>&lt;/VirtualHost&gt;
</span><span class='line'>
</span><span class='line'>&lt;VirtualHost *:443&gt;
</span><span class='line'>  ServerName gmcsrvx2.example.com
</span><span class='line'>  ServerAlias gmcsrvx2
</span><span class='line'>  DocumentRoot /var/www/gmcsrvx2
</span><span class='line'>  SSLEngine On
</span><span class='line'>  SSLCertificateFile /etc/pki/example.com/gmcsrvx2/host-cert.pem
</span><span class='line'>  SSLCertificateKeyFile /etc/pki/example.com/gmcsrvx2/host-key.pem
</span><span class='line'>  SSLCACertificateFile /etc/pki/example.com/example-ca.crt
</span><span class='line'>
</span><span class='line'>  # Require a webauth valid user to access this directory
</span><span class='line'>  &lt;Directory &quot;/var/www/gmcsrvx2&quot;&gt;
</span><span class='line'>          AuthType WebAuth
</span><span class='line'>          Require valid-user
</span><span class='line'>  &lt;/Directory&gt;
</span><span class='line'>&lt;/VirtualHost&gt;
</span></code></pre></td></tr></table></div></figure>


<p>Once you are all set, start Apache. Then navigate your web browser to the host (http://gmcsrvx2.example.com). This should first redirect you to HTTPS, then bounce you to the WebLogin pages. After authenticating, you should be able to access the server.</p>

<h2>Conclusion</h2>

<p>This is by no means a simple thing to get set up. An intimate knowlege how how Kerberos, Apache, and LDAP work is crucial to debugging issues relating to WebAuth. All of my sample configuration files can be found in the <a href="http://archive.grantcohoe.com/projects/webauth/">Archive</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[IP over DNS Exploit]]></title>
    <link href="http://www.grantcohoe.com/blog/2013/01/03/ip-over-dns-exploit/"/>
    <updated>2013-01-03T01:21:00-05:00</updated>
    <id>http://www.grantcohoe.com/blog/2013/01/03/ip-over-dns-exploit</id>
    <content type="html"><![CDATA[<h1>The Basics</h1>

<p>First let&#8217;s review how your traffic gets to it&#8217;s destination. You open up your favorite web browser and punch in &#8220;www.google.com&#8221;. Since your computer works with IP addresses, and not names (like people), you need to do a process of resolving the name. The Domain Name System (DNS) is the service that does this. Your ISP runs DNS servers, that are typically given to you in your DHCP lease. Your computer sends a query to this DNS server asking &#8220;what is the IP address of www.google.com&#8221;. Since your ISP does not have control over the &#8220;google.com&#8221; domain, the request is forwarded to another server. Eventually someone says &#8220;Hey! www.google.com is at 72.14.204.104&#8221;. This response is sent back through the servers to your computer.</p>

<p>After resolving the name, your computer now creates a data packet that will be sent to the computer at 72.14.204.104. The packet gets there by looking at your hosts route table and will hit your default gateway.</p>

<h1>The Technology</h1>

<p>IP over DNS is a method of encapsulating IP packets inside a DNS query. This essentially creates a VPN between a server and a client. In my case, I setup and configured the Iodine DNS server on my server located at RIT that I would use to route my traffic to the internet. Inside the tunnel exists the subnet of 192.168.0.0/27, with the server being at 192.168.0.1. My client connected and received IP address 192.168.0.2.</p>

<h1>The Problem</h1>

<p>Certain WLAN installations will include a guest SSID that non-controlled clients can associate to (In this scenario, I will use ExampleGuest, keeping the actual one I used anonymous). Often your traffic will get routed to a captive portal first, requiring you to enter credentials supplied by your organization. Until you do so, none of your traffic will reach it&#8217;s destination outside the LAN&#8230; UNLESS you discover a vulnerability, such as the one we are going to explore.</p>

<p>When I walked into the Example Corp site, I flipped open my trusty laptop and got to work. After associating with the ExampleGuest SSID, I was given the IP address 10.24.50.22/24 with gateway 10.24.50.1. I opened my web browser in attempt to get to &#8220;www.google.com&#8221;, and was immediately directed to the captive portal asking me to log in. Obviously I do not have credentials to this network, so I am at a dead end at this time.</p>

<p>Next I whipped out a terminal session, and did a lookup on &#8220;www.google.com&#8221;. Lo and behold the name was resolved to it&#8217;s external IP address. This means that DNS traffic was being allowed past the captive portal and out onto the network. If &#8220;www.google.com&#8221; resolved to something like &#8220;1.1.1.1&#8221; or an address in the 10.24.0.0/16 space, I know that the captive portal is grabbing all of my traffic. This would be the end of this experiment. However as I saw, this was not the case. External DNS queries were still being answered. Time to do some hacks.</p>

<h1>The Exploit</h1>

<p>Step 1) I need my Iodine client to be able to &#8220;query&#8221; my remote name server. I added a static route to my laptop that forced traffic to my server through the gateway given to me by the DHCP server. (ip route add 129.21.50.104 via 10.24.50.1)</p>

<p>Step 2) I need to establish my IPoDNS tunnel. (iodine -P mypasswordwenthere tunnel.grantcohoe.com) A successful connection gave me the IP address 192.168.0.2. I was then able to ping 192.168.0.1, which is the inside IP address of the tunnel).</p>

<p>Step 3) I need to change my default gateway to the server address inside the tunnel (ip route add default via 192.168.0.1).</p>

<p>And with that, all of my traffic is going to be encapsulated over the IP over DNS tunnel and sent to my server as DNS queries, this giving me unrestricted internet access bypassing the captive portal.</p>

<h1>The Defense</h1>

<p>This entire experiment would grind to a halt if DNS queries were not being handled externally. The network administrator should enable features necessary to either drop DNS requests or answer them with the captive portal IP address.</p>

<h1>The Conclusion</h1>

<p>End result: Unrestricted internet access over a wireless network that I have no credentials to.</p>

<p>Difficulty of setting this up: HIGH
Speed of tunneled internet: SLOW
Worth it for practical use: NOT AT ALL
Worth it for education: A LOT</p>

<p>This sort of trick can work on airplane and hotel wireless systems as well. Most sites do not think to have their captive portals capture DNS traffic in addition to regular IP traffic. As we can see here, it can be used against them.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Dynamic Dual-Home Linux Server]]></title>
    <link href="http://www.grantcohoe.com/blog/2013/01/03/dynamic-dual-home-linux-server/"/>
    <updated>2013-01-03T01:15:00-05:00</updated>
    <id>http://www.grantcohoe.com/blog/2013/01/03/dynamic-dual-home-linux-server</id>
    <content type="html"><![CDATA[<h1>Requirements</h1>

<p>I have a shiny new VM server sitting in my dorm room. I have access to two networks, one operated by my dorm organization and the other provided to me by RIT. Both get me to the internet, but do so through different paths/SLAs. I want my server to be accessible from both networks. I also want to be able to attach VM hosts to NAT&#8217;d networks behind each respective network. This gives me a total of four possible VM networks (primary-external, primary-internal, secondary-external, secondary-internal). I have a Hurricane Electric IPv6 tunnel endpoint configured on the server, and want IPv6 connectivity available on ALL networks regardless of being external or internal. And to complicate matters, my external IP addresses are given to me via DHCP so I cannot set anything statically. Make it so.</p>

<h1>Dependencies</h1>

<ul>
<li>IPTables</li>
<li>EBTables</li>
<li>Kernel 2.6 or newer</li>
<li>IPCalc
You also need access to two networks.</li>
</ul>


<h1>Script Setup</h1>

<p>First, like any good shell script, we should define our command paths:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>SERVICE=/sbin/service
</span><span class='line'>IPTABLES=/sbin/iptables
</span><span class='line'>IP6TABLES=/sbin/ip6tables
</span><span class='line'>EBTABLES=/sbin/ebtables
</span><span class='line'>IPCALC=/bin/ipcalc</span></code></pre></td></tr></table></div></figure>


<p>Next we&#8217;ll define the interface names that we are going to use. These should already be pre-configured and have their appropriate IP information.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>PRIMARY_EXTERNAL_INTERFACE="primary-net"
</span><span class='line'>PRIMARY_INTERNAL_INTERFACE="primary-nat"
</span><span class='line'>SECONDARY_EXTERNAL_INTERFACE="secondary-net"
</span><span class='line'>SECONDARY_INTERNAL_INTERFACE="secondary-nat"
</span><span class='line'>IPV6_TUNNEL_INTERFACE="he-ipv6"</span></code></pre></td></tr></table></div></figure>


<h1>Subnet Information</h1>

<p>Now we need to load in the relevant subnet layouts. In an ideal world this would be set statically. However due to the nature of the environment I am in, both of my networks serve me my address via DHCP and is subject to change. This is very dirty and not very efficient, but it works:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># Here we will get the subnet information for the primary network
</span><span class='line'>PRIMARY_EXTERNAL_NETWORK=`$IPCALC -n $(ip -4 addr show dev $PRIMARY_EXTERNAL_INTERFACE | grep "inet" | cut -d ' ' -f 6) | cut -d = -f 2`
</span><span class='line'>PRIMARY_EXTERNAL_PREFIX=`$IPCALC -p $(ip -4 addr show dev $PRIMARY_EXTERNAL_INTERFACE | grep "inet" | cut -d ' ' -f 6) | cut -d = -f 2`
</span><span class='line'>PRIMARY_EXTERNAL_NETWORK="$PRIMARY_EXTERNAL_NETWORK/$PRIMARY_EXTERNAL_PREFIX"
</span><span class='line'># Then the NAT'd network behind the primary
</span><span class='line'>PRIMARY_INTERNAL_NETWORK=`ip -4 addr show dev $PRIMARY_INTERNAL_INTERFACE | grep "inet" | cut -d ' ' -f 6 | sed "s/[0-9]\+\//0\//"`
</span><span class='line'># Now the subnet information for the secondary network
</span><span class='line'>SECONDARY_EXTERNAL_NETWORK=`$IPCALC -n $(ip -4 addr show dev $SECONDARY_EXTERNAL_INTERFACE | grep "inet" | cut -d ' ' -f 6) | cut -d = -f 2`
</span><span class='line'>SECONDARY_EXTERNAL_PREFIX=`$IPCALC -p $(ip -4 addr show dev $SECONDARY_EXTERNAL_INTERFACE | grep "inet" | cut -d ' ' -f 6) | cut -d = -f 2`
</span><span class='line'>SECONDARY_EXTERNAL_NETWORK="$SECONDARY_EXTERNAL_NETWORK/$SECONDARY_EXTERNAL_PREFIX"
</span><span class='line'># And it's NAT'd network.
</span><span class='line'>SECONDARY_INTERNAL_NETWORK=`ip -4 addr show dev $SECONDARY_INTERNAL_INTERFACE | grep "inet" | cut -d ' ' -f 6 | sed "s/[0-9]\+\//0\//"`
</span><span class='line'>
</span><span class='line'># This is where we load in the IP addresses of the interfaces
</span><span class='line'>PRIMARY_EXTERNAL_IP=`ip -4 addr show dev $PRIMARY_EXTERNAL_INTERFACE | grep inet | cut -d ' ' -f 6 | sed "s/\/[0-9]\+$//"`
</span><span class='line'>PRIMARY_INTERNAL_IP=`ip -4 addr show dev $PRIMARY_INTERNAL_INTERFACE | grep inet | cut -d ' ' -f 6 | sed "s/\/[0-9]\+$//"`
</span><span class='line'>SECONDARY_EXTERNAL_IP=`ip -4 addr show dev $SECONDARY_EXTERNAL_INTERFACE | grep inet | cut -d ' ' -f 6 | sed "s/\/[0-9]\+$//"`
</span><span class='line'>SECONDARY_INTERNAL_IP=`ip -4 addr show dev $SECONDARY_INTERNAL_INTERFACE | grep inet | cut -d ' ' -f 6 | sed "s/\/[0-9]\+$//"`
</span><span class='line'>
</span><span class='line'># We get the gateways by pinging once out of the appropriate interface to the multicast address of All Routers on the network. 
</span><span class='line'>PRIMARY_GATEWAY_IP=`ping -I $PRIMARY_EXTERNAL_IP 224.0.0.2 -c 1 | grep "icmp_seq" | cut -d : -f 1 | awk '{print $4}'`
</span><span class='line'>SECONDARY_GATEWAY_IP=`ping -I $SECONDARY_EXTERNAL_IP 224.0.0.2 -c 1 | grep "icmp_seq" | cut -d : -f 1 | awk '{print $4}'`</span></code></pre></td></tr></table></div></figure>


<h1>System Configuration</h1>

<p>In order to get most of these features working, we need to enable IP forwarding in the kernel.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>echo "Enabling IP forwarding..."
</span><span class='line'>sysctl -w net.ipv4.ip_forward=1
</span><span class='line'>sysctl -w net.ipv6.conf.all.forwarding=1</span></code></pre></td></tr></table></div></figure>


<h1>Routes</h1>

<p>The routes are the most critical part of making this whole system work. We use two cool features of the linux networking stack, Route Tables and Route Rules. Route Tables are similar to your VRF tables in Cisco-land. Basically you maintain several different routing tables on a single system in addition to the main one. In order to specify what table a packet should use, you configure Route Rules. A rule basically says &#8220;Packets that match this rule should use table A&#8221;. In this system I use rules to force a packet to use a route table based on its source address.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>
</span><span class='line'># Kernel IP Routes
</span><span class='line'>echo "Setting system default gateways"
</span><span class='line'>ip route del default
</span><span class='line'>ip route add default via $PRIMARY_GATEWAY_IP
</span><span class='line'>ip -6 route add ::/0 dev $IPV6_TUNNEL_INTERFACE
</span><span class='line'>
</span><span class='line'>echo "Adding default routes for primary external network..."
</span><span class='line'>ip route flush table $PRIMARY_EXTERNAL_INTERFACE-routes
</span><span class='line'>ip route add $PRIMARY_EXTERNAL_NETWORK dev $PRIMARY_EXTERNAL_INTERFACE src $PRIMARY_EXTERNAL_IP table $PRIMARY_EXTERNAL_INTERFACE-routes
</span><span class='line'>ip route add default via $PRIMARY_GATEWAY_IP table $PRIMARY_EXTERNAL_INTERFACE-routes
</span><span class='line'>
</span><span class='line'>echo "Adding default routes for secondary external network..."
</span><span class='line'>ip route flush table $SECONDARY_EXTERNAL_INTERFACE-routes
</span><span class='line'>ip route add $SECONDARY_EXTERNAL_NETWORK dev $SECONDARY_EXTERNAL_INTERFACE src $SECONDARY_EXTERNAL_IP table $SECONDARY_EXTERNAL_INTERFACE-routes
</span><span class='line'>ip route add default via $SECONDARY_GATEWAY_IP table $SECONDARY_EXTERNAL_INTERFACE-routes
</span><span class='line'>
</span><span class='line'>echo "Creating routes for primary internal network..."
</span><span class='line'>ip route flush table $PRIMARY_INTERNAL_INTERFACE-routes
</span><span class='line'>ip route add $PRIMARY_INTERNAL_NETWORK dev $PRIMARY_INTERNAL_INTERFACE table $PRIMARY_INTERNAL_INTERFACE-routes
</span><span class='line'>ip route add default via $PRIMARY_GATEWAY_IP table $PRIMARY_INTERNAL_INTERFACE-routes
</span><span class='line'>
</span><span class='line'>echo "Creating routes for secondary internal network..."
</span><span class='line'>ip route flush table $SECONDARY_INTERNAL_INTERFACE-routes
</span><span class='line'>ip route add $SECONDARY_INTERNAL_NETWORK dev $SECONDARY_INTERNAL_INTERFACE table $SECONDARY_INTERNAL_INTERFACE-routes
</span><span class='line'>ip route add default via $SECONDARY_GATEWAY_IP table $SECONDARY_INTERNAL_INTERFACE-routes
</span><span class='line'>
</span><span class='line'>echo "Creating route rules for primary external network..."
</span><span class='line'>ip rule del from $PRIMARY_EXTERNAL_IP
</span><span class='line'>ip rule add from $PRIMARY_EXTERNAL_IP table $PRIMARY_EXTERNAL_INTERFACE-routes
</span><span class='line'>
</span><span class='line'>echo "Creating route rules for secondary external network..."
</span><span class='line'>ip rule del from $SECONDARY_EXTERNAL_IP
</span><span class='line'>ip rule add from $SECONDARY_EXTERNAL_IP table $SECONDARY_EXTERNAL_INTERFACE-routes
</span><span class='line'>
</span><span class='line'>echo "Creating route rules for primary internal network..."
</span><span class='line'>ip rule del from $PRIMARY_INTERNAL_NETWORK
</span><span class='line'>ip rule add from $PRIMARY_INTERNAL_NETWORK lookup $PRIMARY_INTERNAL_INTERFACE-routes
</span><span class='line'>
</span><span class='line'>echo "Creating route rules for secondary internal network..."
</span><span class='line'>ip rule del from $SECONDARY_INTERNAL_NETWORK
</span><span class='line'>ip rule add from $SECONDARY_INTERNAL_NETWORK lookup $SECONDARY_INTERNAL_INTERFACE-routes</span></code></pre></td></tr></table></div></figure>


<h1>Firewall</h1>

<p>My script also maintains the host firewall rules, so we&#8217;ll enable those:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>echo "Reseting firewall rules..."
</span><span class='line'>$SERVICE iptables restart
</span><span class='line'>$SERVICE ip6tables restart
</span><span class='line'>
</span><span class='line'>echo "Setting up IPv4 firewall rules..."
</span><span class='line'>$IPTABLES -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
</span><span class='line'>$IPTABLES -A INPUT -p ipv6 -j ACCEPT
</span><span class='line'>$IPTABLES -A INPUT -p icmp -j ACCEPT
</span><span class='line'>$IPTABLES -A INPUT -i lo -j ACCEPT
</span><span class='line'>$IPTABLES -A INPUT -s mason.csh.rit.edu -p tcp --dport 5666 -j ACCEPT
</span><span class='line'>$IPTABLES -A INPUT -p tcp --dport 53 -j ACCEPT
</span><span class='line'>$IPTABLES -A INPUT -p udp --dport 53 -j ACCEPT
</span><span class='line'>$IPTABLES -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
</span><span class='line'>$IPTABLES -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
</span><span class='line'>$IPTABLES -A INPUT -j REJECT --reject-with icmp-host-prohibited
</span><span class='line'>
</span><span class='line'>echo "Setting up IPv6 firewall rules..."
</span><span class='line'>$IP6TABLES -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
</span><span class='line'>$IP6TABLES -A INPUT -p ipv6-icmp -j ACCEPT
</span><span class='line'>$IP6TABLES -A INPUT -i lo -j ACCEPT
</span><span class='line'>$IP6TABLES -A INPUT -p tcp  --dport 53 -j ACCEPT
</span><span class='line'>$IP6TABLES -A INPUT -p udp  --dport 53 -j ACCEPT
</span><span class='line'>$IP6TABLES -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
</span><span class='line'>$IP6TABLES -A INPUT -j REJECT --reject-with icmp6-adm-prohibited
</span><span class='line'>
</span><span class='line'>echo "Setting up firewall rules for primary internal network..."
</span><span class='line'>$IPTABLES -A FORWARD -s $PRIMARY_INTERNAL_NETWORK -j ACCEPT
</span><span class='line'>$IPTABLES -t nat -A POSTROUTING -s $PRIMARY_INTERNAL_NETWORK -j SNAT --to-source $PRIMARY_EXTERNAL_IP
</span><span class='line'>
</span><span class='line'>echo "Setting up firewall rules for secondary internal network..."
</span><span class='line'>$IPTABLES -A FORWARD -s $SECONDARY_INTERNAL_NETWORK -j ACCEPT
</span><span class='line'>$IPTABLES -t nat -A POSTROUTING -s $SECONDARY_INTERNAL_NETWORK -j SNAT --to-source $SECONDARY_EXTERNAL_IP
</span><span class='line'>
</span><span class='line'>echo "Setting up default firewall actions..."
</span><span class='line'>$IPTABLES -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
</span><span class='line'>$IPTABLES -A FORWARD -j REJECT --reject-with icmp-port-unreachable</span></code></pre></td></tr></table></div></figure>


<h1>Router Advertisements</h1>

<p>One of the features of my networking setup is that all networks, no matter internal or external have IPv6 connectivity. This is achieved by sending Router Advertisements out all interfaces. This is all well and good for the VMs that I am hosting, but these advertisements travel out of the physical interfaces to other hosts on the network! This is not good in that I am allowing other users to use my IPv6 tunnel interface. This puzzled me for a long time until I discovered a handy little program called &#8220;ebtables&#8221;. Ebtables is basically iptables for layer 2. As such, I was able to filter all router advertisement broadcasts out of the physical interfaces.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>echo "Blocking IPv6 router advertisement to the world..."
</span><span class='line'>$SERVICE radvd stop
</span><span class='line'>$SERVICE ebtables restart
</span><span class='line'>$EBTABLES -A OUTPUT -d 33:33:0:0:0:1 -o eth1 -j DROP
</span><span class='line'>$EBTABLES -A OUTPUT -d 33:33:0:0:0:1 -o eth0 -j DROP
</span><span class='line'>$SERVICE radvd start</span></code></pre></td></tr></table></div></figure>


<h1>End Result</h1>

<p>You now have a dual-homed server with two external networks, two internal networks, and IPv6 connectivity to all. Both external networks can receive their configuration via DHCP and will dynamically adjust their routing accordingly.</p>

<p><img src="http://www.grantcohoe.com/images/blog/enterprise-diagram.png" width="662" height="457" alt="" title="" /></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Facebook Friend Guidelines]]></title>
    <link href="http://www.grantcohoe.com/blog/2013/01/03/facebook-friend-guidelines/"/>
    <updated>2013-01-03T00:42:00-05:00</updated>
    <id>http://www.grantcohoe.com/blog/2013/01/03/facebook-friend-guidelines</id>
    <content type="html"><![CDATA[<p>If I am the requester or the requestee, it means that I have had a conversation with you (Not chat/texted. Actual person-to-person) on at least two separate occasions. (Occasionally this may be reduced to one depending on circumstances) Do not get this confused with what I consider a &#8220;dialog&#8221;. A dialog is nothing more than &#8220;Hi! How are you today? What&#8217;s up?&#8221;. A conversation entails we discussed and compared our thoughts on at least one topic at length >5min. Also If you are from my present, it means that I consider there a statistically significant chance that we will see each other in person again in the future. If you are from my past, then we talked at least twice on several (>2) occasions. If you are from my future, well that feature hasn&#8217;t been implemented yet and will probably cause me to segfault.</p>

<p>The logic behind these guidelines is relatively simple. There is no substitute for real life interaction. The idea of &#8220;meeting someone over Facebook&#8221; doesn&#8217;t sit well with me. Whenever I see a person friend-request someone they don&#8217;t really know or have had any degree of conversation with, it makes me question their ability to do so face-to-face. It also helps avoid the potential &#8220;stalker&#8221; effect that can come about easily with social media.</p>

<p>Take for example Jack and Jill. Jack is an avid fan of a school sports team. Jill is his favorite player on the sports team. Jack and Jill do not know each other, and have had nothing more than a dialog (as defined earlier) between them at various meet-n-greet events. Jill gets a friend-request from Jack several days later. Jill not wanting to potentially upset Jack accepts the friend-request. She now encounters frequent chat messages from Jack that lead a quick and dull conversation. Various other actions get Jack labeled as a &#8220;stalker&#8221; in Jills mind. This is not where Jack wanted to end up as he is now considered &#8220;the bad guy&#8221;. While his motives (assume everything here to be at face-value, no hidden agendas) are honorable, they have led to an awkward situation for both of them.</p>

<p>By my guidelines, Jill should never have accepted the friend-request. Similarly Jack should have never sent one. Since neither of them have had any level of in-person conversations, they have no common ground on which to establish a friendship.</p>

<p>I will occasionally receive friend-requests from people from High School. These I find myself subjecting to a higher degree of scrutiny since I do not associate with this crowd a whole lot anymore. If I did not particularly enjoy your presence back then, I probably have no reason to change that.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Secure Mirroring Highly-Available OpenLDAP Cluster]]></title>
    <link href="http://www.grantcohoe.com/blog/2013/01/03/secure-mirroring-highly-available-openldap-cluster/"/>
    <updated>2013-01-03T00:41:00-05:00</updated>
    <id>http://www.grantcohoe.com/blog/2013/01/03/secure-mirroring-highly-available-openldap-cluster</id>
    <content type="html"><![CDATA[<h1>Background</h1>

<p>My organization stores user information in an OpenLDAP directory server. This includes contact information, shell preferences, iButton IDs, etc. The directory server does not store the users password and relies on a Kerberos KDC to provide authentication via SASL. This is a widely supported configuration and is popular because you can achieve SSO (Single Sign-On) and keep passwords out of your directory. Our shell access machines are configured to do LDAP authentication of users which basically instructs PAM to do a bind to the LDAP server using the credentials provided by the user. If the bind is successful, the user logs in. If not, well sucks to be them. Before this project we had a single server handling the directory running CentOS 5.8/OpenLDAP 2.3. If this server went poof, then all userdata is lost and no one could log into any other servers (or websites if configured with Stanford Webauth. See the guide for more on this). Obviously this is a problem that needed correcting.</p>

<h1>Technology</h1>

<h2>LDAP Synchronization</h2>

<p>OpenLDAP 2.4 introduced a method of replication called &#8220;mirrormode&#8221;. This allows you to use their already existing syncrepl protocol to synchronize data between multiple servers. Previously (OpenLDAP &lt;= 2.3) only allowed you to do a master-slave style of replication where the slaves are read-only and would be unwilling to perform changes. Obviously this has some limitations in that if your master (or &#8220;provider&#8221; in OpenLDAP-ish) were to die, then your users cannot do any changes until you get it back online. Using MirrorMode, you can create an &#8220;N-way Multi-Master&#8221; topology that allows all servers to be read/write and instantly replicate their changes to the others.</p>

<h2>High Availability</h2>

<p>To enable users to have LDAP access even if one of the servers dies, we need a way to keep the packets flowing and automatically failover to the secondary servers. Linux has a package called &#8220;Heartbeat&#8221; that allows this sort of functionality. If you are familiar with Cisco HSRP or the open-source VRRP, it works the same way. Server A is assigned an IP address (lets say 10.0.0.1) and Server B is assigned a different address (lets say 10.0.0.2). Heartbeat is configured to provide a third IP address (10.0.0.3) that will always be available between the two. On the primary server, an ethernet alias is created with the virtualized IP address. Periodic heartbeats (keep-alive packets) are sent out to the other servers to indicate &#8220;I&#8217;m still here!&#8221;. Should these messages start disappearing (like when the server dies), the secondary will notice the lack of updates and automatically create a similar alias interface on itself and assign that virtualized IP. This allows you to give your clients one host, but have it seemlessly float between several real ones.</p>

<h2>SASL Authentication</h2>

<p>The easy way of configuring MirrorMode requires you to store your replication DN&#8217;s credentials in plaintext in the config file. Obviously this is not very secure since you are storing passwords in plaintext. As such we can use the hosts Kerberos principal to bind to the LDAP server as the replication DN and perform all of the tasks we need to do. This is much better than plaintext!</p>

<h2>SSL</h2>

<p>Since we like being secure, we should really be using LDAPS (LDAP + SSL) to get our data. We will be setting this up too using our PKI. We will save this for the end since we want to ensure that our core functionality actually works first.</p>

<h1>New Servers</h1>

<p>I spun up two new machines, lets call them &#8220;warlock.example.com&#8221; and &#8220;ldap2.example.com&#8221;. Each of them runs my favorite Scientific Linux 6.2 but with OpenLDAP 2.4. You cannot do MirrorMode between 2.3 and 2.4.</p>

<p><img src="http://www.grantcohoe.com/sites/default/files/styles/medium/public/ldaptopo.PNG" alt="" title="" class="image-medium" /></p>

<h1>Configuration</h1>

<h2>Packages</h2>

<p>First we need to install the required packages for all of this nonsense to work.</p>

<ul>
<li>openldap (LDAP libraries)</li>
<li>openldap-servers (Server)</li>
<li>openldap-clients (Client utilities)</li>
<li>cyrus-sasl (SASL daemon)</li>
<li>cyrus-sasl-ldap (LDAP authentication for SASL)</li>
<li>cyrus-sasl-gssapi (Kerberos authentication for SASL)</li>
<li>krb5-workstation (Kerberos client utilities)</li>
<li>heartbeat (Failover)</li>
</ul>


<p>If you are coming off of a fresh minimal install, you might want to install openssh-clients and vim as well. Some packages may not be included in your base distribution and may need other repositories (EPEL, etc)</p>

<h2>Kerberos Keytabs</h2>

<p>Each host needs its own set of host/ and ldap/ principals as well as a shared one for the virtualized address. In the end, you need a keytab with the following principals:</p>

<ul>
<li>host/ldap1.example.com@EXAMPLE.COM</li>
<li>ldap/ldap1.example.com@EXAMPLE.COM</li>
<li>host/ldap.example.com@EXAMPLE.COM</li>
<li>ldap/ldap.example.com@EXAMPLE.COM</li>
</ul>


<p>WARNING: Each time you write a -randkey&#8217;d principal to a keytab, it&#8217;s KVNO (Key Version Number) is increased, thus invalidating all previous written principals. You need to merge the shared principals into each hosts keytab. See my guide on Kerberos Utilities for information on doing this.</p>

<p>Put this file at /etc/krb5.keytab and set an ACL on it such that the LDAP user can read it.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@ldap1 ~]# chmod 640 /etc/krb5.keytab 
</span><span class='line'>[root@ldap1 ~]# setfacl -m u:ldap:r /etc/krb5.keytab 
</span><span class='line'>[root@ldap1 ~]# </span></code></pre></td></tr></table></div></figure>


<p>If you see something like &#8220;kerberos error 13&#8221; or &#8220;get_sec_context: 13&#8221; it means that someone cannot read the keytab, usually the LDAP server. Fix it.</p>

<h2>NTP</h2>

<p>Kerberos and the OpenLDAP synchronization require synchronized clocks. If you aren&#8217;t already set up for this, follow my guide for setting up NTP on a system before continuing.</p>

<h2>SASL</h2>

<p>You need saslauthd to be running on both LDAP servers. If you do not already have this set up, follow my guide for SASL Authentication before continuing.</p>

<h2>Logging</h2>

<p>We will be using Syslog and Logrotate to manage the logfiles for the LDAP daemon (slapd). By default it will spit out to local4. This is configurable depending on your system, but for me I am leaving it as the default. Add an entry to your <code>rsyslog</code> config file (usually <code>/etc/rsyslog.conf</code>) for <code>slapd</code></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>local4.*                /var/log/slapd.log</span></code></pre></td></tr></table></div></figure>


<p>Now unless we tell <code>logrotate</code> to rotate this file, it will get infinitely large and cause you lots of headaches. I created a config file to automatically rotate this log according the the system defaults. This was done at <code>/etc/logrotate.d/slapd</code>:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>/var/log/slapd.log {
</span><span class='line'>    missingok
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>


<p>Then restart <code>rsyslog</code>. Logrotate runs on a cron job and is not required to be restarted.</p>

<h2>Data Directory</h2>

<p>Since I am grabbing the data from my old LDAP server, I will not be setting up a new data directory. On the old server and on the new master, the data directory is <code>/var/lib/ldap/</code>. I simply scp&#8217;d all of the contents from the old server over to this directory. If you do this, I recommend stopping the old server for a moment to ensure that there are no changes occurring while you work. After scp-ing everything, make sure to chown everything to the LDAP user. I also recommend running <code>slapindex</code> to ensure that all data gets reindexed.</p>

<p><code>Client Library Configuration</code>
Now to make it convenient to test your new configuration, edit your <code>/etc/openldap/ldap.conf</code> to change the URI and add the certificate settings.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>BASE            dc=example,dc=com
</span><span class='line'>URI             ldaps://ldap.example.com
</span><span class='line'>TLS_CACERT      /etc/pki/tls/example-ca.crt
</span><span class='line'>TLS_REQCERT     allow</span></code></pre></td></tr></table></div></figure>


<p>When configuring this file on the servers, TLS_REQCERT must be set to ALLOW since we are doing Syncrepl over LDAPS. Obviously since we are using a shared certificate for ldap.example.com, it will not match the hostname of the server and will fail. On all of your clients, they should certainly &#8220;demand&#8221; the certificate. But in this instance that prevents us from accomplishing Syncrepl over LDAPS.</p>

<h2>Certificates for LDAPS</h2>

<p>Since people want to be secure, OpenLDAP has the ability to do sessions inside of TLS tunnels. This works the same way HTTPS traffic does. To do this you need to have the ability to generate SSL certificates based on a given CA. This procedure varies from organization to organization. Regardless of your method, the hostname you chose is critical as this will be the name that is verified. In this setup, we are creating a host called &#8220;ldap.example.com&#8221; that all LDAP clients will be configured to use. As such the same SSL certificate for both hosts will be generated for &#8220;ldap.example.com&#8221; and placed on each server.</p>

<p>I placed the public certificate at <code>/etc/pki/tls/certs/slapd.pem</code>, the secret key in <code>/etc/pki/tls/private/slapd.pem</code>, and my CA certificate at <code>/etc/pki/tls/example-ca.crt</code>. After obtaining my files, I verify them to make sure that they will actually work:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@ldap1 ~]# openssl verify -CAfile /etc/pki/tls/example-ca.crt /etc/pki/tls/certs/slapd.pem
</span><span class='line'>/etc/pki/tls/certs/slapd.pem: OK
</span><span class='line'>[root@ldap1 ~]# </span></code></pre></td></tr></table></div></figure>


<p>You need to allow the LDAP account to read the private certificate:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@ldap1 ~]# setfacl -m u:ldap:r /etc/pki/tls/private/slapd.pem</span></code></pre></td></tr></table></div></figure>


<h2>Server Configuration</h2>

<p>If you are using a previous server configuration, just scp the entire <code>/etc/openldap</code> code over to the new servers. Make sure you blow away any files or directories that may have been added for you before you copy. If you are not, you might need to do a bit of setup. OpenLDAP 2.4 uses a new method of configuration called &#8220;cn=config&#8221;, which stores the configuration data in the LDAP database. However since this is not fully supported by most clients, I am still using the config file. For setting up a fresh install, see one of my other articles on this. (Still in progress at the time of this writing)</p>

<p>The following directives will need to be placed in your slapd.conf for the SSL certificates:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>TLSCertificateFile /etc/pki/tls/certs/slapd.pem
</span><span class='line'>TLSCertificateKeyFile /etc/pki/tls/private/slapd.pem
</span><span class='line'>TLSCACertificateFile /etc/pki/tls/example-ca.crt</span></code></pre></td></tr></table></div></figure>


<p>Depending on your system, you may need to configure the daemon to run on ldaps://. On Red-Hat based systems this is in <code>/etc/sysconfig/ldap</code>.</p>

<p>You need to add two things to your configuration for Syncrepl to function. First to your <code>slapd.conf</code>:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># Syncrepl ServerID
</span><span class='line'>serverID 001
</span><span class='line'>
</span><span class='line'># Syncrepl configuration for mirroring instant replication between another 
</span><span class='line'># server. The binddn should be the host/ principal of this server 
</span><span class='line'># stored in the Kerberos keytab
</span><span class='line'>syncrepl rid=001
</span><span class='line'>provider=ldaps://ldap2.example.com
</span><span class='line'>type=refreshAndPersist
</span><span class='line'>retry="5 5 300 +"
</span><span class='line'>searchbase="dc=example,dc=com"
</span><span class='line'>attrs="*,+"
</span><span class='line'>bindmethod=sasl
</span><span class='line'>binddn="cn=ldap1,ou=hosts,dc=example,dc=com"
</span><span class='line'>mirrormode TRUE</span></code></pre></td></tr></table></div></figure>


<p>The serverID value must uniquely identify the server. Make sure you change it when inserting the configuration onto the secondary server. Likewise change the Syncrepl RID as well for the same reason.</p>

<p>Secondly you need need to allow the replication binddn full read access to all objects. This should go in your ACL file (which could be your slapd.conf, but shouldnt be).</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>access to *
</span><span class='line'>        by dn.exact="cn=ldap1,ou=hosts,dc=example,dc=com" read
</span><span class='line'>        by dn.exact="cn=ldap2,ou=hosts,dc=example,dc=com" read</span></code></pre></td></tr></table></div></figure>


<p>WARNING: If you do not have an existing ACL setup, doing just these entries will prevent anything else from doing anything with your server. These directives are meant to be ADDED to an existing ACL.</p>

<p>You should be all set and ready to start the server.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@ldap1 ~]# service slapd start
</span><span class='line'>Starting slapd:                                            [  OK  ] 
</span><span class='line'>[root@ldap1 ~]# </span></code></pre></td></tr></table></div></figure>


<p>Make sure that when you do your SASL bind, the server reports your DN correctly. To verify this:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>ldap1 ~ # su ldap -s /bin/bash
</span><span class='line'>bash-4.1$ kinit -k -t /etc/krb5.keytab host/ldap1.example.com
</span><span class='line'>bash-4.1$ ldapwhoami -Q
</span><span class='line'>dn:cn=ldap1,ou=hosts,dc=example,dc=com
</span><span class='line'>bash-4.1$</span></code></pre></td></tr></table></div></figure>


<p>That DN is the one that should be in your ACL and have read access to everything.</p>

<p>Since the LDAP user will always need this principal, I recommend adding a cronjob to keep the ticket alive. I wrote a script that will renew your ticket and fix an SELinux permissioning problem as well. You can get it <a href="http://archive.grantcohoe.com/projects/ldap/slaprenew">here</a>. Just throw it into your <code>/usr/local/sbin/</code> directory. There are better ways of doing this, but this one works just as well.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>0 */2 * * * /usr/local/sbin/slaprenew</span></code></pre></td></tr></table></div></figure>


<h2>Firewall</h2>

<p>Dont forget to open up ports 389 and 636 for LDAP and LDAPSSL!</p>

<h2>Searching</h2>

<p>After configuring both the master and the secondary servers, we now need to get the data initially replicated across your secondaries. Assuming you did like me and copied the data directory from an old server, your master is the only one that has real data. Start the service on this machine. If all went according to plan, you should be able to search for an object to verify that it works.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@ldap1 ~]# kinit user
</span><span class='line'>Password for user@EXAMPLE.COM:
</span><span class='line'>[root@ldap1 ~]# ldapsearch -h localhost uid=user uidNumber -Q -LLL
</span><span class='line'>dn: uid=user,ou=users,dc=example,dc=com
</span><span class='line'>uidNumber: 10046
</span><span class='line'>
</span><span class='line'>[root@ldap1 ~]#</span></code></pre></td></tr></table></div></figure>


<p>If you get errors, increase the debug level (-d 1) and work out any issues.</p>

<h2>Replication</h2>

<p>After doing a kinit as the LDAP user described above (host/ldap2.example.com), start the LDAP server on the secondary. If you tail the slapd log file, you should start seeing replication events occurring really fast. This is the server loading its data from the provider as specified in slapd.conf. Once it is done, try searching the server in a similar fashion as above.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@ldap2 ~]# tail /var/log/slapd.log
</span><span class='line'>slapd[15759]: syncrepl_entry: rid=001 be_search (0)
</span><span class='line'>slapd[15759]: syncrepl_entry: rid=001 uid=user,ou=Users,dc=example,dc=com
</span><span class='line'>slapd[15759]: syncrepl_entry: rid=001 be_add uid=user,ou=Users,dc=example,dc=com (0)
</span><span class='line'>slapd[15759]: syncrepl_entry: rid=001 LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_ADD)
</span><span class='line'>slapd[15759]: syncrepl_entry: rid=001 inserted UUID 84ba3544-5be8-102b-9a32-4dfcdb785320
</span><span class='line'>slapd[15759]: syncrepl_entry: rid=001 be_search (0)
</span><span class='line'>slapd[15759]: syncrepl_entry: rid=001 uid=user,ou=Users,dc=example,dc=com
</span><span class='line'>slapd[15759]: syncrepl_entry: rid=001 be_add uid=user,ou=Users,dc=example,dc=com (0)
</span><span class='line'>slapd[15759]: syncrepl_entry: rid=001 LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_ADD)
</span><span class='line'>slapd[15759]: syncrepl_entry: rid=001 inserted UUID 84c04164-5be8-102b-9a33-4dfcdb785320
</span><span class='line'>slapd[15759]: syncrepl_entry: rid=001 be_search (0)</span></code></pre></td></tr></table></div></figure>


<h2>Heartbeat</h2>

<p>Heartbeat provides failover for configured resources between several Linux systems. In this case we are going to provide high-availability of an alias IP address (10.0.0.3) which we will distribute to clients as the LDAP server (ldap.example.com). Heartbeat configuration is very simple and only requires three files:</p>

<p><code>/etc/ha.d/haresources</code> contains the resources that we will be failing over. It should be the same on both servers.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>ldap1.example.com IPaddr::10.0.0.3/24/eth0:1/10.0.0.255</span></code></pre></td></tr></table></div></figure>


<p>The reason the name of the host above is not &#8220;ldap.example.com&#8221; is because the entry must be a node listed in the configuration file (below).</p>

<p><code>/etc/ha.d/authkeys</code> contains a shared secret used to secure the heartbeat messages. This is to ensure that someone doesnt just throw up a server and claim to be a part of your cluster.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>auth 1
</span><span class='line'>1 md5 mysupersecretpassword</span></code></pre></td></tr></table></div></figure>


<p>Make sure to chmod it to something not world-readable (600 is recommend).</p>

<p>Finally, <code>/etc/ha.d/ha.cf</code> is the Heartbeat configuration file. It should contain entries for each server in your cluster, timers, and log files.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>mcast           eth0 225.0.0.1 694 1 0
</span><span class='line'>auto_failback   on
</span><span class='line'>keepalive 1
</span><span class='line'>deadtime 5
</span><span class='line'>debugfile       /var/log/ha-debug.log
</span><span class='line'>logfile         /var/log/ha.log
</span><span class='line'>logfacility     local0
</span><span class='line'>udp             eth0
</span><span class='line'>node            ldap1.example.com
</span><span class='line'>node            ldap2.example.com</span></code></pre></td></tr></table></div></figure>


<p>After all this is set, start the heartbeat service. After a bit you should see another ethernet interface show up on your primary. To test failover, unplug one of the machines and see what happens!</p>

<h2>DNS Hack</h2>

<p>A side affect of having the LDAP server respond on the shared IP address is that it gets confused about its hostname. As such you need to edit your <code>/etc/hosts</code> file to point the ldap.example.com name to each of the actual host IP addresses. In this example, ldap1 is 10.0.0.1 and ldap2 is 10.0.0.2. You should modify your hosts file to include:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>10.0.0.1 ldap.example.com ldap
</span><span class='line'>10.0.0.2 ldap.example.com ldap</span></code></pre></td></tr></table></div></figure>


<p>The first entry should be the address of the local system (10.0.0.2 should be the first in the case of ldap2).</p>

<p>Your DNS server should be able to do forward and reverse lookups for <code>ldap.example.com</code> going to 10.0.0.3 (the highly available address).</p>

<p>If you are having issues binding between the servers or binding from clients, it is usually due to DNS problems.</p>

<h1>Testing</h1>

<p>If all went according to plan, you should be able to see Sync messages in your slapd log file.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>slapd[11059]: slapd starting
</span><span class='line'>slapd[11059]: do_syncrep2: rid=002 LDAP_RES_INTERMEDIATE - REFRESH_DELETE</span></code></pre></td></tr></table></div></figure>


<p>Likewise if you log into a client machine (in my case, I made this the KDC) you should be able to search at only the ldap.example.com host. The others will return errors.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@kdc ~]# ldapsearch -Q -LLL uid=user displayName -h ldap.example.com
</span><span class='line'>dn: uid=user,ou=users,dc=example,dc=com
</span><span class='line'>displayName: Firstname Lastname (user)
</span><span class='line'>
</span><span class='line'>[root@kdc ~]# ldapsearch -Q -LLL uid=user displayName -h ldap1.example.com
</span><span class='line'>ldap_sasl_interactive_bind_s: Invalid credentials (49)
</span><span class='line'>        additional info: SASL(-13): authentication failure: GSSAPI Failure: gss_accept_sec_context
</span><span class='line'>[root@kdc ~]# ldapsearch -Q -LLL uid=user displayName -h ldap2.example.com
</span><span class='line'>ldap_sasl_interactive_bind_s: Invalid credentials (49)
</span><span class='line'>        additional info: SASL(-13): authentication failure: GSSAPI Failure: gss_accept_sec_context
</span><span class='line'>[root@kdc ~]# </span></code></pre></td></tr></table></div></figure>


<p>The reason is that the client has a different view of what the server&#8217;s hostname is. This difference causes SASL to freak out and not allow you to bind.</p>

<h1>Errors</h1>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@kdc ~]# ldapsearch -h ldap.example.com uid=user
</span><span class='line'>SASL/GSSAPI authentication started
</span><span class='line'>ldap_sasl_interactive_bind_s: Invalid credentials (49)
</span><span class='line'>        additional info: SASL(-13): authentication failure: GSSAPI Failure: gss_accept_sec_context
</span><span class='line'>[root@kdc ~]#</span></code></pre></td></tr></table></div></figure>


<p>On the server reveals the error of:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>slapd[9888]: GSSAPI Error: Unspecified GSS failure.  Minor code may provide more information (Wrong principal in request)
</span><span class='line'>slapd[9888]: text=SASL(-13): authentication failure: GSSAPI Failure: gss_accept_sec_context</span></code></pre></td></tr></table></div></figure>


<p>This means your DNS is not hacked or functional. Fix it according to the instructions</p>

<p>The LDAP log says:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>slapd[1901]: do_syncrepl: rid=005 rc -2 retrying
</span><span class='line'>slapd[1901]: slap_client_connect: URI=ldap://ldap2.example.com ldap_sasl_interactive_bind_s failed (-2)</span></code></pre></td></tr></table></div></figure>


<p>and <code>/var/log/messages</code> contains:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>GSSAPI Error: Unspecified GSS failure.  Minor code may provide more information (Credentials cache permissions incorrect)</span></code></pre></td></tr></table></div></figure>


<p>You need to change the SELinux context of your KRB5CC file (default is <code>/tmp/krb5cc_$UIDOFLDAPUSER</code> on Scientific Linux) to something the slapd process can read. Since every time you re-initialize the ticket you risk defaulting the permissions, I recommend using my script in your cronjob from above. If someone finds a better way to do this, please let me know!</p>

<p>If after enabling SSL on your client you receive (using -d 1):</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>TLS: can't connect: TLS error -5938:Encountered end of file.</span></code></pre></td></tr></table></div></figure>


<p>Check your certificate files on the SERVER. Odds are you have an incorrect path.</p>

<h1>Summary</h1>

<p>You now have two independent LDAP servers running OpenLDAP 2.4 and synchronizing data between them. They are intended to listen on a Heartbeat-ed service IP address that will always be available even if one of the servers dies. You can also do SASL binds to each server to avoid having passwords stored in your configuration files.</p>

<p>If after reading this you feel there is something that can be improved or isnt clear, feel free to contact me! Also you can grab sample configuration files that I used at <a href="http://archive.grantcohoe.com/projects/ldap">http://archive.grantcohoe.com/projects/ldap</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Kerberos Utilities]]></title>
    <link href="http://www.grantcohoe.com/blog/2013/01/03/kerberos-utilities/"/>
    <updated>2013-01-03T00:36:00-05:00</updated>
    <id>http://www.grantcohoe.com/blog/2013/01/03/kerberos-utilities</id>
    <content type="html"><![CDATA[<p>There are a number of useful Kerberos client utilities that can help you when working with authentication services.</p>

<h1>kinit</h1>

<p>kinit will initiate a new ticket from the Kerberos system. This is how you renew your tickets to access kerberized services or renew service principals for daemons. You can kinit interactively by simply running kinit and giving it the principal you want to init as:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>gmcsrvx1 ~ # kinit grant
</span><span class='line'>Password for grant@GRANTCOHOE.COM: 
</span><span class='line'>gmcsrvx1 ~ # </span></code></pre></td></tr></table></div></figure>


<p>No response is good, and you can view your initialized ticket with klist (discussed later on).</p>

<p>You can also kinit with a keytab by giving it the path to a keytab and a principal.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>gmcsrvx1 ~ # kinit -k -t /etc/krb5.keytab host/gmcsrvx1.grantcohoe.com
</span><span class='line'>gmcsrvx1 ~ # </span></code></pre></td></tr></table></div></figure>


<p>Note that it did not prompt me for a password. That is because it is using the stored principal key in the keytab to authenticate to the Kerberos server.</p>

<h1>klist</h1>

<p>klist is commonly used for two purposes: 1) List your current Kerberos tickets and 2) List the principals stored in a keytab. Running klist without any arguments will perform the first action.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>gmcsrvx1 ~ # klist
</span><span class='line'>Ticket cache: FILE:/tmp/krb5cc_0
</span><span class='line'>Default principal: grant@GRANTCOHOE.COM
</span><span class='line'>
</span><span class='line'>Valid starting     Expires            Service principal
</span><span class='line'>04/18/12 12:44:31  04/19/12 12:44:30  krbtgt/GRANTCOHOE.COM@GRANTCOHOE.COM
</span><span class='line'>  renew until 04/18/12 12:44:31</span></code></pre></td></tr></table></div></figure>


<p>To list the contents of a keytab:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>gmcsrvx1 ~ # klist -k -t /etc/krb5.keytab 
</span><span class='line'>Keytab name: WRFILE:/etc/krb5.keytab
</span><span class='line'>KVNO Timestamp         Principal
</span><span class='line'>---- ----------------- -------------------------------------------------------
</span><span class='line'>   2 02/16/12 14:50:12 host/gmcsrvx1.grantcohoe.com@GRANTCOHOE.COM
</span><span class='line'>   2 02/16/12 14:50:12 host/gmcsrvx1.grantcohoe.com@GRANTCOHOE.COM
</span><span class='line'>   2 02/16/12 14:50:12 host/gmcsrvx1.grantcohoe.com@GRANTCOHOE.COM
</span><span class='line'>gmcsrvx1 ~ # </span></code></pre></td></tr></table></div></figure>


<p>The duplication of the principal names represents each of the encryption types that are stored in the keytab. In my case, I use three encryption types to store my principals. If you support older deprecated enc-types (as Kerberos calls them), you will see more entries here.</p>

<h1>kdestroy</h1>

<p>kdestroy destroys all Kerberos tickets for your current user. You can verify this by doing:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>gmcsrvx1 ~ # kdestroy
</span><span class='line'>gmcsrvx1 ~ # klist
</span><span class='line'>klist: No credentials cache found (ticket cache FILE:/tmp/krb5cc_0)
</span><span class='line'>gmcsrvx1 ~ # </span></code></pre></td></tr></table></div></figure>


<h1>ktutil</h1>

<p>The Keytab Utility lets you view and modify keytab files. To start, you need to read in a keytab</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>ktutil:  rkt /etc/krb5.keytab 
</span><span class='line'>ktutil:  list
</span><span class='line'>slot KVNO Principal
</span><span class='line'>---- ---- --------------------------------------------------------------------
</span><span class='line'>   1    2 host/gmcsrvx1.grantcohoe.com@GRANTCOHOE.COM
</span><span class='line'>   2    2 host/gmcsrvx1.grantcohoe.com@GRANTCOHOE.COM
</span><span class='line'>   3    2 host/gmcsrvx1.grantcohoe.com@GRANTCOHOE.COM
</span><span class='line'>ktutil:  </span></code></pre></td></tr></table></div></figure>


<p>If you want to merge two keytabs, you can repeat the read command and the second keytab will be appended to the list. You can also selectively add and delete entries to the keytab as well. Once you are done, you can write the keytab out to a file.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>ktutil:  wkt /etc/krb5.keytab 
</span><span class='line'>ktutil:  quit
</span><span class='line'>gmcsrvx1 ~ # </span></code></pre></td></tr></table></div></figure>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[High-Availability with Multipath Routing]]></title>
    <link href="http://www.grantcohoe.com/blog/2013/01/03/high-availability-with-multipath-routing/"/>
    <updated>2013-01-03T00:34:00-05:00</updated>
    <id>http://www.grantcohoe.com/blog/2013/01/03/high-availability-with-multipath-routing</id>
    <content type="html"><![CDATA[<h1>Multipath Routing</h1>

<p>Multipath routing is when you have a router with multiple equal-cost paths to a single destination. Since each of these routes carries the same weight, the router will distribute traffic across all of them roughly equally. You can read more on this technology on <a href="https://en.wikipedia.org/wiki/Equal-cost_multi-path_routing">Wikipedia</a>. This is more about the implementation of such a topology.</p>

<h1>The Topology</h1>

<p>In my setup, I have three clients on the 192.168.0.0/24 subnet with gateway 192.168.0.254. Likewise I have three servers on the 10.0.0.0/24 subnet with gateway 10.0.0.254. I want my clients to always be able to access a webserver at host 172.16.0.1/32. This is configured as a loopback address on each of the three servers. This is the multipath part of the project. Each of the servers has the same IP address on a loopback interface and will therefore answer on it. However since the shared router between these two networks has no idea the 172.16.0.1/32 network is available via the servers, my clients cannot access it. This is where the routing comes into play. I will be using an OSPF daemon on my servers to send LSA&#8217;s (read up on OSPF if you are not familiar) to the router.
<img src="http://www.grantcohoe.com/images/blog/multipath.png" alt="" title="" /></p>

<h1>Server Configuration</h1>

<h2>Firewall</h2>

<p>You need to allow OSPF traffic to enter your system. IPtables supports the OSPF transport so you only need a minimum of one rule:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>iptables -I INPUT 1 -p ospf -j ACCEPT</span></code></pre></td></tr></table></div></figure>


<p>Save you firewall configuration after changing it.</p>

<h2>Package Installation</h2>

<p>You need to install Quagga, a suite of routing daemons that will be used to talk OSPF with the router. These packages are available in most operating systems.</p>

<h2>Interface Configuration</h2>

<p>Configure your main interface statically as you normally would. You also need to setup a loopback interface for the highly-available host. Procedure for this varies by operating system. Since I am using Scientific Linux, I have a configuration file in <code>/etc/sysconfig/network-scripts/ifcfg-lo:1</code>:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>DEVICE=lo:1
</span><span class='line'>IPADDR=172.16.0.1
</span><span class='line'>NETMASK=255.255.255.255
</span><span class='line'>ONBOOT=yes</span></code></pre></td></tr></table></div></figure>


<p>Make sure you restart your network process (or your host) after you do this. I first thought the reason this entire thing wasn&#8217;t working was a Linux-ism as my FreeBSD testing worked fine. I later discovered that it was because hot-adding an interface sometimes doesn&#8217;t add all the data we need to the kernel route table.</p>

<h2>OSPF Configuration</h2>

<p>Quagga&#8217;s ospfd has a single configuration file that is very Cisco-like in syntax. It is located at <code>/etc/quagga/ospfd.conf</code>:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>hostname server1
</span><span class='line'>interface eth0
</span><span class='line'>router ospf
</span><span class='line'>  ospf router-id 10.0.0.1
</span><span class='line'>  network 10.0.0.0/24 area 0
</span><span class='line'>  network 172.16.0.1/32 area 0
</span><span class='line'>log stdout</span></code></pre></td></tr></table></div></figure>


<p>ospfd has a partner program called zebra that manages the kernel route table entries learned via OSPF. While we may not necessarily want these, zebra must be running and configured in order for this to work. Edit your <code>/etc/quagga/zebra.conf</code>:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>hostname server1
</span><span class='line'>interface eth0</span></code></pre></td></tr></table></div></figure>


<p>After you are all set, start zebra and ospfd (and make sure they are set to come up on boot).</p>

<h1>Router Configuration</h1>

<p>I am using a virtualized Cisco 7200 router in my testing environment. You may have to modify your interfaces, but otherwise this configuration is generic across all IOS:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>R1&gt;enable
</span><span class='line'>R1#configure terminal
</span><span class='line'>Enter configuration commands, one per line.  End with CNTL/Z.
</span><span class='line'>R1(config)#router ospf 1
</span><span class='line'>R1(config-router)#network 10.0.0.0 0.0.0.255 area 0
</span><span class='line'>R1(config-router)#end</span></code></pre></td></tr></table></div></figure>


<p>This enables OSPF on the 10.0.0.0/24 network and will start listening for LSAs. When it processes a new one, the route will be inserted into the routing table. After a while, you should see something like this:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>R1#show ip route ospf
</span><span class='line'>     172.16.0.0/32 is subnetted, 1 subnets
</span><span class='line'>O       172.16.0.1 [110/11] via 10.0.0.3, 00:04:42, GigabitEthernet1/0
</span><span class='line'>                   [110/11] via 10.0.0.2, 00:04:42, GigabitEthernet1/0
</span><span class='line'>                   [110/11] via 10.0.0.1, 00:04:42, GigabitEthernet1/0</span></code></pre></td></tr></table></div></figure>


<p>This is multipath routing. The host 172.16.0.1/32 has three equal paths available to get to it.</p>

<h1>Testing</h1>

<p>To verify that my clients were actually getting load-balanced, I threw up an Apache webserver on each server with a static index.html file containing the ID of the server (server 1, server 2, server 3, etc). This way I can curl the highly-available IP address and can see which host I am getting routed to. You should see your clients get distributed out across any combination of the three servers.</p>

<p>Now lets simulate a host being taken offline for maintenance. Rather than having to fail over a bunch of services, all you need to do is stop the ospfd process on the server. After the OSPF dead timer expires, the route will be removed and no more traffic will be routed to it. That host is now available for downtime without affecting any of the others. The router just redistributes the traffic on the remaining routes.</p>

<p>But lets say the host immediately dies. There is no notification to the router that the backend host is no longer responding. The only thing you can do at this point is wait for the OSPF dead timer to expire. You can configure this to be a shorter amount of time, thus making &#8220;failover&#8221; more transparent.</p>

<h1>Summary</h1>

<p>Multipath routing is basically a poor-mans load balancer. It has no checks to see if the services are actually running and responding appropriately. It also does not behave very well with sessions or data that involves lots of writes. However for static web hosting or for caching nameservers (the use that sparked my interest in this technology), it works quite well.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Secure OpenLDAP Server with Kerberos Authentication]]></title>
    <link href="http://www.grantcohoe.com/blog/2013/01/03/secure-openldap-server-with-kerberos-authentication/"/>
    <updated>2013-01-03T00:26:00-05:00</updated>
    <id>http://www.grantcohoe.com/blog/2013/01/03/secure-openldap-server-with-kerberos-authentication</id>
    <content type="html"><![CDATA[<h1>Host Configuration</h1>

<p>There are some things we need to set up prior to installing and configuring OpenLDAP.</p>

<h2>Kerberos</h2>

<p>You will need a working KDC somewhere in your domain. You also need to have the server configured as a Kerberos client (<code>/etc/krb5.conf</code>) and be able to <code>kinit</code> without issue.</p>

<p>There are two principals that you will need in your <code>/etc/krb5.keytab</code>:</p>

<ul>
<li>host/server.example.com@EXAMPLE.COM
<li>ldap/server.example.com@EXAMPLE.COM
</ul>


<h2>saslauthd</h2>

<p>If you do not already have this working, see my guide on how to set it up.</p>

<h1>Packages</h1>

<p>You need the following for our setup:</p>

<ul>
<li>krb5-server-ldap (for the Kerberos schema)
<li>openldap
<li>openldap-clients
<li>openldap-servers
<li>cyrus-sasl-gssapi
<li>cyrus-sasl-ldap
</ul>


<h1>SSL Certificates</h1>

<p>You will need SSL certificates matching the hostname you intend your LDAP server to listen on (ldap.example.com is different than server.example.com). Procure these from your PKI administrator. I place mine in the default directories as shown:</p>

<ul>
<li>Server Public Key - /etc/pki/tls/certs/slapd.pem
<li>Server Private Key - /etc/pki/tls/private/slapd.pem
<li>CA Certificate - /etc/pki/tls/cert.pem
</ul>


<h1>ACLs</h1>

<p>The LDAP user needs to be able to read the private key and keytab you configured earlier. Ensure that it can.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@localhost ~]# setfacl -m u:ldap:r /etc/krb5.keytab
</span><span class='line'>[root@localhost ~]# setfacl -m u:ldap:r /etc/pki/tls/private/slapd.pem</span></code></pre></td></tr></table></div></figure>


<h1>OpenLDAP Configuration</h1>

<h2>Directory Cleanup</h2>

<p>By default there are some extra files in the configuration directory. Since we are not using the cn=config method of configuring the server, we are simply going to remove the things we don&#8217;t want.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[root@localhost ~]# cd /etc/openldap/
</span><span class='line'>[root@localhost ~]# rm -rf slapd.d ldap.conf cacerts</span></code></pre></td></tr></table></div></figure>


<p>We will be re-creating ldap.conf later on with the settings that we want.</p>

<h2>Kerberos Schema</h2>

<p>Copy <code>/usr/share/doc/krb5-server-ldap-1.9/kerberos.schema</code> into your schema directory (default: <code>/etc/openldap/schema</code>. This contains all of the definitions for Kerberos-related attributes.</p>

<h2>Data Directory</h2>

<p>Decide where you want your data directory to be. By default this is <code>/var/lib/ldap</code> Copy over the standard DB_CONFIG file to that directory from <code>/usr/share/openldap-servers/DB_CONFIG.example</code>. This contains optimization information about the structure of the database.</p>

<h2>Enable LDAPS</h2>

<p>Some systems require you to explicitly enable LDAPS listening. On Red Hat Enterprise Linux-based distributions, this is done by changing <code>SLAPD_LDAPS</code> to YES in <code>/etc/sysconfig/ldap</code>.</p>

<h2>slapd.conf</h2>

<p>Create a <code>/etc/openldap/slapd.conf</code> to configure your server. You can grab a copy of my basic configuration file <a href="http://archive.grantcohoe.com/projects/ldap/slapd_basic.conf">here</a>.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'># Include base schema files provided by the openldap-servers package.
</span><span class='line'>include /etc/openldap/schema/corba.schema
</span><span class='line'>include /etc/openldap/schema/core.schema
</span><span class='line'>include /etc/openldap/schema/cosine.schema
</span><span class='line'>include /etc/openldap/schema/duaconf.schema
</span><span class='line'>include /etc/openldap/schema/dyngroup.schema
</span><span class='line'>include /etc/openldap/schema/inetorgperson.schema
</span><span class='line'>include /etc/openldap/schema/java.schema
</span><span class='line'>include /etc/openldap/schema/misc.schema
</span><span class='line'>include /etc/openldap/schema/nis.schema
</span><span class='line'>include /etc/openldap/schema/openldap.schema
</span><span class='line'>include /etc/openldap/schema/pmi.schema
</span><span class='line'>include /etc/openldap/schema/ppolicy.schema
</span><span class='line'>
</span><span class='line'># Site-specific schema and ACL includes. These are either third-party or custom.
</span><span class='line'>include /etc/openldap/schema/kerberos.schema
</span><span class='line'>
</span><span class='line'># Daemon files needed for the running of the daemon
</span><span class='line'>pidfile /var/run/openldap/slapd.pid
</span><span class='line'>argsfile /var/run/openldap/slapd.args
</span><span class='line'>
</span><span class='line'># Limit SASL options to only GSSAPI and not other client-favorites. Apparently there is an issue where
</span><span class='line'># clients will default to non-working SASL mechanisms and will make you angry.
</span><span class='line'>sasl-secprops noanonymous,noplain,noactive
</span><span class='line'>
</span><span class='line'># SASL connection information. The realm should be your Kerberos realm as configured for the system. The
</span><span class='line'># host should be the LEGITIMATE hostname of this server
</span><span class='line'>sasl-realm EXAMPLE.COM
</span><span class='line'>sasl-host ldap.example.com
</span><span class='line'>
</span><span class='line'># SSL certificate file paths
</span><span class='line'>TLSCertificateFile /etc/pki/tls/certs/slapd.pem
</span><span class='line'>TLSCertificateKeyFile /etc/pki/tls/private/slapd.pem
</span><span class='line'>TLSCACertificateFile /etc/pki/tls/cert.pem
</span><span class='line'>
</span><span class='line'># Rewrite certain SASL bind DNs to more readable ones. Otherwise you bind as some crazy default
</span><span class='line'># that ends up in a different base than your actual one. This uses regex to rewrite that weird
</span><span class='line'># DN and make it become one that you can put within your suffix.
</span><span class='line'>authz-policy from
</span><span class='line'>authz-regexp &quot;^uid=[^,/]+/admin,cn=example\.com,cn=gssapi,cn=auth&quot; &quot;cn=ldaproot,dc=example,dc=com&quot;
</span><span class='line'>authz-regexp &quot;^uid=host/([^,]+)\.example\.com,cn=example\.com,cn=gssapi,cn=auth&quot; &quot;cn=$1,ou=hosts,dc=example,dc=com&quot;
</span><span class='line'>authz-regexp &quot;^uid=([^,]+),cn=example\.com,cn=gssapi,cn=auth&quot; &quot;uid=$1,ou=users,dc=example,dc=com&quot;
</span><span class='line'>
</span><span class='line'># Logging
</span><span class='line'>#loglevel 16384
</span><span class='line'>loglevel 256
</span><span class='line'>
</span><span class='line'># Actual LDAP database for things you want
</span><span class='line'>database bdb
</span><span class='line'>suffix &quot;dc=example,dc=com&quot;
</span><span class='line'>rootdn &quot;cn=ldaproot,dc=example,dc=com&quot;
</span><span class='line'>rootpw {MD5}X03MO1qnZdYdgyfeuILPmQ==
</span><span class='line'>directory /var/lib/ldap
</span><span class='line'>
</span><span class='line'># Indicies for the database. These are used to improve performance of the database
</span><span class='line'>index entryCSN eq
</span><span class='line'>index entryUUID eq
</span><span class='line'>index objectClass eq,pres
</span><span class='line'>index ou,cn,mail eq,pres,sub,approx
</span><span class='line'>index uidNumber,gidNumber,loginShell eq,pres
</span><span class='line'>
</span><span class='line'># Configuration database
</span><span class='line'>database config
</span><span class='line'>rootdn &quot;cn=ldaproot,dc=example,dc=com&quot;
</span><span class='line'>
</span><span class='line'># Monitoring database
</span><span class='line'>database monitor
</span><span class='line'>rootdn &quot;cn=ldaproot,dc=example,dc=com&quot;
</span></code></pre></td></tr></table></div></figure>


<p>To generate a password for your directory and hash it, you can use the <code>slappasswd</code> utility. See my guide on LDAP utilities for details. After that you should be all set. Start the slapd service, but dont query it yet.</p>

<h1>Client Configuration</h1>

<p>The <code>/etc/openldap/ldap.conf</code> file is the system-wide default LDAP connection settings. This way you do not have to specify the host and protocol each time you want to run a command. Make it now.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'># OpenLDAP client configuration file. Used for host default settings
</span><span class='line'>BASE            dc=example,dc=com
</span><span class='line'>URI             ldaps://ldap.example.com
</span><span class='line'>TLS_CACERT      /etc/pki/tls/cert.pem
</span><span class='line'>TLS_REQCERT     demand
</span></code></pre></td></tr></table></div></figure>


<h1>Population</h1>

<p>Right now you should have a running server, but with no data in it. I created a simple example setup file to get a basic tree set up. At this point you need to architect how you want your directory to be organized. You may chose to follow this or chose your own.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>miranda ldap # cat setup.ldif
</span><span class='line'>dn: dc=example,dc=com
</span><span class='line'>dc: example
</span><span class='line'>o: Example Corporation
</span><span class='line'>objectclass: top
</span><span class='line'>objectclass: dcObject
</span><span class='line'>objectclass: organization
</span><span class='line'>
</span><span class='line'>dn: ou=hosts,dc=example,dc=com
</span><span class='line'>ou: hosts
</span><span class='line'>objectclass: top
</span><span class='line'>objectclass: organizationalUnit
</span><span class='line'>
</span><span class='line'>dn: ou=users,dc=example,dc=com
</span><span class='line'>ou: users
</span><span class='line'>objectclass: top
</span><span class='line'>objectclass: organizationalUnit
</span><span class='line'>
</span><span class='line'>dn: cn=ldap1,ou=hosts,dc=example,dc=com
</span><span class='line'>cn: ldap1
</span><span class='line'>sn: ldap1
</span><span class='line'>objectclass: top
</span><span class='line'>objectclass: person
</span><span class='line'>
</span><span class='line'>dn: cn=ldap2,ou=hosts,dc=example,dc=com
</span><span class='line'>cn: ldap2
</span><span class='line'>sn: ldap2
</span><span class='line'>objectclass: top
</span><span class='line'>objectclass: person
</span><span class='line'>
</span><span class='line'>dn: uid=user,ou=users,dc=example,dc=com
</span><span class='line'>objectclass: top
</span><span class='line'>objectclass: person
</span><span class='line'>objectclass: organizationalPerson
</span><span class='line'>objectclass: posixAccount
</span><span class='line'>objectclass: inetOrgPerson
</span><span class='line'>ou: Users
</span><span class='line'>uid: user
</span><span class='line'>uidNumber: 10000
</span><span class='line'>gidNumber: 150
</span><span class='line'>givenName: Firstname
</span><span class='line'>sn: Lastname
</span><span class='line'>cn: Firstname Lastname
</span><span class='line'>gecos: Firstname Lastname
</span><span class='line'>Description: Firstname Lastname
</span><span class='line'>homeDirectory: /users/user
</span><span class='line'>loginShell: /bin/bash
</span><span class='line'>mail: firstname.lastname@example.com
</span><span class='line'>displayname: Firstname Lastname (user)
</span><span class='line'>userPassword: {SASL}user@EXAMPLE.COM
</span><span class='line'>
</span><span class='line'>dn: uid=admin,ou=users,dc=example,dc=com
</span><span class='line'>objectclass: top
</span><span class='line'>objectclass: person
</span><span class='line'>objectclass: organizationalPerson
</span><span class='line'>objectclass: posixAccount
</span><span class='line'>objectclass: inetOrgPerson
</span><span class='line'>ou: Users
</span><span class='line'>uid: admin
</span><span class='line'>uidNumber: 10001
</span><span class='line'>gidNumber: 151
</span><span class='line'>givenName: Firstname
</span><span class='line'>sn: Lastname
</span><span class='line'>cn: Firstname Lastname
</span><span class='line'>gecos: Firstname Lastname
</span><span class='line'>Description: Firstname Lastname
</span><span class='line'>homeDirectory: /users/admin
</span><span class='line'>loginShell: /bin/bash
</span><span class='line'>mail: firstname.lastname@example.com
</span><span class='line'>displayname: Firstname Lastname (admin)
</span></code></pre></td></tr></table></div></figure>


<p>You can add the contents of this file to your directory using ldapadd.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>ldapadd -x -D cn=ldaproot,dc=example,dc=com -W -f setup.ldif
</span></code></pre></td></tr></table></div></figure>


<h1>Testing</h1>

<p>You should now be able to query your server and figure out who it thinks you are based on your Kerberos principal.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>[root@ldap ~]# kinit user
</span><span class='line'>Password for user@EXAMPLE.COM:
</span><span class='line'>[root@ldap ~]# ldapwhoami
</span><span class='line'>SASL/GSSAPI authentication started
</span><span class='line'>SASL username: user@EXAMPLE.COM
</span><span class='line'>SASL SSF: 56
</span><span class='line'>SASL data security layer installed.
</span><span class='line'>dn:uid=user,ou=users,dc=example,dc=com
</span><span class='line'>[root@ldap ~]#
</span></code></pre></td></tr></table></div></figure>


<p>Here you can see that it thinks that I am <code>uid=user,ou=users,dc=example,dc=com</code> given my principal of <code>user@EXAMPLE.COM</code>.</p>

<p>Now try searching:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>[root@ldap ~]# ldapsearch uid=user
</span><span class='line'>SASL/GSSAPI authentication started
</span><span class='line'>SASL username: user@EXAMPLE.COM
</span><span class='line'>SASL SSF: 56
</span><span class='line'>SASL data security layer installed.
</span><span class='line'># extended LDIF
</span><span class='line'>#
</span><span class='line'># LDAPv3
</span><span class='line'># base &lt;dc=example,dc=com&gt; (default) with scope subtree
</span><span class='line'># filter: uid=user
</span><span class='line'># requesting: ALL
</span><span class='line'>#
</span><span class='line'>
</span><span class='line'># user, users, example.com
</span><span class='line'>dn: uid=user,ou=users,dc=example,dc=com
</span><span class='line'>objectClass: top
</span><span class='line'>objectClass: person
</span><span class='line'>objectClass: organizationalPerson
</span><span class='line'>objectClass: posixAccount
</span><span class='line'>objectClass: inetOrgPerson
</span><span class='line'>ou: Users
</span><span class='line'>uid: user
</span><span class='line'>uidNumber: 10000
</span><span class='line'>gidNumber: 150
</span><span class='line'>givenName: Firstname
</span><span class='line'>sn: Lastname
</span><span class='line'>cn: Firstname Lastname
</span><span class='line'>gecos: Firstname Lastname
</span><span class='line'>description: Firstname Lastname
</span><span class='line'>homeDirectory: /users/user
</span><span class='line'>loginShell: /bin/bash
</span><span class='line'>mail: firstname.lastname@example.com
</span><span class='line'>displayName: Firstname Lastname (user)
</span><span class='line'>
</span><span class='line'># search result
</span><span class='line'>search: 5
</span><span class='line'>result: 0 Success
</span><span class='line'>
</span><span class='line'># numResponses: 2
</span><span class='line'># numEntries: 1
</span><span class='line'>[root@ldap ~]#
</span></code></pre></td></tr></table></div></figure>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Fix Me Maybe]]></title>
    <link href="http://www.grantcohoe.com/blog/2013/01/03/fix-me-maybe/"/>
    <updated>2013-01-03T00:23:00-05:00</updated>
    <id>http://www.grantcohoe.com/blog/2013/01/03/fix-me-maybe</id>
    <content type="html"><![CDATA[<p>Fix Me Maybe (parody of Call Me Maybe)
Words by Grant Cohoe (cohoe)
Music &amp; original words by Carly Rae Jepsen</p>

<p>This was dedicated to Ross Delinger (rossdylan) because: &#8220;FIX THE DAMN IRC SERVER!&#8221; Like the original song, it then went a lot further than expected. What more might come of this?!</p>

<p><a href="http://csh.rit.edu/~ducker/fixmemaybe.mp3">MP3 - Sung by Alex Howland (ducker)</a></p>

<p>Lyrics:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>I started as a project
</span><span class='line'>Something come Fall we'd forget
</span><span class='line'>The system full of neglect
</span><span class='line'>But now you've logged into me.
</span><span class='line'>
</span><span class='line'>Everything's been broke for awhile
</span><span class='line'>It's not great R-T-P style
</span><span class='line'>This wasn't supposed to be a trial
</span><span class='line'>But now you've logged into me.
</span><span class='line'>
</span><span class='line'>Your session was open
</span><span class='line'>Bytes of logs were flowin'
</span><span class='line'>Files were c-h-ownin'
</span><span class='line'>Need to get them daemons going
</span><span class='line'>
</span><span class='line'>I'm used to broken things
</span><span class='line'>These users are crazy
</span><span class='line'>But here's my address, 
</span><span class='line'>so fix me maybe?
</span><span class='line'>
</span><span class='line'>It's hard to figure out
</span><span class='line'>What is wrong here
</span><span class='line'>But here's my address, 
</span><span class='line'>so fix me maybe?
</span><span class='line'>
</span><span class='line'>I'm used to broken things
</span><span class='line'>These users are crazy
</span><span class='line'>But here's my address, 
</span><span class='line'>so fix me maybe?
</span><span class='line'>
</span><span class='line'>And all the other boys
</span><span class='line'>Try and break me
</span><span class='line'>But here's my address,
</span><span class='line'>so fix me maybe?
</span><span class='line'>
</span><span class='line'>You took your time with fix
</span><span class='line'>Broke in no time 'cause they're pricks
</span><span class='line'>You didn't help anything
</span><span class='line'>But still, you're logged in me
</span><span class='line'>
</span><span class='line'>I page, and cache and write
</span><span class='line'>Every morn day and night
</span><span class='line'>Processor cycles aren't tight
</span><span class='line'>But still, you're logged in me
</span><span class='line'>
</span><span class='line'>Your session was open
</span><span class='line'>Bytes of logs were flowin'
</span><span class='line'>Files were c-h-ownin'
</span><span class='line'>Need to get them daemons going
</span><span class='line'>
</span><span class='line'>I'm used to broken things
</span><span class='line'>These users are crazy
</span><span class='line'>But here's my address, 
</span><span class='line'>so fix me maybe?
</span><span class='line'>
</span><span class='line'>It's hard to figure out
</span><span class='line'>What is wrong here
</span><span class='line'>But here's my address, 
</span><span class='line'>so fix me maybe?
</span><span class='line'>
</span><span class='line'>I'm used to broken things
</span><span class='line'>These users are crazy
</span><span class='line'>But here's my address, 
</span><span class='line'>so fix me maybe?
</span><span class='line'>
</span><span class='line'>And all the other boys
</span><span class='line'>Try and break me
</span><span class='line'>But here's my address,
</span><span class='line'>so fix me maybe?
</span><span class='line'>
</span><span class='line'>Before you came into my logs 
</span><span class='line'>I was broken so bad
</span><span class='line'>I was broken so bad
</span><span class='line'>I was broken so so bad
</span><span class='line'>
</span><span class='line'>Before you came into my logs 
</span><span class='line'>I was broken so bad
</span><span class='line'>And you should know that
</span><span class='line'>I was broken so bad
</span><span class='line'>
</span><span class='line'>It's hard to figure out
</span><span class='line'>What is wrong here
</span><span class='line'>But here's my address, 
</span><span class='line'>so fix me maybe?
</span><span class='line'>
</span><span class='line'>I'm used to broken things
</span><span class='line'>These users are crazy
</span><span class='line'>But here's my address, 
</span><span class='line'>so fix me maybe?
</span><span class='line'>
</span><span class='line'>And all the other boys
</span><span class='line'>Try and break me
</span><span class='line'>But here's my address,
</span><span class='line'>so fix me maybe?
</span><span class='line'>
</span><span class='line'>Before you came into my logs 
</span><span class='line'>I was broken so bad
</span><span class='line'>I was broken so bad
</span><span class='line'>I was broken so so bad
</span><span class='line'>
</span><span class='line'>Before you came into my logs 
</span><span class='line'>I was broken so bad
</span><span class='line'>And you should know that
</span><span class='line'>
</span><span class='line'>So fix me, maybe?</span></code></pre></td></tr></table></div></figure>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Makefile-based PKI Management]]></title>
    <link href="http://www.grantcohoe.com/blog/2013/01/01/makefile-based-pki-management/"/>
    <updated>2013-01-01T23:03:00-05:00</updated>
    <id>http://www.grantcohoe.com/blog/2013/01/01/makefile-based-pki-management</id>
    <content type="html"><![CDATA[<p>Using a couple of seed files, you can easily get started managing your own PKI for your network. You need to have OpenSSL and Make installed on the system you are working with.</p>

<p>First, pick a directory to store your certificates in. I am going to use <code>/etc/pki/example.com</code> since this is where all the other system SSL stuff is stored and for you SELinux people, will already have the right contexts. cd into that directory and create the Makefile:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='make'><span class='line'><span class="nv">CONFIG</span><span class="o">=</span>config/openssl.cnf
</span><span class='line'><span class="nv">PUB</span><span class="o">=</span>host-cert.pem
</span><span class='line'><span class="nv">PRIV</span><span class="o">=</span>host-key.pem
</span><span class='line'><span class="nv">REQ</span><span class="o">=</span>req.pem
</span><span class='line'><span class="nv">PUBNPRIV</span><span class="o">=</span>host-combined.pem
</span><span class='line'>
</span><span class='line'><span class="nf">issue</span><span class="o">:</span>
</span><span class='line'>  mkdir -p <span class="k">${</span><span class="nv">DEST</span><span class="k">}</span>
</span><span class='line'>  openssl req -new -nodes -out <span class="k">${</span><span class="nv">DEST</span><span class="k">}</span>/<span class="k">${</span><span class="nv">REQ</span><span class="k">}</span> -config <span class="k">${</span><span class="nv">CONFIG</span><span class="k">}</span>
</span><span class='line'>  mv <span class="k">${</span><span class="nv">PRIV</span><span class="k">}</span> <span class="k">${</span><span class="nv">DEST</span><span class="k">}</span>/
</span><span class='line'>  openssl ca -out <span class="k">${</span><span class="nv">DEST</span><span class="k">}</span>/<span class="k">${</span><span class="nv">PUB</span><span class="k">}</span> -config <span class="k">${</span><span class="nv">CONFIG</span><span class="k">}</span> -infiles <span class="k">${</span><span class="nv">DEST</span><span class="k">}</span>/<span class="k">${</span><span class="nv">REQ</span><span class="k">}</span>
</span><span class='line'>  <span class="k">if</span> <span class="o">[</span> <span class="k">${</span><span class="nv">DEST</span><span class="k">}</span> <span class="o">=</span> mail -o <span class="k">${</span><span class="nv">DEST</span><span class="k">}</span> <span class="o">=</span> mail/ <span class="o">]</span>; <span class="k">then </span>cp <span class="k">${</span><span class="nv">DEST</span><span class="k">}</span>/<span class="k">${</span><span class="nv">PUB</span><span class="k">}</span> <span class="k">${</span><span class="nv">DEST</span><span class="k">}</span>/<span class="k">${</span><span class="nv">PUBNPRIV</span><span class="k">}</span>; cat <span class="k">${</span><span class="nv">DEST</span><span class="k">}</span>/<span class="k">${</span><span class="nv">PRIV</span><span class="k">}</span> &gt;&gt; <span class="k">${</span><span class="nv">DEST</span><span class="k">}</span>/<span class="k">${</span><span class="nv">PUBNPRIV</span><span class="k">}</span>; <span class="k">fi</span>
</span><span class='line'><span class="k">  </span>chmod <span class="nv">go</span><span class="o">=</span> <span class="k">${</span><span class="nv">DEST</span><span class="k">}</span>/<span class="k">${</span><span class="nv">PRIV</span><span class="k">}</span>
</span><span class='line'>  <span class="k">if</span> <span class="o">[</span> -e <span class="k">${</span><span class="nv">DEST</span><span class="k">}</span>/<span class="k">${</span><span class="nv">PUBNPRIV</span><span class="k">}</span> <span class="o">]</span>; <span class="k">then </span>chmod <span class="nv">go</span><span class="o">=</span> <span class="k">${</span><span class="nv">DEST</span><span class="k">}</span>/<span class="k">${</span><span class="nv">PUBNPRIV</span><span class="k">}</span>; <span class="k">fi</span>
</span><span class='line'>
</span><span class='line'><span class="nf">revoke</span><span class="o">:</span>
</span><span class='line'>  openssl ca -config <span class="k">${</span><span class="nv">CONFIG</span><span class="k">}</span> -revoke <span class="k">${</span><span class="nv">SOURCE</span><span class="k">}</span>/<span class="k">${</span><span class="nv">PUB</span><span class="k">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>This lets us perform two actions (targets): Issue and Revoke. Issue will create a new host certificate from your CA. Revoke will expire an already-existing certificate. This is mainly used for renewal since you need to revoke then issue.</p>

<p>Next we will need a configuration directory and some basic files:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='console'><span class='line'><span class="go">[root@gmcsrvx1 example.com ]# mkdir config config/newcerts config/CA</span>
</span><span class='line'><span class="go">[root@gmcsrvx1 example.com ]# touch config/index.txt</span>
</span><span class='line'><span class="go">[root@gmcsrvx1 example.com ]# echo &#39;01&#39; &gt; config/serial</span>
</span></code></pre></td></tr></table></div></figure>


<p>After that, cd into the config directory and create an <code>openssl.cnf</code> file. This is the OpenSSL configuration file used for certificate generation:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'># OpenSSL configuration file.
</span><span class='line'>#
</span><span class='line'># Adapted by Grant Cohoe 2011 (www.grantcohoe.com)
</span><span class='line'># Original by some past CSHer (www.csh.rit.edu)
</span><span class='line'>
</span><span class='line'># Establish working directory.
</span><span class='line'>
</span><span class='line'>dir               = /etc/pki/example.com
</span><span class='line'>
</span><span class='line'>[ req ]
</span><span class='line'>default_bits      = 2048          # Size of keys
</span><span class='line'>default_keyfile   = host-key.pem      # name of generated keys
</span><span class='line'>default_md        = sha1          # message digest algorithm
</span><span class='line'>string_mask       = nombstr           # permitted characters
</span><span class='line'>distinguished_name    = req_distinguished_name
</span><span class='line'>req_extensions        = v3_req            # always use v3 extensions for reqs
</span><span class='line'>
</span><span class='line'>[ req_distinguished_name ]
</span><span class='line'># Variable name  Prompt string
</span><span class='line'>#----------------------  ----------------------------------
</span><span class='line'>0.organizationName        = Organization Name (company)
</span><span class='line'>organizationalUnitName    = Organizational Unit Name (department, division)
</span><span class='line'>emailAddress          = Email
</span><span class='line'>emailAddress_max      = 40
</span><span class='line'>localityName          = Locality Name (city)
</span><span class='line'>stateOrProvinceName       = State or Province Name (full name)
</span><span class='line'>countryName           = Country Name (2 letter code)
</span><span class='line'>countryName_min       = 2
</span><span class='line'>countryName_max       = 2
</span><span class='line'>commonName            = Common Name (full hostname)
</span><span class='line'>commonName_max            = 64
</span><span class='line'>
</span><span class='line'># Default values for the above, for consistency and less typing.
</span><span class='line'># Variable name  Value
</span><span class='line'>#------------------------------  ------------------------------
</span><span class='line'>0.organizationName_default        = Example Corp
</span><span class='line'>organizationalUnitName_default    = System Engineering
</span><span class='line'>emailAddress_default          = root@example.com
</span><span class='line'>localityName_default          = Rochester
</span><span class='line'>stateOrProvinceName_default       = New York
</span><span class='line'>countryName_default               = US
</span><span class='line'>
</span><span class='line'>[ v3_ca ]
</span><span class='line'>basicConstraints      = CA:TRUE
</span><span class='line'>subjectKeyIdentifier  = hash
</span><span class='line'>authorityKeyIdentifier    = keyid:always,issuer:always
</span><span class='line'>
</span><span class='line'>[ v3_req ]
</span><span class='line'>basicConstraints      = CA:FALSE
</span><span class='line'>subjectKeyIdentifier  = hash
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>[ ca ]
</span><span class='line'>default_ca    = CA_default
</span><span class='line'>
</span><span class='line'>[ CA_default ]
</span><span class='line'>serial        = $dir/serial
</span><span class='line'>database      = $dir/index.txt
</span><span class='line'>new_certs_dir = $dir/newcerts
</span><span class='line'>certificate   = $dir/CA/example-ca.crt
</span><span class='line'>private_key   = $dir/CA/example-ca.key
</span><span class='line'>default_days  = 365
</span><span class='line'>default_md    = sha1
</span><span class='line'>preserve      = no
</span><span class='line'>email_in_dn   = no
</span><span class='line'>nameopt       = default_ca
</span><span class='line'>certopt       = default_ca
</span><span class='line'>policy        = policy_match
</span><span class='line'>
</span><span class='line'>[ policy_match ]
</span><span class='line'>countryName           = match
</span><span class='line'>stateOrProvinceName       = match
</span><span class='line'>organizationName      = match
</span><span class='line'>organizationalUnitName    = optional
</span><span class='line'>commonName            = supplied
</span><span class='line'>emailAddress          = optional
</span></code></pre></td></tr></table></div></figure>


<p>You should ensure that the directory definition and organization information is changed to match what you want.</p>

<p>After this you are ready to generate your CA:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='console'><span class='line'><span class="go">openssl req -config openssl.cnf -new -x509 -extensions v3_ca -keyout CA/example-ca.key -out CA/example-ca.crt -days 1825</span>
</span></code></pre></td></tr></table></div></figure>


<p>This will generate a CA certificate based on your settings file and will last for 5 years, after which you will need to renew it.</p>

<p>Enter a certificate password when prompted. You do not need to specify a Common Name (CN) as asked later in the process. Ensure that the other field defaults are correct, as they came from your <code>openssl.cnf</code> file and are needed to match in other certificates.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
</pre></td><td class='code'><pre><code class='console'><span class='line'><span class="go">[root@gmcsrvx1 config]# openssl req -config openssl.cnf -new -x509 -extensions v3_ca -keyout CA/example-ca.key -out CA/example-ca.crt -days 1825</span>
</span><span class='line'><span class="go">Generating a 2048 bit RSA private key</span>
</span><span class='line'><span class="go">................................................................................</span>
</span><span class='line'><span class="go">..................+++</span>
</span><span class='line'><span class="go">writing new private key to &#39;CA/example-ca.key&#39;</span>
</span><span class='line'><span class="go">Enter PEM pass phrase:</span>
</span><span class='line'><span class="go">Verifying - Enter PEM pass phrase:</span>
</span><span class='line'><span class="go">-----</span>
</span><span class='line'><span class="go">You are about to be asked to enter information that will be incorporated</span>
</span><span class='line'><span class="go">into your certificate request.</span>
</span><span class='line'><span class="go">What you are about to enter is what is called a Distinguished Name or a DN.</span>
</span><span class='line'><span class="go">There are quite a few fields but you can leave some blank</span>
</span><span class='line'><span class="go">For some fields there will be a default value,</span>
</span><span class='line'><span class="go">If you enter &#39;.&#39;, the field will be left blank.</span>
</span><span class='line'><span class="go">-----</span>
</span><span class='line'><span class="go">Organization Name (company) [Example Corp]:</span>
</span><span class='line'><span class="go">Organizational Unit Name (department, division) [System Engineering]:</span>
</span><span class='line'><span class="go">Email [root@example.com]:</span>
</span><span class='line'><span class="go">Locality Name (city) [Rochester]:</span>
</span><span class='line'><span class="go">State or Province Name (full name) [New York]:</span>
</span><span class='line'><span class="go">Country Name (2 letter code) [US]:</span>
</span><span class='line'><span class="go">Common Name (full hostname) []:</span>
</span><span class='line'><span class="go">[root@gmcsrvx1 config]#</span>
</span></code></pre></td></tr></table></div></figure>


<p>Unfortunately this process creates the private key file to be world readable. This is extremely bad. Fix it. Also ensure that the public key is readable by all. It is supposed to be.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='console'><span class='line'><span class="go">[root@gmcsrvx1 config]# chmod 600 CA/example-ca.key</span>
</span><span class='line'><span class="go">[root@gmcsrvx1 config]# chmod 644 CA/example-ca.crt</span>
</span></code></pre></td></tr></table></div></figure>


<p>Now back up one directory (back to the working directory you started at). I usually make a symlink to the CA public key here so you can easily reference it.</p>

<p>You can now issue SSL certificates by typing <code>make DEST=hostname</code> where hostname is the name of the server you are going to issue to.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
</pre></td><td class='code'><pre><code class='console'><span class='line'><span class="go">[root@gmcsrvx1 example.com]# make DEST=gmcsrvx1</span>
</span><span class='line'><span class="go">mkdir -p gmcsrvx1</span>
</span><span class='line'><span class="go">openssl req -new -nodes -out gmcsrvx1/req.pem -config config/openssl.cnf</span>
</span><span class='line'><span class="go">Generating a 2048 bit RSA private key</span>
</span><span class='line'><span class="go">..............................................+++</span>
</span><span class='line'><span class="go">......................................+++</span>
</span><span class='line'><span class="go">writing new private key to &#39;host-key.pem&#39;</span>
</span><span class='line'><span class="go">-----</span>
</span><span class='line'><span class="go">You are about to be asked to enter information that will be incorporated</span>
</span><span class='line'><span class="go">into your certificate request.</span>
</span><span class='line'><span class="go">What you are about to enter is what is called a Distinguished Name or a DN.</span>
</span><span class='line'><span class="go">There are quite a few fields but you can leave some blank</span>
</span><span class='line'><span class="go">For some fields there will be a default value,</span>
</span><span class='line'><span class="go">If you enter &#39;.&#39;, the field will be left blank.</span>
</span><span class='line'><span class="go">-----</span>
</span><span class='line'><span class="go">Organization Name (company) [Example Corp]:</span>
</span><span class='line'><span class="go">Organizational Unit Name (department, division) [System Engineering]:</span>
</span><span class='line'><span class="go">Email [root@example.com]:</span>
</span><span class='line'><span class="go">Locality Name (city) [Rochester]:</span>
</span><span class='line'><span class="go">State or Province Name (full name) [New York]:</span>
</span><span class='line'><span class="go">Country Name (2 letter code) [US]:</span>
</span><span class='line'><span class="go">Common Name (full hostname) []:gmcsrvx1.example.com</span>
</span><span class='line'><span class="go">mv host-key.pem gmcsrvx1/</span>
</span><span class='line'><span class="go">openssl ca -out gmcsrvx1/host-cert.pem -config config/openssl.cnf -infiles gmcsr</span>
</span><span class='line'><span class="go">Using configuration from config/openssl.cnf</span>
</span><span class='line'><span class="go">Enter pass phrase for /etc/pki/example.com/config/CA/example-ca.key:</span>
</span><span class='line'><span class="go">Check that the request matches the signature</span>
</span><span class='line'><span class="go">Signature ok</span>
</span><span class='line'><span class="go">The Subject&#39;s Distinguished Name is as follows</span>
</span><span class='line'><span class="go">organizationName      :PRINTABLE:&#39;Example Corp&#39;</span>
</span><span class='line'><span class="go">organizationalUnitName:PRINTABLE:&#39;System Engineering&#39;</span>
</span><span class='line'><span class="go">localityName          :PRINTABLE:&#39;Rochester&#39;</span>
</span><span class='line'><span class="go">stateOrProvinceName   :PRINTABLE:&#39;New York&#39;</span>
</span><span class='line'><span class="go">countryName           :PRINTABLE:&#39;US&#39;</span>
</span><span class='line'><span class="go">commonName            :PRINTABLE:&#39;gmcsrvx1.example.com&#39;</span>
</span><span class='line'><span class="go">Certificate is to be certified until May  1 18:12:03 2013 GMT (365 days)</span>
</span><span class='line'><span class="go">Sign the certificate? [y/n]:y</span>
</span><span class='line'>
</span><span class='line'>
</span><span class='line'><span class="go">1 out of 1 certificate requests certified, commit? [y/n]y</span>
</span><span class='line'><span class="go">Write out database with 1 new entries</span>
</span><span class='line'><span class="go">Data Base Updated</span>
</span><span class='line'><span class="go">if [ gmcsrvx1 = mail -o gmcsrvx1 = mail/ ]; then cp gmcsrvx1/host-cert.pem gmcsr.pem; fi</span>
</span><span class='line'><span class="go">chmod go= gmcsrvx1/host-key.pem</span>
</span><span class='line'><span class="go">if [ -e gmcsrvx1/host-combined.pem ]; then chmod go= gmcsrvx1/host-combined.pem;</span>
</span><span class='line'><span class="go">[root@gmcsrvx1 example.com]#</span>
</span></code></pre></td></tr></table></div></figure>


<p>If you look in the directory it made for you (the hostname you specified) you will find the private and public keys for the server.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='console'><span class='line'><span class="go">[root@gmcsrvx1 example.com]# ls -l gmcsrvx1/</span>
</span><span class='line'><span class="go">total 12</span>
</span><span class='line'><span class="go">-rw-r--r--. 1 root root 3997 May  1 14:12 host-cert.pem</span>
</span><span class='line'><span class="go">-rw-------. 1 root root 1704 May  1 14:12 host-key.pem</span>
</span><span class='line'><span class="go">-rw-r--r--. 1 root root 1171 May  1 14:12 req.pem</span>
</span></code></pre></td></tr></table></div></figure>


<p>You can revoke this certificate using the makefile as well:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='console'><span class='line'><span class="go">[root@gmcsrvx1 example.com]# make revoke SOURCE=gmcsrvx1</span>
</span><span class='line'><span class="go">openssl ca -config config/openssl.cnf -revoke gmcsrvx1/host-cert.pem</span>
</span><span class='line'><span class="go">Using configuration from config/openssl.cnf</span>
</span><span class='line'><span class="go">Enter pass phrase for /etc/pki/example.com/config/CA/example-ca.key:</span>
</span><span class='line'><span class="go">Revoking Certificate 01.</span>
</span><span class='line'><span class="go">Data Base Updated</span>
</span><span class='line'><span class="go">[root@gmcsrvx1 example.com]#</span>
</span></code></pre></td></tr></table></div></figure>


<p>There you go, yet another useful service to have around for dealing with your network. Raw files used above are available in the <a href="http://archive.grantcohoe.com/projects/ssl">Archive</a>. Now back to Webauth with me&#8230;</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[System Technology Accounting and Resource Registration Solution (STARRS)]]></title>
    <link href="http://www.grantcohoe.com/blog/2013/01/01/system-technology-accounting-and-resource-registration-solution-starrs/"/>
    <updated>2013-01-01T20:10:00-05:00</updated>
    <id>http://www.grantcohoe.com/blog/2013/01/01/system-technology-accounting-and-resource-registration-solution-starrs</id>
    <content type="html"><![CDATA[<h1>Background</h1>

<p>Like most of my projects, it all started with CSH. RIT allocates us two /24 public-facing networks to distribute out to our users. These resources need to have some degree of accounting in the event a user does something stupid (piracy, kiddie-pr0n, etc). RIT handles this with their own internal application, referred to as &#8220;start.rit.edu&#8221;. <em>Fun aside, Start.RIT was coded by an old CSHer, now RIT employee and CSH advisor. He still maintains portions of it today.</em> When the CSH network got to the point of needing our own internal application, a member (<a href="http://www.csh.rit.edu/~sunday/">Joe Sunday</a>) created &#8220;start.csh.rit.edu&#8221;. Similar to it&#8217;s RIT counterpart, start.csh allowed administrators to register machines and distribute resources on the network. Start.csh also allowed for users to manage firewall rules for their hosts at the border firewall systems. On the backend, it had a script that would automatically generate an ISC-DHCPD config file and load it into the server.</p>

<p>Unfortunately over time, bits of Start began to break. The fact that users could not register their own machines was a major source of irritation for the RTPs (Root-Type-Persons, or Sysadmins). When the network topology was shifted to accomodate some reorganization within RIT, the firewall rule system broke completely. There was no way to clear out old hosts that havent been on the network in years. And after the house DHCP server was compromised (then obliterated by the RTPs for security), the automatic DHCP generation was completely gone. We needed something new.</p>

<p>Starting in the Spring of 2011 I starting to architect a new application to encoumpase the previous functionality and add a lot of new features and enhancements that would benefit us for years to come. Going into the projects, I knew one thing: It had to be based in PostgreSQL. Pg has native datatypes for IP addresses, subnets, and MAC addresses. I know that this would be invaluable to have later on in the project. I also knew that I didnt want to write a daemon that ran on some server imposing application logic.</p>

<h1>Development</h1>

<p>At this point in my career, I didn&#8217;t have a whole lot of database architecting experience. I began to search for a schema creation application to help me architect what I knew was going to be a complex schema. I ran across a service called <a href="http://www.schemabank.com">SchemaBank</a>. (SB is now defunct) It was a schema design webapp that supported Postgres. It also introduced me to two things that would change the course of the application forever: Triggers and Functions. I realized that I could use Pg as the backend daemon to the entire application. For client interaction with the application, I started to develop a set of wrapper API functions that would help impose the application logic on the stored data. While most of this was taken care of in the relations between entities, there were some that could not be expressed as a relation. Fast forward two months, and I had a first revision of the database and the API to start writing an interface for.</p>

<p>At this point I didn&#8217;t know any sort of web languages other than HTML and CSS either. So using a book I won at BarCampRoc on <a href="http://shop.oreilly.com/product/9780596157142.do">PHP, MySQL, and Javascript</a> (a very good book by the way), I started to learn PHP. Originally I was going to go with a purely non-OOP model for the webapp, however after consulting one of my web-dev friends (<a href="http://iota.csh.rit.edu/">Ben Russell</a>), he suggested that I go with an OOP model and to use some sort of framework to avoid having to write a ton of extra code. At this point I went with one that another one of my web-dev friends had used, <a href="http://ellislab.com/codeigniter">Codeigniter</a>. So I set to work and started writing classes. During this time, I knew that I needed a new a new dhcpd.conf generation function. One of my friends (<a href="http://blog.agargiulo.com/">Anthony Gargiulo</a>) expressed an interest in helping out with the project, so I tasked him with writing a generation function in Perl. Four months later, I had a working PHP web interface (and he had a working dhcpd.conf generator). At this point, I had everything except a name. I dont really remember a lot about how it came about, but I think I took the first cool-sounding word that came to my head. I was in a Quake 3 Arena mood that day and remembered an old console command (impulse). I took that word and backronymed it to the IP Management Program for Use in Local Server Environments.</p>

<h1>Initial Implementation</h1>

<p>When we returned to RIT in the Fall, I set to work deploying IMPULSE. After a few hickups here and there, everything was in place and in use. Users were fairly receptive to it, mainly that they could register their devices themselves. However after some time, a few problems emerged. The web interface became terribly slow with all of the data that people had entered. It wasnt very efficient at allowing users to complete basic tasks and had a few bugs. Clearly some changes needed to occur, but during the course of the year I didn&#8217;t want to touch it. I spent 6 months writing code on this project, and I really didnt want to work on it again.</p>

<h1>Refresh</h1>

<p>My latest co-op offerred me a chance to take to the code once again, this time with a new use case in mind. They wanted something that could manage network registrations for developers in a complex environment, but there were a few major additions that needed to happen. IMPULSE needed to go global. It needeed more specific access control. It needed better device integration. And most importantly, it also needed a new interface. Armed with all the knowlege I have gained over the last year, I set out to work. 2 months later I had a new web interface and a lot of new fixes and enhancements to the core. However the name IMPULSE no longer applied. So I cooked up a new one: STARRS (System Technology Accounting and Resource Registration Solution). And that&#8217;s presumably what you actually care about.</p>

<h1>Features</h1>

<p>STARRS starts off with Datacenters, which correspond to your physical locations. Each datacenter contains Subnets and VLANs. Each datacenter then contains one or more Availability Zones, which are logical partitions of resources within the datacenter. AZs contain ranges of your subnets.</p>

<p>Within datacenters are Systems. A system is a computer, based on a hardware Platform (usually Custom though). A system can have Interfaces which attach to your network. On each interface can be Addresses that are assigned from your Availability Zones. You can get your addresses in a variety of ways (depending on family). DHCP and Static for IPv4, and Autoconf, DHCPv6, and Static for IPv6. (Oh yeah, STARRS does both IPv4 and IPv6). Your addresses are given to you with a set expiration date. If you dont renew before that date (You will get email notifications), it will be automatically deleted. On your addresses, you can create a variety of DNS Records that can be added into managed DNS Zones. Zone DDNS updates are done with Keys that are stored within STARRS. If your address is configured with DHCP, you can be a member of a DHCP Class. Classes, Ranges, and Subnets all have a variety of configuration options that can be set. You can also set options globally. For network systems, you can store SNMP Credentials that STARRS can use to look up Switchport and CAM Table data. Using this you can easily locate your system interfaces in your infrastructure. And of course, you can search for systems that you have configured.</p>

<p>STARRS depends on your existing authentication infrastructure for its user data. It does not track credentials within itself, but relies on the client to provide the user and external sources for privileging. The STARRS web interface gets the username from the web server from configurable PHP variables. It takes the username and calls an API initializing function that sets up your privilege levels. STARRS can get privilege data from one of the following:</p>

<ul>
<li>Local Tables</li>
<li>OpenLDAP</li>
<li>Active Directory</li>
</ul>


<p>Users can be global ADMINs and have RW access to everything in the database. They can be USERs who can create/edit/remove their own stuff, but cannot see certain confidential configuration and cannot edit other peoples stuff. People who are Group Admins can edit other peoples stuff in their group. There is also a PROGRAM user-level that allows external applications Read-Only access to user resources. If you don&#8217;t exist in the privilege source, you will be unable to initialize and do anything in STARRS.</p>

<p>STARRS also has the ability to automatically generate a configuration file for the ISC-DHCPD server based on the resources you configure. It supports key-based DDNS updates to zones, DHCP classes, global/range/subnet/class options, and more. A cronjob runs to periodically generate, download, and reload the server configuration file. Eventually this might change to something more real, but for now this is what works.</p>

<p>Use cases have STARRS working with the following web authentication services:</p>

<ul>
<li><a href="http://webauth.stanford.edu/">Stanford Webauth</a></li>
<li><a href="http://httpd.apache.org/docs/2.2/mod/mod_ldap.html">Basic Auth w/ mod_ldap</a></li>
</ul>


<h1>Deployment</h1>

<p>All of the code is available on Github in two repositories:</p>

<ul>
<li><a href="https://github.com/cohoe/starrs">Core/Database</a></li>
<li><a href="https://github.com/cohoe/starrs-web">Web</a></li>
</ul>


<p>There is an unofficial and unsupported command-line interface written by a friend of mine (<a href="http://ryansb.com/">Ryan Brown</a>) located <a href="https://github.com/ryansb/ish">Here</a>.</p>

<p>STARRS is licensed under the MIT license.</p>

<h1>Demo</h1>

<p>You can access <a href="http://starrsdemo.grantcohoe.com">the demo by clicking here.</a> Username is &#8216;root&#8217; and password is &#8216;admin&#8217;. The database resets itself every 24 hours at midnight, so don&#8217;t expect long-term persistence of data.</p>

<h1>Who Should Use This</h1>

<p>If you are a service provider to a group of users who consume network resources that you control. You want some way of accounting for what resources are in use and where they are in your network. The use cases of it so far are:</p>

<ul>
<li>Computer Science House - Dorm of college students (about 350 systems)</li>
<li>Work - Product developers in 4 sites across 3 countries (1000+ systems)</li>
<li>Enterprise - My personal VM server (30 systems)</li>
</ul>


<h1>Future</h1>

<p>There are a couple of enhancements on deck for the next release (whever that may be). See the respective Github project issues for details. However STARRS will soon be encompasing libvirt support. When you create a system, you can specify it to be a Virtual Machine living on a Host in one of your datacenters. None of this has been worked on, but the idea is for STARRS to be a complete network management solution. Maybe I&#8217;ll call it CloudSTARRS (like rockstars, but in the cloud haha).</p>
]]></content>
  </entry>
  
</feed>
