Showing posts with label centos6. Show all posts
Showing posts with label centos6. Show all posts

Thursday, March 13, 2014

Installing Snort 2.9.6.0 on CentOS 6.5 64-bit

Some time ago I wrote a post about installing Snort 2.9.1 on CentOS 6. In the mean time I decided it's time to upgrade so the idea of this post is to document what changed with respect to that older post. In short, binary packages for CentOS 6 are now provided on the Snort's download page. So, you only need to download them and install (or install using URL). Yet, there is a problem with a libdnet dependency (I don't know which one was used during compilation, but it certainly wasn't the one in EPEL).

Compiling and installing

In case you want to rebuild them, the process is now almost without any problems. In the following text I'll assume that you started with a minimal CentOS installation with the following packages installed (and their dependencies, of course): gcc, make, bison, flex, autoconf, automake, rpmbuild.

First, download daq source rpm file. Before rebuilding it, you should install pcap-devel. This is actually something rpmbuild tool will warn you that you have to install. When you installed it, rebuild daq:
rpmbuild --rebuild daq
then, install it:
yum localinstall ~/rpmbuild/RPMS/x86_64/daq-2.0.2-1.x86_64.rpm
Next, for snort you'll need libdnet library which is in EPEL. So, first install EPEL:
yum install http://mirrors.neterra.net/epel/6/i386/epel-release-6-8.noarch.rpm
Then, install necessary packages:
yum install libdnet-devel zlib-devel
Those two aren't listed as dependencies in Snort's SRPM file, so you'll get some cryptic error message. Now, download Snort's srpm file and rebuild it using:
rpmbuild --rebuild snort-2.9.6.0-1.src.rpm
Now, install it using:
yum localinstall ~/rpmbuild/RPMS/x86_64/snort-2.9.6.0-1.x86_64.rpm
That's all there is for installation.

Configuring and running

