July 29, 2006

Installing Fedora Directory Server on FC5

Well, there are the official installation instructions which basically work because they’re pretty simple: install the RPM and run the indicated setup program. I did created a fedora-ds user and group to run the server as; I don’t know if this is beneficial, but if they do it for every other service why not this one?

There is a note there on the install instructions saying that the console will not work if you don’t turn off SELinux. I did not have that experience when I installed Sun Java 5 (using RPM from jpackage.org) and ran startconsole through SSH’s X11 forwarding.

Now, before I did that I did have problems connecting to the server with an installation of the administration console on another machine. I suspect these problems were related to weird DNS issues. However, I initially forgot to change the IPs allowed to connect to the administration server as per these directions. I note that FDS 1.0.2 seems to retain the bug from earlier releases whereby the results of matching the IP are inverted: if it matches, you’re denied, otherwise you’re allowed. (Or something.)

To get SSL going I did a few different things. References for these activities were primarily Managing SSL and SASL from the RH Directory Server docs and the HowTo:SSL page from the FDS Wiki.

  1. I made a new CA to be used on my whole network using the easy-rsa stuff from OpenVPN. These scripts make it nice and easy to administer your CA.
  2. From the “Fedora Management Console” you get when you first startconsole -x nologo, find “Administration Server” in the tree and double click it to open the administration server console.
  3. Select the “Manage Certificates” task from the “Tasks” tab.
  4. The first time you open this you’ll probably get prompted to set a password that’s used to encrypt the private keys. Go ahead and do that.
  5. Go into the “CA Certs” tab, click the “Install” button, and follow the prompts to install the CA certificate that easy-rsa made for you.
  6. Now close out all those windows so you’re back down to the “Fedora Management Console” window.
  7. Find and double click the LDAP server in the tree to get its console.
  8. Repeat steps 3-6 for the LDAP server.

At this point both servers have your CA certificate. Now you need to assign them their own key and certificate.

If you want to assign separate keys to the administration server and the LDAP server, you can do that through the GUI: in manage certificate you can generate a request in the “Server Certs” tab of “Manage Certificates,” use sign-req from easy-rsa to make a certificate, then import that certificate in the “Server Certs” tab.

One gotcha: I don’t believe OpenSSL (at least as configured by default in easy-rsa) will let you have two certificates with the same DN, and that usually means you’ll want to differ the CN on the certificates; but I’m pretty sure the CN on both certificates needs to be the host name that was used to connect via SSL. (Otherwise, I presume you’ll go to connect and the SSL client—whatever it might be—will say “hey, the certificate sent to me by the server doesn’t match the name on the certificate! bye!”) Use a separate host name for the administration server and the LDAP server, no problem. Find out I’m wrong about this requirement, no problem (make the CN’s different to indicate which one is for the administration server and which one is for the LDAP server).

But if you, like me, want to use one host name to connect to both servers, and you also like to assume problems will occur before they have been solidly confirmed (as I have above), you may want to do what I did: use the same certificate/key for both the administration server and the LDAP server. The trick here is that you can’t (or, at least, I can’t) do this from the GUI. First, make a single key/certificate for the servers with easy-rsa; use build-key-server, not build-key. You need the pk12util on the command line. Doing this is as described in the HowTo:SSL Wiki page:

openssl pkcs12 -export -inkey PRIVATE-KEY -in CERTIFICATE -out /tmp/crt.p12 -nodes -name 'NICKNAME'
cd /opt/fedora-ds/shared/bin
./pk12util -i /tmp/crt.p12 -d /opt/fedora-ds/alias/ -P PREFIX-

In my case, PRIVATE-KEY was something like /root/ca/keys/ldap.example.com.key (the key file generated by build-key-server), CERTIFICATE was /root/ca/keys/ldap.example.com.crt (again, a result of build-key-server), and I used the CN (the host name) for the NICKNAME. When openssl pkcs12 asks for an export password, just press enter. You need to run the pk12util command twice: once using something like slapd-ldap- (the hyphen on the end is important!) for PREFIX and again using something like admin-serv-ldap- for PREFIX (if you used an instance name other than ldap, the default when running setup, replace ldap in those PREFIX values with your instance name). The first time you run it with slapd-ldap- you import the key and certificate into the LDAP server; the second invocation of pk12util imports the key and certificate into the administration server. pk12util may ask for your “token” or something; that’s the password you set when you first opened the “Manager Certificates” task.

When it reports something like pk12util-bin: PKCS12 IMPORT SUCCESSFUL for each invocation of pk12util you should be able to see your imported key/certificate in the “Manage Certificates” task of both the administration server and the LDAP server.

Now that you’ve done the hard work of actually getting the necessary keys and certificates into FDS, you need to go into the configuration of each of the administration and the LDAP servers and enable SSL, then restart both servers. This process is described in the RHDS documentation on enabling SSL.

I’ll take a moment to note that I disable all “insecure” ciphers (that’s what I think I’m doing when I uncheck them, at least). I’m a little concerned that, when editing the TLS ciphers for the LDAP server, I uncheck them all because the only two available ciphers are 56-bit “export” ciphers. I don’t know if I need to enable a plug-in, if a more secure cipher is simply missing in FDS, or if some specification (LDAP? TLS? I don’t believe either of these would specify such a thing) say you can’t use a stronger cipher with TLS in this case. At any rate, I suspect disabling all TLS ciphers means STARTTLS will never work with my LDAP server, and I’m OK with that (I’ll just use port 636).

A final note: learning that pk12util and certutil are there, and a bit about what they can do, is probably valuable. For example, I initially used build-key (instead of build-key-server) to generate my key/certificate. When I went to restart the administration server and the LDAP server, neither would start back up because of an SSL error. I had to use certutil to delete them and pk12util to put new ones back in (after I revoked the old ones and generated new ones with build-key-server).

Now, I want FDS to start without asking me for the password I encrypted the key/certificate databases with. To do this for the LDAP server, make a file /opt/fedora-ds/alias/slapd-ldap-pin.txt (once again, replace ldap with your instance name if you’re not using the default) with the following contents:

Internal (Software) Token:PASSWORD

Where PASSWORD is the password you set. Make sure this file is something like mod 400 and only readable/writable by the user/group FDS runs as (fedora-ds in my case). To store the administration server’s passphrase requires just a touch more work. First, make a file such as /opt/fedora-ds/admin-serv/config/password.conf and give it contents such as:

internal:PASSWORD

Again, PASSWORD is the password you set for the administration server’s certificate store. Again, make sure this file has proper permissions: 400, owned by user/group FDS runs as. Now you have to change the “NSS” module’s configuration to tell it to read from this file. Edit /opt/fedora-ds/admin-serv/config/nss.conf, find the line that begins with NSSPassPhraseDialog and change it to look something like:

NSSPassPhraseDialog file:/opt/fedora-ds/admin-serv/config/password.conf

Now you should be able to restart both the LDAP and administration servers with impunity, and without being asked for a password.

There are a few SysV init scripts for FDS on the FDS Wiki, but I wasn’t totally happy with any of them so I made my own. You can download fedora-ds.init which starts the LDAP server. Edit the instance variable to match your instance name (if it’s not ldap) and install it mod 755 in /etc/init.d, named whatever you’d like (I like slapd-ldap for my ldap instance). There’s also fedora-ds-admin.init to start/stop the administration server. I installed this as /etc/init.d/fedora-ds-admin. Don’t forget to run chkconfig -add and chkconfig ... on for both services.

July 20, 2006

Installing RT on CentOS

Versions: CentOS 4.3, RT 3.6.0, PostgreSQL 8.1.3, Postfix 2.2.10, Perl 5.8.5, mod_perl 2.0.1. (Mind you, not using MySQL.) That PostgreSQL and probably Postfix are not the versions that ship with CentOS 4.3 I’m afraid, but they were probably built from Fedora RPMs. The origins of that mod_perl are filled in below.

I’ve installed RT in the past, and I’m somewhat used to how it works. I’m also aware (but not “used to”) how many Perl dependencies it requires.

I mostly followed the instructions at http://wiki.bestpractical.com/index.cgi?ManualInstallation. I’ll show my configure command line since it gives me the opportunity to explain a bit about how I structured the installation:

./configure --prefix=/srv/www/support.domain.com/apps/rt3 
--with-db-host='' --with-db-type=Pg --with-db-database=domain_rt3 
--with-db-rt-user=domain_rt3 --with-db-rt-pass='sekret' 
--with-web-user=apache --with-web-group=apache 
--with-rt-group=support_domain_com 
--with-bin-owner=support_domain_com 
--with-libs-owner=support_domain_com 
--with-libs-group=support_domain_com --with-db-dba=postgres
  • Everything gets installed in a directory specific to the virtual host I’m working with. This might be even more useful if RT supports multiple instances and one or more of my customers wants their own ticketing system. But mostly just because I consider RT a web application, and I consider web applications to be bound to their particular web site (I can’t think of any exceptions to this thinking, but I bet there are some).
    • All the files in /srv/www/support.domain.com are owned by the support_domain_com user. I create my virtual hosts with some scripts that create a new user for every web site we host. Creating separate users is necessary for giving clients SFTP access to modify their web sites. In this case it’s not really necessary, but it doesn’t seem altogether wrong that there should be someone other than root owning RT’s myriad files.
    • DocumentRoot actually points to /srv/www/support.domain.com/root. Note that RT is not being installed in the DocumentRoot (which is completely proper as far as I know).
  • --with-db-host='' makes the DBD::Pg driver connect via Unix domain sockets.
    • Setting --with-db-dba is important for using RT’s installation scripts to create your initial database.
  • domain_rt3 basically indicates (to me) “this is the user that RT uses for the installation on domain.com.” (Sorry if “domain” is a poor example domain for these purposes.)