I'll assume that you are installing a fresh instance, i.e. no previous configuration. In case there is previous installation be careful not to overwrite existing configuration. To configure snort you'll have to download snortrules archive. Then, unpack it:
mkdir ~/snort
tar xzf snortrules-snapshot-2960.tar.gz -C ~/snort
chown root.root ~/snort
Next you have to move files in their place. First, move basic configuration file:
mv -f snort/etc/* /etc/snort/
Note that I'm using force option of move command to overwrite existing files. Next, move rules to their place:
mv -i snort/rules snort/preproc_rules snort/so_rules /etc/snort/
Now, if you are using SELinux you should change context of the files you moved to /etc/snort directory. Do it using the following commands:
chcon -R system_u:object_r:snort_etc_t:s0 /etc/snort
chcon -R system_u:object_r:lib_t:s0 /etc/snort/so_rules/precompiled/RHEL-6-0/
You should now modify configuration file. Here is a diff of the changes I made:
--- snort.conf.orig 2014-03-13 11:25:53.889609831 +0100
+++ snort.conf 2014-03-13 11:37:32.419292894 +0100
@@ -42,16 +42,16 @@
 ###################################################

 # Setup the network addresses you are protecting
-ipvar HOME_NET any
+ipvar HOME_NET 192.168.1.0/24

 # Set up the external network addresses. Leave as "any" in most situations
 ipvar EXTERNAL_NET any

 # List of DNS servers on your network
-ipvar DNS_SERVERS $HOME_NET
+ipvar DNS_SERVERS 192.168.1.8,192.168.1.9

 # List of SMTP servers on your network
-ipvar SMTP_SERVERS $HOME_NET
+ipvar SMTP_SERVERS 192.168.1.20

 # List of web servers on your network
 ipvar HTTP_SERVERS $HOME_NET
@@ -101,13 +101,13 @@
 # Path to your rules files (this can be a relative path)
 # Note for Windows users:  You are advised to make this an absolute path,
 # such as:  c:\snort\rules
-var RULE_PATH ../rules
-var SO_RULE_PATH ../so_rules
-var PREPROC_RULE_PATH ../preproc_rules
+var RULE_PATH rules
+var SO_RULE_PATH so_rules
+var PREPROC_RULE_PATH preproc_rules

 # If you are using reputation preprocessor set these
-var WHITE_LIST_PATH ../rules
-var BLACK_LIST_PATH ../rules
+var WHITE_LIST_PATH rules
+var BLACK_LIST_PATH rules

 ###################################################
 # Step #2: Configure the decoder.  For more information, see README.decode
@@ -240,13 +240,13 @@
 ###################################################

 # path to dynamic preprocessor libraries
-dynamicpreprocessor directory /usr/local/lib/snort_dynamicpreprocessor/
+dynamicpreprocessor directory /usr/lib64/snort-2.9.6.0_dynamicpreprocessor/

 # path to base preprocessor engine
-dynamicengine /usr/local/lib/snort_dynamicengine/libsf_engine.so
+dynamicengine /usr/lib64/snort-2.9.6.0_dynamicengine/libsf_engine.so.0

 # path to dynamic rules libraries
-dynamicdetection directory /usr/local/lib/snort_dynamicrules
+dynamicdetection directory /etc/snort/so_rules/precompiled/RHEL-6-0/x86-64/2.9.6.0/

 ###################################################
 # Step #5: Configure preprocessors
And you can download the complete snort.conf file that worked for me. Be careful, you need to change IP addresses in the configuration file to match your environment.

Finally, create two empty files, /etc/snort/rules/white_list.rules and /etc/snort/rules/black_list.rules.

Now, you should be able to start Snort, i.e.
# /etc/init.d/snortd start
Starting snort: Spawning daemon child...
My daemon child 1904 lives...
Daemon parent exiting (0)                         [  OK  ]

Tuesday, March 11, 2014

Compiling OVALDI 5.10.1.6 on CentOS 6.5

Some time ago I wrote about compiling Ovaldi on CentOS 6. Now, I tried to compile it again, and I found out that some things changed. Most importantly, there is no need to compile old Xalan/Xerces libraries any more. But, there are still problems with RPM. To make the story short, I managed to compile it and create RPM. Here are the files:
  • patch you need to be able to compile ovaldi
  • SRPM file you can use to recompile ovaldi; it contains patch
  • RPM file if you don't want to compile it yourself (and you trust me ;))
Note that I didn't do any testing at all! So, it might happen that rpm based stuff doesn't work. If that's the case leave a comment and I'll take a look when I find time.

Tuesday, June 18, 2013

Upgrading Alfresco

This is a short note on how I upgraded Alfresco. The basic idea was to just replace WAR files while keeping configuration files with local modifications intact. To be able to do that, I'll unpack WAR archive, integrate changes I made to running instance of Alfresco, create new WAR archives and place them in tomcat webapps folder so that he unpacks and deploys them.

Preparation

So, I downloaded Alfresco 4.2.c. More specifically, I downloaded file alfresco-community-4.2.c.zip. The version I had was 4.0.d.

To find out what configuration files are changed in the running instance I unpacked alfresco.war archive (that file is in the downloaded archive) into a separate directory using unzip command. I suggest that you create directory alfresco, enter that directory and then run unzip command. There, I run the following script:
#!/bin/bash
OLDPATH=/var/lib/tomcat6/webapps/alfresco/
for i in `find . -path ./WEB-INF/classes/alfresco/messages -prune -o -name \*properties -print`
do
        # If file doesn't exist we don't need to check it, go to next one
        [ -f $OLDPATH/$i ] || continue
        # If the old and new files are the same, then skip it also
        cmp -s $OLDPATH/$i $i && continue
        # diff -uN $OLDPATH/$i $i | less
        echo $i
done
The script showed me what files have changed:
./WEB-INF/classes/test/alfresco/test-hibernate-cfg.properties./WEB-INF/classes/alfresco/model/dataTypeAnalyzers_en.properties./WEB-INF/classes/alfresco/workflow/invitation-nominated-workflow-messages_ja.properties./WEB-INF/classes/alfresco/templates/webscripts/org/alfresco/slingshot/wiki/move.post_it.properties./WEB-INF/classes/alfresco/templates/webscripts/org/alfresco/slingshot/wiki/move.post_de.properties./WEB-INF/classes/alfresco/templates/webscripts/org/alfresco/slingshot/wiki/move.post_nl.properties./WEB-INF/classes/alfresco/templates/webscripts/org/alfresco/slingshot/wiki/move.post_es.properties./WEB-INF/classes/alfresco/templates/webscripts/org/alfresco/slingshot/wiki/move.post_fr.properties./WEB-INF/classes/alfresco/templates/webscripts/org/alfresco/slingshot/wiki/move.post_ja.properties./WEB-INF/classes/alfresco/templates/webscripts/org/alfresco/slingshot/wiki/move.post.properties./WEB-INF/classes/alfresco/domain/hibernate-cfg.properties./WEB-INF/classes/alfresco/repository.properties./WEB-INF/classes/alfresco/subsystems/email/OutboundSMTP/outboundSMTP.properties./WEB-INF/classes/alfresco/subsystems/thirdparty/default/swf-transform.properties./WEB-INF/classes/alfresco/subsystems/thirdparty/default/imagemagick-transform.properties./WEB-INF/classes/alfresco/subsystems/fileServers/default/file-servers.properties./WEB-INF/classes/alfresco/subsystems/Synchronization/default/default-synchronization.properties./WEB-INF/classes/alfresco/subsystems/Search/solr/solr-search.properties./WEB-INF/classes/alfresco/subsystems/Search/solr/solr-backup.properties./WEB-INF/classes/alfresco/subsystems/Authentication/ldap-ad/ldap-ad-authentication.properties./WEB-INF/classes/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties./WEB-INF/classes/alfresco/subsystems/Authentication/kerberos/kerberos-authentication.properties./WEB-INF/classes/alfresco/subsystems/Authentication/alfrescoNtlm/alfresco-authentication.properties./WEB-INF/classes/alfresco/subsystems/Authentication/passthru/passthru-authentication-context.properties./WEB-INF/classes/alfresco/subsystems/OOoDirect/default/openoffice-transform.properties./WEB-INF/classes/alfresco/version.properties./WEB-INF/classes/log4j.properties
Of those, localization files are not important (the ones ending in _[a-z][a-z].properties). If you uncomment a line containing less then the script will compare each file and show you difference in less. Based on that, I factored out the following configuration files that were changed:
./WEB-INF/classes/alfresco/repository.properties
./WEB-INF/classes/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties
./WEB-INF/classes/alfresco/subsystems/Authentication/kerberos/kerberos-authentication.properties
./WEB-INF/classes/log4j.properties
I also found that I didn't change mail configuration data in the file:
./WEB-INF/classes/alfresco/subsystems/email/OutboundSMTP/outboundSMTP.properties
The next step was to find what changes are due to local configuration, and which ones are due to the changes in upstream. Namely, I'll take old configuration files but the changes in the new version have to be propagated. It turned out that repository.properties doesn't have any changes, while the other three have. So, I started to change files in the new version of Alfresco, that I unpacked. Finally, when all the changes are done, create new archive:
cd ..
mv alfresco.war alfresco.war.OLD
cd alfresco
zip -9rv ../alfresco .
cd ..
mv alfresco.zip alfresco.war
The first two commands rename old archive, next two create a new archive, and the final command changes name to have extension WAR. I assumed here that you unpacked original WAR archive into directory called alfresco.

All this has to be done with share.war archive too. In my case, the script showed that only log4j.properties has been changed so I incorporated changes and created a modified share.war archive.

Update

Finally, I stopped tomcat, and alfresco using:
service tomcat6 stop
created a copy of existing alfresco and share directories in tomcat's webapp directory. I also renamed old alfresco.war and share.war, and moved the ones I prepared in their place. Take care about permissions, tomcat has to be owner of everything! Then, I started tomcat with:
service tomcat6 start
and also started to pray that it works. Well, almost, I watched logs (/var/log/tomcat6/catalina.out) because I doubt that praying would help. ;)

Everything was OK, i.e. errors that I received (openoffice, pdf2swf) were expected because I didn't inistalled them. But, two errors were not expected:
java.io.FileNotFoundException: alfresco.log (Permission denied)
well, that one was cause by share.war not being able to reopen log file already being used by alfresco.war. So, I changed in appropriate log4j.properties that it uses its own separate log file. Except that it turned that I forgot to change log4j.properties. Anyway, I gave separate log to share.war just to be on a safe side and to finish this finally. The second error was:
java.net.BindException: Permission denied
That one was caused by FTP server not being able to bind to a low numbered port. This is OK, because I'm not running tomcat as a root. So, I'm safe to ignore it.

Tuesday, March 12, 2013

Storing arpwatch output into database

arpwatch is very useful tool which logs its output via syslog and also sends mail alerts. Unfortunately, this isn't configurable, i.e. arpwatch, out-of-the-box, doesn't support any other way of logging.  One approach is to modify arpwatch to be able to log into some SQL database, but this isn't straightforward way, i.e. not an easy one. Namely, arpwatch is written in C, and besides, it's hard to know if this would be accepted by upstream (who ever that migh be).

So, I decided to go with a different approach. I configured arpwatch to log its output into log file and wrote a Python script that executes via cron and transfers all the data into the database. Here is how I did it along with all the scripts.

Configuring logging

The first step is to configure arpwatch to log its output into a separate file. This isn't possible to do in arpwatch itself, but it is possible to achieve it by configuring syslog, or rsyslog to be more precise. On CentOS 6 rsyslog is used that allows just that. All you have to do is to place a file named (for example) arpwatch.conf in directory /etc/rsyslog.d with the following content:
if $programname == 'arpwatch' then /var/log/arpwatch.log
&~
Don't forget to restart rsyslog after that. This will write anything logged by arpwatch binary into /var/log/arpwatch.log file. All the different log lines that can appear are documented in arpwatch's manual page so I won't replicate them here.

Configuring database

In my case I created a single table using the following SQL statement:
CREATE TABLE arpwatch (
  macaddr char(17) NOT NULL,
  ip_addr int(10) unsigned NOT NULL,
  state varchar(8) NOT NULL,
  timestamp datetime NOT NULL,
  oldmac char(17) DEFAULT NULL
)
I think it's pretty obvious what goes where. Only thing that might be strange is that I'm using INT(10) for IP address. But that is because SNORT also stores IP addresses in such a way so in order to be compatible with it I used it also. Also, what is missing is primary key, but for the time being I'm not using it.

Script

Here is the script that should be started from the cron. For example, store it in /usr/local/sbin directory and to start it every 20 minutes add the following line (as root user) to cron using 'crontab -e' command:
*/20 * * * * /usr/local/sbin/arpwatchlog2sql.py
Note that the script expects configuration file. Here is a sample configuration file you'll have to modify. The script expects configuration file to be in its current directory, but you can place it into /usr/local/etc and modify the line CONFIGFILE in script accordingly.

Log rotation

Finally, you should be certain that logs are properly handled, i.e. rotated along with other logs. Since arpwatch is logging via syslog, that means that you have to modify rsyslog's log configuration file, i.e. /etc/logrotate.d/syslog. In there you'll see that logfiles maintained by rsyslog are enumerated, one per line. Just add arpwatch.log to that list and that should be it.

Thursday, November 8, 2012

Installing certificate for Alfresco...

This post is continuation of the post about installing Alfresco using native Tomcat6 installation (on CentOS6). If you followed steps given in that post, you have running Alfresco installation but Tomcat uses self-signed certificate.

To install your own certificate first obtain it (you can use your own, self managed, CA or you can buy commercial one), then install it on your Tomcat instance. You'll find a lot of information about this in SSL Howto on Tomcat's Web pages, but that page assumes that everything you do, you are doing using keytool.

Here is a quick Howto with an assumption that you have files newcert.pem (containing certificate), newkey.pem (containing private key) and cacert.pem (your CA certificate). By default, tomcat's keystore is in its home (/usr/share/tomcat6) and it is named .keystore. Keystore file is password protected and default password for it is changeit. Note that the period isn't part of password! I suggest that you copy this file to root's home under the name keystore (note no leading dot!) or whatever else you wish so that you can restore old copy in case something goes wrong with the following steps.

The installation is two step process. First, you create keystore containing you certificate, private key and CA's certificate. In second step, you import that information to Tomcat's keystore.

First step is to pack certificate for Alfresco, its private key and CA's certificate into PKCS12 store using openssl tool as follows:
$ openssl pkcs12 -export \
        -in newcert.pem -inkey newkey.pem \
        -out mycert.p12 -name tomcat \
        -CAfile cacert.pem -caname root -chain
Enter Export Password:
Verifying - Enter Export Password:
This command assumes that all necessary files (newcert.pem, newkey.pem and cacert.pem) are in you current directory. Output of the command is also stored into current directory. Note that you are asked for password that will protect all the data. Enter something or later you'll see the following warning:
*****************  WARNING WARNING WARNING  *****************
* The integrity of the information stored in the srckeystore*
* has NOT been verified!  In order to verify its integrity, *
* you must provide the srckeystore password.                *
*****************  WARNING WARNING WARNING  *****************
And then you'll receive the following error:
keytool error: java.security.UnrecoverableKeyException: Get Key failed: / by zero
Second step is to import this pkcs12 file to tomcat's keystore using keytool as follows:
$ keytool -importkeystore -srckeystore mycert.p12 \
        -srcstoretype pkcs12 -destkeystore /usr/share/tomcat6/.keystore
Enter destination keystore password:
Enter source keystore password:
Existing entry alias tomcat exists, overwrite? [no]:  yes
Entry for alias tomcat successfully imported.
Import command completed:  1 entries successfully imported, 0 entries failed or cancelled
Again, input file is in the current directory and you are importing directly into tomcat's keystore. Note that the existing certificate with the alias tomcat will be removed and you are asked to confirm that! The default alias Tomcat searches when it start is called tomcat.

Third step is to change private key's password that has to be the same as for the keystore. Do that using the following command:
keytool -keypasswd -alias tomcat -new <keypassword> -keystore /usr/share/tomcat6/.keystore
You'll be asked for the keystore's password and the password for the key will be set to keypassword.

And that's it. Restart tomcat and check if it is using new certificate.

Tuesday, October 30, 2012

Installing ossec client on CentOS 6...

Ok, I did this already, but I managed to forget it. Still, it isn't strange, after all, it's not that you are adding new machines every day. Anyway, here are the steps that are need in order to install OSSEC client on a CentOS machine, more specifically CentOS 6. I decided to write this post if someone also needs these instructions, but certainly for me so that next time I have to do it I don't have to think a lot. Note that I like to install RPM packages because it is easier to update them instead compiling from source, and also someone else is worrying about new releases. Additionally, it's not so good to install development environment on production machines that don't need it, for security reasons. Ok, here we go.

First, make sure that you have EPEL repository added. The easiest way to do this is using the following command (note, bold is what you type, the rest is what you get from the machine):
# rpm -Uvh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
Retrieving http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-7.noarch.rpm
warning: /var/tmp/rpm-tmp.7IMdWB: Header V3 RSA/SHA256 Signature, key ID 0608b895: NOKEY
Preparing...                ##################################### [100%]
1:epel-release   ##################################### [100%]
Second, fetch necessary packages. I didn't want to install Atomicorp's repository, so I only fetched ossec packages using wgetossec-hids and ossec-hids-client are what you need. Select the newest versions you can find. Next, install them using yum command:
# yum localinstall ossec-hids-client-2.6-15.el6.art.x86_64.rpm ossec-hids-2.6-15.el6.art.x86_64.rpm
I assumed that yum is executed in the same directory where you placed downloaded packages. Also, if you downloaded some other versions, change names appropriately.

Open ossec's configuration file, /var/ossec/etc/ossec-agent.conf, and change the line that has <server-ip></server-ip> element. It has to point to your server's IP address. You can also add files to be monitored in addition to the existing ones, or remove some of the existing ones if they are not used on the machine you are installing ossec client.

Now, go to the OSSEC server and run there agent management tool. It is probably in /var/ossec/bin:
# ./manage_agents


****************************************
* OSSEC HIDS v2.5-SNP-100907 Agent manager.     *
* The following options are available: *
****************************************
   (I)mport key from the server (I).
   (Q)uit.
Choose your action: I or Q: A

- Adding a new agent (use '\q' to return to the main menu).
  Please provide the following:
   * A name for the new agent: centos6.domain.local
   * The IP Address of the new agent: 192.168.10.41
   * An ID for the new agent[030]: <just press ENTER>
Agent information:
   ID:030
   Name:centos6.domain.local
   IP Address:192.168.10.41

Confirm adding it?(y/n): y
Agent added.
Note that the tool doesn't display all the options you have on your disposal. Next what you need to do is to extract a key that you'll import into the client. This is also done using manage_clients tool, so either start it again, or in case you didn't exit after you added an agent just continue:
 ****************************************
* OSSEC HIDS v2.5-SNP-100907 Agent manager.     *
* The following options are available: *
****************************************
   (I)mport key from the server (I).
   (Q)uit.
Choose your action: I or Q: e

Available agents:
   ID: 002, Name: somehost, IP: 10.0.10.1
   ID: 030, Name: centos6.domain.local, IP: 192.168.10.41
Provide the ID of the agent to extract the key (or '\q' to quit): 030
Agent key information for '030' is:
<here a very long string will be printed>
** Press ENTER to return to the main menu.
Again, option to export the key isn't listed in the help message! Anyway, copy the very long string that is printed (agent's key) and you can quit from the tool and logout from the OSSEC server.

Go now to ossec client, change directory to /var/ossec/bin and run manage_client tool:
# ./manage_client


****************************************
* OSSEC HIDS v2.6 Agent manager.     *
* The following options are available: *
****************************************
   (I)mport key from the server (I).
   (Q)uit.
Choose your action: I or Q: I

* Provide the Key generated by the server.
* The best approach is to cut and paste it.
*** OBS: Do not include spaces or new lines.

Paste it here (or '\q' to quit):
<very long string copied here!>

Agent information:
   ID:030
   Name:centos6.domain.local
   IP Address:192.168.10.41

Confirm adding it?(y/n): y
Added.
Finally, restart ossec client:
# /etc/init.d/ossec-hids restart
Shutting down ossec-hids:                      [  OK  ]
Starting ossec-hids:                           [  OK  ]
You should see you new client in OSSEC's Web interface which should confirm that it is running OK.

Thursday, July 26, 2012

Searching for packet catpuring and interface manipulation library for Python...

I needed a script that would monitor network traffic and capture and process only DHCP traffic. It turned out I couldn't find such script so I decided to write one (more about that script in another post). For a language I decided to use Python. That was the easy part. Now, I had to decide which libraries I will use that will allow me to capture network traffic, decode DHCP request and responses, and manipulate IP addresses on interfaces.

I started with the network traffic capturing. pcap library is the library for network capture, so it was natural for me to search for a Python interface to this library. I found several such interfaces, i.e. pcap, pylibpcap, pypcap, and pcapy. There is also library interface specifically for Python 3, i.e. py3kcap. While searching for pcap interface, three other Python libraries poped out: libdnet (here is the old project page), dpkt and scapy.

But, not all libraries are equal, nor they serve the same purpose. libdnet allows sending packets, manipulation with kernel's routing tables, firewall and arp cache. So, besides Ethernet and IP, it doesn't offer much more in term of supported protocols. dpkt, on the other hand, is made just for this purpose! It supports easy creation and parsing of different TCP/IP protocols. Finally, Scapy is a swiss army knife of network manipulation. It offers shell in which one can manipulate packets, but also can be used within other scripts. Unfortunately, while browsing the source of Scapy I realized that it uses os.popen interface and calls external programs. So, this actually was enough for me to eliminate scapy from further consideration.

The next elimination criteria is availability of the packages within CentOS and Fedora. I try to hold on prepackaged software as much as possible, so quick search (yum search) showed that on both, CentOS 6 and Fedora 17, there are packages for pcapy and dpkt (named python-dpkt). For some reason, there is dnet, but python interface isn't packaged. I found this bugzilla entry, but without any answer!

So, I settled on pcapy and dpkt. The only piece of puzzle that was missing now is how to manipulate interface addresses. I stumbled on netifaces, which allows me to obtain information about interfaces and also on this post for Windows. But all the results I got were on how to obtain IP address. In the end, I gave up and decided that I'll try to use libdnet even though I'll have to compile it from the source. Either that, or I'll use raw sockets and ioctls which are accessible from Python using standard libraries.