With that out of the way, you get right into the fun part: make testdeps.

You’re missing everything. (OK, not literally.)

Go get cpan2rpm and use it for most of RT’s dependencies. cpan2rpm will make everything into (mostly) nice little RPMs. cpan2rpm doesn’t work right with packages that use Module::Build (I think that’s what causes it) and you end up having to use the --version X.Y... argument to cpan2rpm. So my typically cpan2rpm invocation might look like:

cpan2rpm --no-upgrade-chk --install Foo::Bar [--version ...]
         [--make-no-test]

--make-no-test comes in when make test fails for a particular CPAN package. I had to do this on a handful of packages and my RT installation thus far seems no worse for it.

Installation of some of the resulting RPMs will fail because they need to update some files on the system that belong to the perl package. You’ll need to use rpm -Uvh --replacefiles on these (and if someone has a cleaner solution that’s easier than “rebuild the perl RPM without those files” please let me know). Additionally, some packages will have their auto-dependencies miscalculated; for example, one package claimed it required something like Win32::Registry. For these sorts of cases, you’ll need to give --nodeps to RPM, or else fix the dependencies with the appropriate cpan2rpm arguments.

It’s unfortunate that cpan2rpm apparently does not automatically get and build dependencies of the package you’re installing. What this means is that you’ll basically have a text editor open for use as a “stack” while you install RT dependencies: try to cpan2rpm an RT dependency, find out it has three unmet dependencies, push the RT dependency onto the stack, try to install one of the three dependencies, find it has its own unmet dependency, so push the package onto the stack and try the next one… and so on. Also, sometimes cpan2rpm Foo::Bar doesn’t find what distribution Foo::Bar is in, and I’m not sure why. I think MailTools is one such distribution. So instead of doing cpan2rpm Mail::Mailer (or whatever package I was looking for) I had to search CPAN to find the distribution name (MailTools) then cpan2rpm MailTools.

One RT dependency of note is Apache::Request. I’ve always had a problem finding this package in an RPM. The package name you’ll need to request is libapreq if you use mod_perl, or libapreq if you use mod_perl2. But you know what? Don’t try doing that through cpan2rpm because it doesn’t work. Moreover, CentOS 4.3 includes mod_perl 1.99. That’s some scary shit: closer to mod_perl 2, but not quite there yet. So here’s what I did: take the mod_perl SRPM from Fedora Core 4 updates and the libapreq2 SRPM from Fedora Core 5 Extras (I wanted to use mod_perl from FC5 but it required Apache 2.2, and I wasn’t about to go there), rebuild them on CentOS 4, and install the results. It seems to work just fine on my system so far.

[root@host rt3]# rpm -q mod_perl libapreq2
mod_perl-2.0.1-1.fc4
libapreq2-2.07-2.el4
[root@host rt3]# cat /etc/redhat-release
CentOS release 4.3 (Final)

One more note: install Apache::DBI. Somehow I didn’t have this, but if you’re going to use mod_perl, you’ll need it.

And that’s it for installing all of RT’s dependencies! It’s just that easy. Except it took me several hours to do this. But anyway…

Moving on, I’ll note that when you make install, you’ll need to go in and make a few directories under apps/rt3 mod 755, such as share and lib for example. Maybe var. I think RT’s installation thinks of itself as going into /usr/local, where you’ve already got those directories created with the proper permissions; so RT won’t “fix” the permissions on those directories, even when you ask it to make fixperms.

I did have to poke at /var/lib/pgsql/data/pg_hba.conf a bit since I only had rules for the postgres user to access stuff, and at the time doing sudo -u postgres make initialize-database wasn’t working very well. So I ended up jamming a temporary trust statement in pg_hba.conf while I did make initialize-database. Note that when using PostgreSQL, RT does everything for you including making the DB and the user RT will use to access that DB.

From here on it’s more or less a matter of following the directions. Some people have had problems running RT with SELinux in play, hence the page http://wiki.bestpractical.com/index.cgi?SELinux. Thus far I’ve had only one such problem I can think of: apache isn’t allowed to poke about in /usr/sbin, which makes running /usr/sbin/sendmail hard. (Note: it might work if you specify /usr/sbin/sendmail.postfix in the case of Postfix users; the first error I got was just trying to read the link. From reading the SELinux policy a little bit, though, I’m pretty sure things in the httpd_whatever_t context can’t get at /usr/sbin at all.) My solution (from apps/rt3/etc/RT_SiteConfig.pm:

Set($MailCommand, 'smtp');
Set($SMTPServer, 'localhost');

These tell Mail::Internet (or is it Mail::Mailer?) to talk SMTP to localhost instead of trying to invoke sendmail. Of course, once I did this I had some other problems, as described in this bug report send to Best Practical regarding problems with the Sender header in mail originated from RT. It includes a very small patch you can make if you have the problem described. Hopefully it might be fixed by the time you read this, either in RT or in MailTools (or both).

While we’re on the subject of SELinux, I’ll add that all the RT files seem to be in the httpd_sys_content_t context, and I have the httpd_unified boolean on in SELinux.

Also, in my default installation I’ll note I didn’t need $DatabaseRequireSSL turned on to talk to PostgreSQL. In fact, I think turning it on caused breakage.

My Apache configuration looks basically like what they have there, but with a few more directives to turn on SSL and make sure everyone gets pushed through the SSL version of the site. One change that I did make, and which I noted on the RT Wiki’s ManualInstallation page, is:

PerlModule Apache2::compat

instead of:

PerlModule Apache2 Apache::compat

It is suggested that use of Apache 2 requires inclusion of a directive such as:

RedirectMatch permanent (.*)/$ http://example.com$1/index.html

I did not have to use that. Everything worked right out of the box. (Ha. Ha.)

Just a few words about my mail setup. (I hope to talk more about all the mail services I’ve set up on this same server.) First of all, I only have one RT queue currently, and it’s named “Support.” I set up support.domain.com in virtual_alias_domains (referring to the Postfix main.cf directive). Then I put /etc/postfix/virtual in virtual_alias_maps, and set up these aliases:

postmaster@support.domain.com      some-postmaster@domain.com
abuse@support.domain.com           some-abuse@domain.com

support@support.domain.com         domain-support
support-comment@support.domain.com domain-support-comment

So e-mails to support@support.domain.com will go to the local user domain-support. By directing to a local user, I can then make entries in /etc/aliases such as:

domain-support: "|/srv/www/support.domain.com/apps/rt3/bin/rt-mailgate
         --queue support --action correspond
         --url https://support.domain.com"
domain-support-comment: "|/srv/www/support.domain.com/apps/rt3/bin/rt-mailgate
             --queue support --action comment
             --url https://support.domain.com"

(Wrapping added by me for readability.) To use https URLs you might need to install Crypt::SSLeay, and of course make sure you have the perl-libwww-perl RPM installed. Some postmap, newaliases, and we’re off to the races: RT now accepts e-mail.


A few more words on exactly how we’re currently using RT.

Now, ideally RT would work like this:

  • My company’s employees can sign in, see, and modify all tickets in the Support queue.
  • My client’s administrators can log in, see, and modify all tickets requested by their employees, but cannot see or modify tickets for other clients, all in the Support queue.
  • Employees at my client submit tickets normally through e-mail. (An optional interface to submit through the Web would be nice; maybe SelfService does this.)

That middle point is the problem. There doesn’t seem to be a way to do something such as “force a filter” on my client’s in-house IT people so that they can only see tickets that involve their company. I suppose another way to do that would be to make per-ticket permissions, and when you’re displaying a queue you check the permissions on each ticket. That might make RT run even slower than it already seems to be (when I say “slow” I mean “less than super speedy like some of the other apps on that server, which are quite possibly less complex and even poorly written”), but I’d write a Scrip that identifies what client a ticket belongs to and presumably sets the proper permissions on it.

Instead I’m using a custom “Client” field and variants on the OnCreateSetDeptHeadCc and AutogeneratedPassword recipes. When a ticket comes in a Scrip tries to match the sender’s e-mail domain to a particular client and then sets the Client field (see AutoSetOwnerForQueue for some idea of how to do that; I actually keep a table corresponding domain to client name in the Scrip which is kind of ugly). When the Client field gets set, another Scrip fires and adds the appropriate per-client administrators group to the ticket’s Cc list.

So RT isn’t exactly suited for what I want to do here. One client has already commented that he wishes he could “take” a ticket (especially since he can see the ticket, and RT gives him the “Take” link, which then presumably fails). The use case is: one of his users submits a ticket, then he decides he wants to fix it, so he’d rather take it. But he’d like the ticketing system to keep track of it, possibly. I had to explain to him that this is a system for submitting support requests to my company, not within his own, but I don’t think that’s really a satisfactory solution. Another solution would be to make a separate queue for each client, and then I can give the various administrators at each client full access to their respective per-company queues. The biggest problem with this is having my company’s employees try to keep track of all these support requests potentially scattered across many different queues. It seems very error-prone.

RT’s methods for clean customization are nice; be sure to use them if you make some of these changes above. (And if you notice that link above, RT’s Wiki really needs a “revert” function.)