And for the end, as a curiosity, I'll mention that there is Python interface to IPTables, python-iptables, which is also packaged for Fedora.

Tuesday, July 24, 2012

ntop 5 on CentOS 6...

Last week I decided to install ntop on one of my CentOS 6 machines and, to much of my surprise, it turned out that there is no ntop package in the standard CentOS6 repositories (i.e. Base, EPEL, RPMFusion). Then, I looked into Fedora repository and it turned out that there is package, but for the older version, i.e. 4.0 (the newest version of ntop at the time this post was written was 5.0). So, I downloaded that older version, placed new version of ntop, modified a bit SPEC file and tried to build it. It didn't work intermediately, but after few more tweaks it worked. I filled a bug report on RedHat's bugzilla so that maintainter can upgrade a package, if he wishes so.

In the mean time, I decided to build package for CentOS 6. The main problem is that Fedora introduced Systemd instead of traditional SysV init used by CentOS. To cut the story short, I managed to do that, too. The resulting SPEC file can be used in both Fedora and EPEL6. I uploaded new SPEC file (and init file) to bugzilla, so you can fetch them there if you wish.

Until maintainers decide what to do, and if anything to do with it, here are the SRPM file and resulting binary RPM file for 64-bit CentOS6.

Friday, July 20, 2012

Integrating FreeIPA and Alfresco...

After describing how to install CentOS, DNS and reverse DNS, FreeIPA and Alfresco, in this post I'm going to describe how to integrate Alfresco with FreeIPA. I want to achieve the following goals with the integration:
  • Users and groups are kept within FreeIPA and authentication is done by FreeIPA.
  • Alfresco Web interface honors Kerberos tickets. Upon opening Web interface users are immediately presented with their pages withoug necessity for authentication (if, of course, they have valid Kerberos tickets).
  • Authentication when mounting DAV share is also done via Kerberos tickets.
In short, I want to achieve SSO (Single Sign-On) as much as possible. Users sign in when they start to use their workstations once, that's the only time they have to enter password.

Tuesday, July 17, 2012

Zimbra log cluttering...

When you run Zimbra, logs generated by it are duplicated in system log files (i.e. /var/log/messages, or /var/log/secure) but also in Zimbra specific log files (i.e. /var/log/zimbra.log). The problem with this is that it clutters system logfiles, i.e. takes unnecessary space and makes them hard to analyze. So, it would be good to make Zimbra log only in its own specific log files.

Googling for solution I found this post but with no satisfactory solution. Since there was no ready solution, I turned to Googling on how to configure rsyslog to do that. Namely, CentOS (on which I'm running Zimbra) uses rsyslog as a replacement for a more traditional syslog. It turns out it is possible to filter according to application doing logging.

So, two offending applications are zimbramon and zmmailboxdmgr. In order to prevent them from logging into /var/log/messages add the following lines before section RULES (that resemble classical syslog rules):
if $programname == 'zimbramon' then /var/log/zimbra-stats.log
& ~

if $programname == 'zmmailboxdmgr' then /var/log/zimbra-stats.log
& ~
The first two lines will redirect zimbramon messages, while the second two will do the same for zmmailboxdmgr.

Thursday, June 28, 2012

Installing Alfresco Community Edition on minimal CentOS...

In this post I'm going to describe how to install Alfresco Community Edition 4.0d starting with a minimal CentOS 6 installation. This will be a two part post after which I'm going to describe how to integrate Alfresco with FreeIPA for authentication and authorization purposes. The goal of the installation is to use as much as possible software available in CentOS. The reason for doing so is that update process is easier, i.e. you only have to do yum update instead of manually downloading and installing updated software.

Environment and Configuration Parameters


I assume that you have CentOS installation ready. If not, then install it, and if you need some info on how to do it, look at this post. Furthermore, I assume that Alfresco should reside within Intranet, i.e. local network. The reason is that there is no need for Alfresco to be accessible from the Internet and thus it doesn't have to be in DMZ. I'll assign IP address 172.16.1.3 to this host. The FQDN of the host will be alfresco.example-domain.local. Now, if you have working DNS you should put this name into DNS, but it's not necessary, i.e. you can put it into /etc/hosts file of any host that will access Alfresco (including Alfresco itself) and that will do for now.

Alfresco needs a relational database. I'm going to use MySQL database. Furhtermore, I'll assume that this database is on the same host as Alfresco. This will allow me to restrict access to database. Unfortunately, standard JDBC driver for MySQL doesn't support access to database via Unix socket, so database has to be accessible via network stack. I'm going to restrict it to loopback interface.

Note that I started with the following state of disk usage:
# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda1             7,0G  944M  5,7G  15% /

Prerequisite software installation


As for the prerequsite software you have to install the following packages (all of them shipped with CentOS):
  • java-1.6.0-openjdk - unless you explicitly specify which java you want to be installed, gcc's version will be used and that one won't work with Alfresco.
  • tomcat6 - servlet container that will run Alfresco. It is mandatory to install this package. This, along with dependencies, will be 129M to download and will take about 382M disk space.
  • mysql-server - this is a package that holds server part of MySQL database.
  • mysql-connector-java - JDBC connector that will allow Alfresco to access MySQL database.
  • unzip - so that you can unpack Alfresco archive (which is distributed as a zip file)
So, install it using yum. This will download 168M which will expand into 503M. Afterwards, this is the state of disk usage:
# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda1             7,0G  1,6G  5,1G  24% /

Configure MySQL database


We also have to prepare MySQL database, i.e. you have to do the following steps:
  1. Configure database to use UTF-8 by default.
  2. Configure it to listen only on loopback interface.
  3. Start database and set root password.
  4. Create alfresco database.
  5. Create alfresco user and assign it a password.
  6. Configure system to start MySQL database during the boot process.
The first two steps are done by editing /etc/my.cnf file. Integrate the following lines with the already existing content (i.e. to existing sections add missing lines, if the section doesn't exist in my.cnf file add it along with all its lines):
[client]
default-character-set=utf8

[mysql]
default-character-set=utf8

[mysqld]
bind-address=127.0.0.1
character-set-server = utf8
collation-server = utf8_unicode_ci
init-connect='SET NAMES utf8'
character-set-server = utf8
Note that MySQL has to listen on loopback because JDBC doesn't allow connection via Unix socket, at least not without tweaks to Alfresco code itself.

Step 3 (i.e. set root password) is done by starting MySQL server and then setting password:
/etc/init.d/mysqld start
/usr/bin/mysqladmin -u root password 'new-password'
String 'new-password' replace with your password (and keep quotes, they prevent shell from interpreting any special character in password you might have!). You should be careful with this password as it is very critical peace of information!

Step 4 and 5 (create alfresco database and user) are done using mysql tool. So, first start this tool:
# mysql -u root -p
Enter password: <type here root password>
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.1.61 Source distribution

Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
and now create database:
mysql> create database alfresco;
Query OK, 1 row affected (0.00 sec)
and grant alfresco user all permissions on the database:
mysql> grant all privileges on alfresco.* to alfresco@localhost identified by 'PASSWORD';
Query OK, 0 rows affected (0.00 sec)
The word PASSWORD should be replaced with a password. Again, this one is critical since all the data will be accessible if someone gets hold on that password. And, while you are at that, remove test database as it is not necessary and might even present security threat:
mysql> drop database test;
Query OK, 0 rows affected (0.00 sec)
That's it as far as mysql client is concerned. So, leave it using exit keyword.

Finally, we should configure system to start MySQL database on each boot. This is easily done with:
chkconfig mysqld on
OK, so much about database. One more thing before going to Alfresco installation. You have to configure tomcat so that it loads MySQL connector when starting, otherwise Alfresco won't be able to connect to database! To to that, open file /etc/tomcat6/catalina.properties and search for line "shared.loader=". Add to that line string /usr/share/java/mysql-connector-java.jar, i.e. it shoud look now like this:
shared.loader=/usr/share/java/mysql-connector-java.jar
Save the file and exit and that's it. Now on to Alfresco itself.

Alfresco Installation


First, go to Alfresco download site and download Community edition, i.e. download file alfresco-community-4.0.d.zip. Then, unpack it (using unzip tool) into a temporary directory:
mkdir tmp
cd tmp
unzip ../alfresco-community-4.0.d.zip
<unzip progress output>
You'll have now few new directories. From directory web-server/webapps move files alfresco.war and share.war into tomcat webapps directory, i.e. into /var/lib/tomcat6/webapps. From now on, I'm going to reference that directory as $WEBAPPS, to shorten a bit typing. Now, start wait a minute and then stop tomcat server. This is so that it unpacks alfresco and share war archives:
/etc/init.d/tomcat6 start
/etc/init.d/tomcat6 stop
In case you receive ERROR message trying to stop tomcat, wait a bit more and then try again. Namely, until tomcat finishes initialization you can not stop it.

Note also that tomcat writes its logs into /var/log/tomcat6. You should monitor that directory when starting tomcat. More specifically, watch catalina.out file. Furthermore, the tip, I remove all log files before starting tomcat again so that it doesn't clutter new log messages with the old ones. Of course, I'm doing that only during installation phase. Later, it is very good idea to keep the logs around!

Go now into directory  $WEBAPPS/alfresco/WEB-INF/classes. There, you'll see file alfresco-global.properties.sample. Copy this file into alfresco-global.properties and change permissions to a more restrictive values:
cp alfresco-global.properties.sample alfresco-global.properties
chmod 600 alfresco-global.properties
and open it in editor. In there do the following:
  1. Immediately at the beginning uncomment lines  dir.root and dir.keystore. Set dir.root to a directory where Alfresco will store data. I used /var/lib/alf_data (which of course, should be created manually!) but any value with enough storage will do. Also, change the owner of that directory to tomcat and restrict access permissions so that only user tomcat can enter into that directory (use permissions 700). dir.keystore should be set to $WEBAPPS/alfresco/WEB-INF/classes/alfresco/keystore.
  2. Uncomment lines db.username and db.password and set correct value for password (username is alfresco so that shouldn't be necessary to change). This password in plain text is the reason you had to change permissions of the file.
  3. Find MySQL section, and in particular lines there db.driver and db.url and uncomment them. Change the value of db.driver to com.mysql.jdbc.Driver.
Now, open file log4j.properties that is in the same directory as the previous file, i.e. $WEBAPPS/alfresco/WEB-INF/classes. Find there the following line:
log4j.appender.File.File=alfresco.log
And change it to:
log4j.appender.File.File=/var/log/tomcat6/alfresco.log
This line specifies where Alfresco will do its logging. The obvious place is the same directory where tomcat places its logs. Do the same change in file $WEBAPPS/share/WEB-INF/classes/log4j.properties.

Now, start tomcat again and try to open the following URL in a Web browser: http://alfresco.example-domain.com:8080/alfresco. After a bit of wait you should be presented with a guest Alfresco home page. You can then logout and login as admin (U: admin/P: admin). Note that if you can not connect, the reason is firewall on Alfresco server. Temporarily turn off the firewall with:
/etc/init.d/iptables stop
and then try again.

Don't forget to configure system so that tomcat is started after each reboot. Anyway, this is the first part of the installation. There are some more tweaks you should do that I'm going to describe in the following post. For the end of this post let me show the disk usage:
# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda1             7,0G  2,1G  4,6G  31% /

Tuesday, June 26, 2012

Installing FreeIPA on minimal CentOS installation..

This post is a continuation on a minimal CentOS6 installation. The goal is to install FreeIPA that will be used as authentication and authorization server for Zimbra and Alfresco.

Environment and parameters


Referring to a figure given in a post about minimal CentOS6 installation, IPA server will be placed within a local network. Actually, it should be placed within separate network along with other servers not accessible from the Internet. But because I have only DMZ and one LAN segment for workstations and to keep things simple, obviously the local network is the place to go. So, based on that, the following parameters will be used:
  • The IP address of FreeIPA server will be 172.16.1.2/24.
  • FQDN name will be ipa.example-domain.local. Note the domain name of the local network!
  • Kerberos REALM will be EXAMPLE-DOMAIN.COM.
I'm also assuming that you already have working DNS server, with both forward and reverse queries working! If you don't, you should first configure DNS (and then configure reverse DNS, too) and then proceed with FreeIPA. Of course, the two can be hosted on the same host, but for my scenario, DNS is with mail server in DMZ as it is accessible from the Internet, while FreeIPA is on a separate host in local network.

Software installation


The first step is to install base OS as specified in the post about minimal CentOS6 installation. Note that some things, like IP address, host name and DNS server should be appropriately changed!

After the base OS installation is finished next step is to install necessary software. So, install ipa-server package using yum:
yum -y install ipa-server 
This will result in installation of hefty set of dependencies, somewhere around 190M to download which will take aproximatelly 572M after installation. Anyway, disk usage after IPA server installation looks something like this:
# df
Filesystem  1K-blocks      Used Available Use% Mounted on
/dev/sda1     7739864   1600788   5745912  22% /

Sever configuration


Now, start server configuration program. Here is the transcript of installation I did:
# ipa-server-install

The log file for this installation can be found in /var/log/ipaserver-install.log
==============================================================================
This program will set up the IPA Server.

This includes:
  * Configure a stand-alone CA (dogtag) for certificate management
  * Configure the Network Time Daemon (ntpd)
  * Create and configure an instance of Directory Server
  * Create and configure a Kerberos Key Distribution Center (KDC)
  * Configure Apache (httpd)

To accept the default shown in brackets, press the Enter key.

Enter the fully qualified domain name of the computer
on which you're setting up server software. Using the form
<hostname>.<domainname>
Example: master.example.com.


Server host name [ipa.example-domain.local]:

The domain name has been calculated based on the host name.

Please confirm the domain name [example-domain.local]:

The IPA Master Server will be configured with
Hostname:    ipa.example-domain.local
IP address:  192.0.2.2
Domain name: example-domain.local

The kerberos protocol requires a Realm name to be defined.
This is typically the domain name converted to uppercase.

Please provide a realm name [EXAMPLE-DOMAIN.LOCAL]: EXAMPLE-DOMAIN.COM
Certain directory server operations require an administrative user.
This user is referred to as the Directory Manager and has full access
to the Directory for system management tasks and will be added to the
instance of directory server created for IPA.
The password must be at least 8 characters long.

Directory Manager password: <enter password>
Password (confirm): <enter password>

The IPA server requires an administrative user, named 'admin'.
This user is a regular system account used for IPA server administration.

IPA admin password: <enter password>
Password (confirm): <enter password>


The following operations may take some minutes to complete.
Please wait until the prompt is returned.

Configuring ntpd
  [1/4]: stopping ntpd
  [2/4]: writing configuration
  [3/4]: configuring ntpd to start on boot
  [4/4]: starting ntpd
done configuring ntpd.
Configuring directory server for the CA: Estimated time 30 seconds
  [1/3]: creating directory server user
  [2/3]: creating directory server instance
  [3/3]: restarting directory server
done configuring pkids.
Configuring certificate server: Estimated time 3 minutes 30 seconds
  [1/17]: creating certificate server user
  [2/17]: creating pki-ca instance
  [3/17]: configuring certificate server instance
  [4/17]: disabling nonces
  [5/17]: creating CA agent PKCS#12 file in /root
  [6/17]: creating RA agent certificate database
  [7/17]: importing CA chain to RA certificate database
  [8/17]: fixing RA database permissions
  [9/17]: setting up signing cert profile
  [10/17]: set up CRL publishing
  [11/17]: set certificate subject base
  [12/17]: configuring certificate server to start on boot
  [13/17]: restarting certificate server
  [14/17]: requesting RA certificate from CA
  [15/17]: issuing RA agent certificate
  [16/17]: adding RA agent as a trusted user
  [17/17]: Configure HTTP to proxy connections
done configuring pki-cad.
Configuring directory server: Estimated time 1 minute
  [1/35]: creating directory server user
  [2/35]: creating directory server instance
  [3/35]: adding default schema
  [4/35]: enabling memberof plugin
  [5/35]: enabling referential integrity plugin
  [6/35]: enabling winsync plugin
  [7/35]: configuring replication version plugin
  [8/35]: enabling IPA enrollment plugin
  [9/35]: enabling ldapi
  [10/35]: configuring uniqueness plugin
  [11/35]: configuring uuid plugin
  [12/35]: configuring modrdn plugin
  [13/35]: enabling entryUSN plugin
  [14/35]: configuring lockout plugin
  [15/35]: creating indices
  [16/35]: configuring ssl for ds instance
  [17/35]: configuring certmap.conf
  [18/35]: configure autobind for root
  [19/35]: configure new location for managed entries
  [20/35]: restarting directory server
  [21/35]: adding default layout
  [22/35]: adding delegation layout
  [23/35]: adding replication acis
  [24/35]: creating container for managed entries
  [25/35]: configuring user private groups
  [26/35]: configuring netgroups from hostgroups
  [27/35]: creating default Sudo bind user
  [28/35]: creating default Auto Member layout
  [29/35]: creating default HBAC rule allow_all
  [30/35]: initializing group membership
  [31/35]: adding master entry
  [32/35]: configuring Posix uid/gid generation
  [33/35]: enabling compatibility plugin
Restarting IPA to initialize updates before performing deletes:
  [1/2]: stopping directory server
  [2/2]: starting directory server
done configuring dirsrv.
  [34/35]: tuning directory server
  [35/35]: configuring directory to start on boot
done configuring dirsrv.
Configuring Kerberos KDC: Estimated time 30 seconds
  [1/14]: setting KDC account password
  [2/14]: adding sasl mappings to the directory
  [3/14]: adding kerberos entries to the DS
  [4/14]: adding default ACIs
  [5/14]: configuring KDC
  [6/14]: adding default keytypes
  [7/14]: adding default password policy
  [8/14]: creating a keytab for the directory
  [9/14]: creating a keytab for the machine
  [10/14]: exporting the kadmin keytab
  [11/14]: adding the password extension to the directory
  [12/14]: adding the kerberos master key to the directory
  [13/14]: starting the KDC
  [14/14]: configuring KDC to start on boot
done configuring krb5kdc.
Configuring ipa_kpasswd
  [1/2]: starting ipa_kpasswd
  [2/2]: configuring ipa_kpasswd to start on boot
done configuring ipa_kpasswd.
Configuring the web interface: Estimated time 1 minute
  [1/13]: disabling mod_ssl in httpd
  [2/13]: setting mod_nss port to 443
  [3/13]: setting mod_nss password file
  [4/13]: enabling mod_nss renegotiate
  [5/13]: adding URL rewriting rules
  [6/13]: configuring httpd
  [7/13]: setting up ssl
  [8/13]: setting up browser autoconfig
  [9/13]: publish CA cert
  [10/13]: creating a keytab for httpd
  [11/13]: configuring SELinux for httpd
  [12/13]: restarting httpd
  [13/13]: configuring httpd to start on boot
done configuring httpd.
Applying LDAP updates
Restarting IPA to initialize updates before performing deletes:
  [1/2]: stopping directory server
  [2/2]: starting directory server
done configuring dirsrv.
Restarting the directory server
Restarting the KDC
Restarting the web server
Sample zone file for bind has been created in /tmp/sample.zone.OHH8V_.db
==============================================================================
Setup complete

Next steps:
    1. You must make sure these network ports are open:
        TCP Ports:
          * 80, 443: HTTP/HTTPS
          * 389, 636: LDAP/LDAPS
          * 88, 464: kerberos
        UDP Ports:
          * 88, 464: kerberos
          * 123: ntp

    2. You can now obtain a kerberos ticket using the command: 'kinit admin'
       This ticket will allow you to use the IPA tools (e.g., ipa user-add)
       and the web user interface.

Be sure to back up the CA certificate stored in /root/cacert.p12
This file is required to create replicas. The password for this
file is the Directory Manager password
As you can see the process is quite automated.

Postinstallation steps


There are few more things that have to be done before clients can be configured. Note the italic text almost at the end of the transcript? It says that there is a file with data you should place in your DNS server. The file is only example, and basically it defines the whole zone. But since we already have working zone, we only need the IPA related part, i.e. without SOA, NS and A records. That would be the following fragment:
; ldap servers
_ldap._tcp              IN SRV 0 100 389        ipa

;kerberos realm
_kerberos               IN TXT EXAMPLE-DOMAIN.TXT

; kerberos servers
_kerberos._tcp          IN SRV 0 100 88         ipa
_kerberos._udp          IN SRV 0 100 88         ipa
_kerberos-master._tcp   IN SRV 0 100 88         ipa
_kerberos-master._udp   IN SRV 0 100 88         ipa
_kpasswd._tcp           IN SRV 0 100 464        ipa
_kpasswd._udp           IN SRV 0 100 464        ipa

;ntp server
_ntp._udp               IN SRV 0 100 123        ipa
Basically, these records define services provided by IPA so that they are discoverable by DNS. All the services (or server - SRV - records) consist of two parts, the first one defines service name with prepended underscore while the second part defines transport protocol, also with prepended underscore. So, for example, there is LDAP over TCP protocol (_ldap._tcp) which listens on port 389 (standard LDAP port) on IPA host. Anyway, place those lines in example-domain.local, and in internal view of example-domain.com zone files. Don't forget to change serial number of zone file and to restart BIND after the change.

It's time to test that IPA is working correctly. First, request ticket for user admin:
# kinit admin
Password for admin@EXAMPLE-DOMAIN.COM:
You are asked password that you entered during installation process! Anyway, you shouldn't receive any message and that means you were issued ticket. To check ticket, use klist command:
# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: admin@EXAMPLE-DOMAIN.COM

Valid starting     Expires            Service principal
06/26/12 17:43:05  06/27/12 17:43:01  krbtgt/EXAMPLE-DOMAIN.COM@EXAMPLE-DOMAIN.COM
If you got output as shown (or similar) then IPA is working correctly. Note that when you have to do something with IPA (using command line tool ipa) you are authorized (and authenticated) with the ticket. So, for example, when you are adding new user, you need to have valid admin ticket.

Client installation


Finally, we'll describe setup of a client, more specifically, Firefox browser. This is necessary so that you can use Web interface to administer IPA server. Two things have to be done. First, you have to edit /etc/krb5.conf file. The content of that file should look like this:

[logging]
        default = FILE:/var/log/krb5libs.log
        kdc = FILE:/var/log/krb5kdc.log
        admin_server = FILE:/var/log/kadmind.log
[libdefaults]
        default_realm = EXAMPLE-DOMAIN.COM
        dns_lookup_realm = false
        dns_lookup_kdc = false
        ticket_lifetime = 24h
        renew_lifetime = 7d
        forwardable = true
[realms]
        EXAMPLE-DOMAIN.COM = {
                kdc = ipa.example-domain.local
                admin_server = ipa.example-domain.local
        }
[domain_realm]
        .example-domain.hr = EXAMPLE-DOMAIN.COM
        example-domain.hr = EXAMPLE-DOMAIN.COM
        .example-domain.local = EXAMPLE-DOMAIN.COM
        example-domain.local = EXAMPLE-DOMAIN.COM
Basically, in this file you define default realm (so that you can write kinit admin, instead of full kinit admin@EXAMPLE-DOMAIN.COM), and you also define KDC server for this real (under realm section). Finally, you define mapping from domain names to realm. In our case, we have a single realm that is valid in all domains. Note that it is possible to use DNS to resolve much of the information we gave in the configuration file but I'm not using that feature currently (dns_lookup_* = false). There is one more reason I'm not using DNS resolution. Namely, while my IPA and DNS servers are virtual machines, I'm using my physical laptop as a client and I don't want to change DNS server for laptop or otherwise half of the things would stop working. :) Oh, yeah, if you are doing the same, don't forget to put name ipa.example-domain.local into /etc/hosts on a laptop. Otherwise, you'll get the following error message:

$ kinit admin
kinit: Cannot contact any KDC for realm 'EXAMPLE-DOMAIN.COM' while getting initial credentials
This actually means that the KDC host name isn't resolvable. If you get the following error message:

$ kinit admin
Password for admin@EXAMPLE-DOMAIN.COM:
kinit: Clock skew too great while getting initial credentials
That means that the clock on one of the machines (KDC or your laptop, or both) is wrong and the difference is too large. So, check and fix clocks. Finally, when everything is OK, you should get no error messages:

$ kinit admin
Password for admin@EXAMPLE-DOMAIN.COM: 
And you can use klist to very that you really got ticket. This ticket is important because without it Web application won't let you access it. Ok, now Firefox configuration. This is done via Firefox browsing, so it's easy. :)

Open Firefox and type IPA server's IP address (or name) into URL location. The first thing you are asked is to import untrasted certificate because you are switched to HTTPS connection. When you've done that you'll receive dialog box that informs you that you have to import CA from IPA server. During the import process it is very important to select all check boxes! Otherwise, the next step won't work! Ok, the next step is automatic configuration of Firefox configuration to allow kerberos ticket forwarding to remote host. When it's done reload page and you should have access to adminstration interface.

I had a problem with some internal error by Web application. It turned out that my laptop used IP address that Web application couldn't resolve to name (via reverse DNS), and then to realm. I had to enter laptop name and IP address into DNS server. Also, be careful that you use the correct DNS server on IPA server.

So, that's it for this post. :)



Setting up reverse DNS server...

In the post about DNS configuration I skipped reverse DNS configuration. But, it is necessary to have it in some cases, like FreeIPA installation or for mail servers. So, I'm going to explain how to configure reverse DNS server.

While "normal" DNS resolution works by names, from root server down to the authoritative one for the name we are looking for, reverse DNS resolution works within special top-level domain (in-addr.arpa). Within this domain, sub-domains are comprised from octets within IP address in reverse order. Now, if your block of IP addresses ends on byte boundary (e.g. /8, /16, /24) the setup is relatively simple. Otherwise, you upstream provider (the one that holds larger IP address block) has to point to your domain on a per address base.

Let us bring this to more concrete values. Suppose that our public IP address space is 192.0.2.0/24. Also, suppose that your mail server has public IP address 192.0.2.2. In that case, reverse query is sent for name 2.2.0.192.in-addr.arpa and query type is set to PTR, i.e. we are looking for a name 2 within 2.0.192.in-addr.arpa zone.

So, it's relatively easy to setup reverse DNS. You need to define appropriate zones that include only network part of your IP addresses. In our case we have two zones, but IP addresses used for one of them depends on who's asking (client from the local network or client on the Internet). So, we have three zones in effect:
  1. DMZ, when asked by local clients, is in the network 10.0.0.0/24. This means we have reverse zone 0.0.10.in-addr.arpa for local clients.
  2. DMZ, when asked by internet clients, is in the network 192.0.2.0/24. This means that for them reverse zone is 2.0.192.in-addr.arpa.
  3. Finally, clients in local network (non-DMZ one) have IP addresses from a block 172.16.1.0/24 and so they are placed within reverse zone 1.16.172.in-addr.arpa.
So, within internal view you should add the following two zone statements:
zone "0.0.10.in-addr.arpa" {
    type master;
    file "example-domain.com.local.rev";
};

zone "1.16.172.in-addr.arpa" {
    type master;
    file "example-domain.local.rev";
};
And within internet view you should add the following zone statement:
zone "2.0.192.in-addr.arpa" {
   type master;
    file "example-domain.com.rev";
};
Then, you should create the three zone files (example-domain.com.local.rev, example-domain.local.rev, and example-domain.com.rev) with the following content:
# cat example-domain.com.local.rev
 $TTL 1D
@    IN    SOA    @ root.example-domain.com. (
            2012062601 ; serial
            1D         ; refresh
            1H         ; retry
            1W         ; expire
            3H )       ; minimum
           NS    ns1.example-domain.com.

1          PTR    ns1.example-domain.com.
# cat example-domain.local.rev
 $TTL 1D
@    IN    SOA    @ root.example-domain.com. (
            2012062601 ; serial
            1D         ; refresh
            1H         ; retry
            1W         ; expire
            3H )       ; minimum
           NS    ns1.example-domain.com.

1          PTR    test.example-domain.local.
# cat example-domain.com.rev
$TTL 1D
@    IN    SOA    @ root.example-domain.com. (
            2012062601 ; serial
            1D         ; refresh
            1H         ; retry
            1W         ; expire
            3H )    ; minimum
           NS    ns1.example-domain.com.

1          PTR    ns1.example-domain.com.
Don't forget to change permissions on those files as explained in the previous post. Now, restart BIND and test server:
# nslookup ns1.example-domain.com 127.0.0.1
Server:  127.0.0.1
Address: 127.0.0.1#53

Name:    ns1.example-domain.com
Address: 10.0.0.1
[root@ipa ~]# nslookup 10.0.0.1 127.0.0.1
Server:  127.0.0.1
Address: 127.0.0.1#53

1.0.0.10.in-addr.arpa    name = ns1.example-domain.com.
As it can be seen, DNS server correctly handles request for IP addres 10.0.0.1 and returns ns1.sistemnet.hr. Let's try with a name from LAN:
# nslookup test.example-domain.local 127.0.0.1
Server:  127.0.0.1
Address: 127.0.0.1#53

Name:    ipa.example-domain.local
Address: 192.0.2.1

[root@ipa named]# nslookup 192.0.2.1 127.0.0.1
Server:  127.0.0.1
Address: 127.0.0.1#53

1.2.0.192.in-addr.arpa    name = test.example-domain.local
That one is correct too. So, that's it, you have reverse DNS correctly configured. Testing from the outside I'm leaving to you as an exercise. ;)

Monday, June 25, 2012

Setting up DNS server...

In the previous post I described how to install minimal CentOS distribution with some additional useful tools. In this part I'm going to describe how to install DNS server. This DNS server will exhibit certain behavior depending on where the client is, in other words we are going to setup split DNS. Note that since DNS server is accessible from the Internet, it is placed in DMZ network, i.e. 10.0.0.0/24.

Environment and configuration parameters


In the following text we assume network topology from the previous post, but we need some additional assumptions and requirements before going further. First, our public domain is example-domain.com and all hosts within DMZ will belong to that zone, i.e. FQDN of mail server will be mail.example-domain.com. But, when some client from the Internet asks for certain host, e.g. mail.example-domain.com DNS server will return public IP address. On the other hand, when client from a local network, or even DMZ, asks for the same host private IP address will be returned, i.e. 10.0.0.2. The reason for such behavior is more efficient routing. In other words, if client from a local network would receive public IP address, then all the traffic would have to be NAT-ed. We'll also assume that we are assigned a public block of IP addresses 192.0.2.0/24.

There will be  also additional domain example-domain.local in which all the hosts from the local domain will be placed. Additionally, this domain will be visible only from the local network and DMZ, it will not exist for clients on the Internet.

To simplify things we are not going to install secondary DNS server nor we are going to install reverse zones. For a test purposes this is OK, but if you are doing anything serious, you should definitely install slave DNS servers (or use someone's service) and configure reverse zones. Also, I completely skipped IPv6 configuration and DNSSEC configuration.

Installation of necessary packages


There are a number of DNS server implementations to choose from. The one shipped with CentOS is BIND. It is the most popular DNS server, with most features, but, in the past it had a lot of vulnerabilities. Nevertheless, we'll use that one. Maybe sometime in future, I write something about alternatives, too.

So, the first step, is to install necessary packages:
yum install bind.x86_64 bind-chroot.x86_64 bind-utils.x86_64
Server itself is in bind package, bind-chroot is used to confine server to alternative root filesystem in case it is compromised. Finally, bind-utils contains utilities we need to test server. This is 4.1M of download data, and it takes around 7M after installation. Not much.

Note that it is a good security practice to confine server into alternative root. As I already said, in the past bind had many vulnerabilities, and in case new one is discovered and exploited, we want to minimize potential damage.

That's all about installation.

Configuration

Next, we need to configure server before starting it. Main configuration file for bind is /etc/named.conf . So, open it with your favorite editor as we are going to make some changes in it. Remember that our domain is called example-domain.com and that we want private addresses to be returned for internal clients, and public ones for external clients. Additionally, we have a local domain example-domain.local. Here is the content of the /etc/named.conf file:
acl lnets {
    10.0.0.0/24;
    172.16.1.0/24;
    127.0.0.0/8;
};

options {
  listen-on port 53 { any; };
  directory     "/var/named";
  dump-file     "/var/named/data/cache_dump.db";
  statistics-file "/var/named/data/named_stats.txt";
  memstatistics-file "/var/named/data/named_mem_stats.txt";
  allow-update     { none; };
  recursion no;

  dnssec-enable no;
};

view "internal" {
    match-clients { lnets; };
    recursion yes;

    zone "." IN {
        type hint;
        file "named.ca";
    };

    zone "example-domain.local" {
        type master;
        file "example-domain.local";
    };

    zone "example-domain.com" {
        type master;
        file "example.domain.local";
    };

    include "/etc/named.rfc1912.zones";
};

view "internet" {
    match-clients { any; };
    recursion no;

    zone "example-domain.com" {
        type master;
        file "example-domain.com";
    };
};
Let me now explain what this configuration file actually specifies. In global, there are four blocks, i.e. acl, options, and two view blocks.

acl block (or blocks, because there may be more such statements) specifies some symbolic name that will refer to group of addresses.  This is good from maintenance perspective because there is only one place where something is defined. In our case, we define our local networks, i.e. DMZ and local LAN. There is also loopback address because when some application on DNS server itself asks something, DNS server should treat it as if it is coming from a local network.

Next is an option block. In our case we specify that DNS server should listen (listen-on) port 53 on any IP address (any). In case you want to restrict on which addresses DNS server listens, you can enumerate them here instead of any keyword. Better yet, create ACL and use symbolic name. In option block we also disabled DNSSEC (dnssec-enable no), disabled updates to server (allow-update no), and disabled recursion (recursion no). Apart from that we defined directories, e.g. for zone files.

Finally, there are two view statements. They define zones depending on where the client asking is. If it is on the local networks, then first view (i.e. internal) is consulted, and if the client is anywhere else, then the second view is consulted (i.e. internet). match-clients statement classifies clients, and it is here that we use our ACL lnets. When query arrives, the source address from the packet is taken and compared to match-clients. The first one that matches is used. So, it is obvious that the second view matches anything but since it is the last one, then it is a catch-all view. Anyway, for our local clients we allow recursive queries (recursion yes), while we disallow it for a global clients (recursion no). This is a good security practice! Also, note that for internal clients we define example-domain.local zone, which isn't defined for global clients. And, for the same example-domain.com zone, two different files (i.e. databases with names) are used. This reflects the fact that we want local clients to get local IP addresses, while global clients should get globally valid IP addresses.

Zone configurations

There are three zones in our case. First one is a global one, used to answer queries to clients on the Internet. Looking into the main configuration file the name of the file containing this zone has to be example-domain.com and it has to be placed in /var/named directory! The content of this file is:
$TTL 1D
@    IN    SOA    @ root.example-domain.com. (
            2012062501    ; serial
            1D            ; refresh
            1H            ; retry
            1W            ; expire
            3H )          ; minimum
           NS    ns1.example-domain.com.

ns1        A    192.0.2.1
There are three records in the file. The first one defines zone itself, it is called Start of Authority, or SOA. The @ sign is shorthand for zone name and it is taken from the /etc/named.conf file. Then, there is a continuation that defines name server (NS) for the zone. It is continuation because the first column (where @ sign is) isn't defined so it is taken from the previous record. Name server is ns1.example-domain.com. Finally, there is IP address of the name server (A record). You should keep in mind that any name that doesn't end with dot is appended with a domain name. A lot of errors are caused by that omission. For example, if you wrote ns1.example-domain.com (without ending dot) this would translate into ns1.example-comain.com.example-domain.com. which is obviously wrong. But note that we are counting on this behavior in A records since we only wrote a name, without a domain!

The other zone files are similar to the previous one and also have to be within /var/named directory. I.e. for local view of example-domain.com. the content of zone file is:
$TTL 1D
@    IN    SOA    @ root.example-domain.com. (
            2012062501 ; serial
            1D         ; refresh
            1H         ; retry
            1W         ; expire
            3H )       ; minimum
        NS    ns1.example-domain.com.

ns1        A    10.0.0.2
Note that it is almost identical, except that IP address for name server is now from a private range! Finally, here is the content of zone that contains names from a local network:
$TTL 1D
@    IN    SOA    @ root.example-domain.local. (
            2012062501 ; serial
            1D         ; refresh
            1H         ; retry
            1W         ; expire
            3H )       ; minimum
        NS    ns1.example-domain.com.

test        A    172.16.1.1
Again, almost the same. Note that I added one test record with phony IP address. This is so that I can test DNS server if it is correctly resolving IP addresses.

One final thing before starting DNS server! You should change file ownership and SELinux context. To do so, use the following two commands (run them in /var/named directory):
chcon system_u:object_r:named_zone_t:s0 example-domain.*
chown root.named example-domain.*
The first command changes SELinux context, and the second one owner and group of files. So, it is time to start BIND, i.e. DNS, server:
/etc/init.d/named start
If there were some error messages, like the following one:
zone example-domain.com/IN/internal: loading from master file example-domain.com.local failed: permission denied
zone example-domain.com/IN/internal: not loaded due to errors.
Then something is wrong. Look carefully what it says to you as the error messages are quite self explanatory! In this particular case the problem is that DNS server can not read zone file. If you get that particular error message, check that SELinux context and ownership were changed properly.

Testing


Now, if you get just OK, it doesn't yet mean that everything is OK. You have to query server in order to see if it responds correctly. But, if there were any errors, they will be logged in /var/log/messages.

To test DNS server, use nslookup like this:
nslookup <name> 127.0.0.1
Here, I assume you are testing on a DNS server itself. If you are testing on some other host then you should change address 127.0.0.1 with proper IP address of DNS server (public one in case you ask from the internet, local one if you are asking from some computer in DMZ or local network). In any case you should receive correct answers. Here are few examples:
# nslookup ns1.example-domain.com 127.0.0.1
Server:        127.0.0.1
Address:    127.0.0.1#53

Name:    ns1.example-domain.com
Address: 10.0.0.2
# nslookup test.example-domain.local 127.0.0.1
Server:        127.0.0.1
Address:    127.0.0.1#53

Name:    test.example-domain.local
Address: 172.16.1.1
As expected, when internal host sends request internal IP address are returned. You should also check that any valid name is properly resolved (recursive queries). For example, you could ask for www.google.hr:
# nslookup www.google.hr 127.0.0.1
Server:        127.0.0.1
Address:    127.0.0.1#53

Non-authoritative answer:
www.google.hr    canonical name = www-cctld.l.google.com.
Name:    www-cctld.l.google.com
Address: 173.194.70.94
Which, in this case, resolves properly.

Now, there is a question how to test if names are properly resolved for clients on the Internet. The obvious solution is to try from some host on the Internet and see what's happening. In case you don't have host on the Internet, you can cheat using NAT. ;)

Do the following. First, add some random IP address to your loopback interface, i.e.:
ip addr add 3.3.3.3/32 dev lo
Then, configure NAT so that any query sent via loopback gets source IP address changed:
iptables -A POSTROUTING -o lo -t nat -p udp --dport 53 -j SNAT --to-source 3.3.3.3
And now, try to send few queries:
# nslookup www.slashdot.org. 127.0.0.1
Server:        127.0.0.1
Address:    127.0.0.1#53

** server can't find www.slashdot.org: REFUSED
That one is OK. Namely, we don't want to resolve third party names for outside clients (remember, recursive is off!). Next test:
# nslookup ns1.example-domain.local. 127.0.0.1
Server:        127.0.0.1
Address:    127.0.0.1#53

** server can't find ns1.example-domain.local: REFUSED
This one doesn't work either. Which is what we wanted, i.e. our local domain isn't visible to the outside world. Finally, this one:
# nslookup ns1.example-domain.com. 127.0.0.1
Server:        127.0.0.1
Address:    127.0.0.1#53

Name:    ns1.example-domain.com
Address: 192.0.2.1
Which sends us correct outside address.

So, all set and done. Don't forget to remove temporary records (i.e. test), iptables rule, lo address, and also don't forget to modify /etc/resolv.conf so that your new server is used by default by local applications.

About Me

scientist, consultant, security specialist, networking guy, system administrator, philosopher ;)

Blog Archive