Setting Up Trac on CentOS

Paul Heinlein
First published on March 23, 2006
Last updated on October 3, 2006

Introduction

After a fairly drawn-out process of identifying which wiki software to deploy at work, we finally settled on Trac, which in addition to a wiki provides a bunch of project-management tools: trouble tickets, milestones, and strong ties to the Subversion revision-control system.

The system hosting Trac is running CentOS 4, a freely redistributable rebuild of Red Hat Enterprise Linux 4. The trouble is that CentOS doesn’t ship with Trac, and our our system setup and implementation requirements conspired to make Trac’s installation a somewhat involved process. This document tries to spell out all the special instructions someone would have to follow to re-implement our Trac setup.

Local conventions

Before launching into the gory details of installing and configuring Trac and Subversion on our wiki server, it’s worth noting our local conventions:

  • We expected to host multiple Trac instances. One instance would be the default, primus inter pares, but all instances would live at the same level in the filesystem.

  • The /srv directory hosts both the Subversion repositories (/srv/svn) and Trac instances (/srv/trac).

  • Apache manages all access to Subversion repositories on the wiki server.

System Modifications

Our wiki server, like all Red Hat-based systems, manages most software with rpm, the Red Hat package manager. The system’s security constraints are partly governed by SELinux, which is running what Red Hat calls a targeted policy. Certain applications, Apache among them, are governed by fairly strict and comprehensive security policies. All three of these pieces—package management, SELinux, and Apache—needed modification in our setup.

System Packages

A few Apache- and Python-related packages, along with packages on which they depend, must be installed from the base CentOS distribution for Trac to function: httpd, mod_dav_svn, mod_python, and subversion.

The base CentOS distibution doesn’t include Trac or the ClearSilver template library on which it depends. Rather than building those packages in house, I used pre-built packages from Dag Wieers’ repository.

Somewhat later, after Trac was up and running, I discovered that its reStructuredText capabilities required python-docutils, a collection of Python modules not included with CentOS. Dag’s repository didn’t have a package for it either, so I fetched it instead from Karanbir Singh’s repository.

CentOS uses yum to handle dependency checking and remote installation of packages, so using packages from the other repositories was a simple matter of expanding the yum configuration on the host system:

[dag]
name=Dag RPM Repository for Red Hat Enterprise Linux
baseurl=http://apt.sw.be/redhat/el$releasever/en/$basearch/dag
gpgcheck=1
enabled=0
includepkgs=clearsilver python-clearsilver trac

[kbs-CentOS-Extras]
name=CentOS.Karan.Org-EL$releasever - Stable
gpgcheck=1
gpgkey=http://centos.karan.org/RPM-GPG-KEY-karan.org.txt
enabled=0
baseurl=http://centos.karan.org/el$releasever/extras/stable/$basearch/RPMS/
includepkgs=python-docutils python-imaging

Please note that the enabled directives in both third-party repository definitions is set to 0 (false). This allows yum to work automatically from the official CentOS repository without hitting any snags from the other repositories. To get updates from dag and/or pyvault, use yum’s --enablerepo option:

yum --enablerepo=dag --enablerepo=kbs-CentOS-Extras update

SELinux Policies

In Red Hat’s targeted SELinux policies, the Apache web server can only read files assigned a security context type of httpd_sys_content_t. The standard context for a web-readable directory can be seen in a listing of /var/www/html on Red Hat systems:

$ stat -Z -c %C /var/www/html
system_u:object_r:httpd_sys_content_t

To get Trac to work in an SELinux-enabled environment, therefore, all web content needs to be typed as httpd_sys_content_t. Retyping is done via the chcon utility. Given the local filesystem setup, the retyping took a single invocation of chcon:

chcon -R \
  -u system_u -r object_r -t httpd_sys_content_t \
  /srv/svn /srv/trac

Apache Configuration

The security profile of our Trac site wasn’t terribly stringent, so there was no need to establish an SSL infrastructure. On the other hand, HTTP Basic authentication is terribly weak, so authentication for Trac access is provided by the HTTP digest access scheme. Digest authentication poses one difficulty: it cannot currently be used in conjunction with LDAP, PAM, /etc/passwd, or any other system-authentication scheme. The digest password database is completely divorced from system accounts.

Trac is a fairly hefty process, so it is typically run under FastCGI or mod_python rather than plain CGI. Since CentOS includes mod_python in its standard Apache package, that’s the acceleration method we chose to employ. The Apache configuration file, /etc/httpd/conf/httpd.conf, needs to load the Python module at start time. It also needs the subversion and DAV modules.

As mentioned above, all Trac instances live in /srv/trac and all Subversion repositories live in /srv/svn. Apache rewards such simplicity by providing directives that understand parent paths for both applications. Interestingly, the Location of the Subversion directory root must not be specified via an Alias or a symlink from the DocumentRoot; it’s a completely manufactured URI, managed by the Subversion/DAV modules.

# snip lead-in stuff for brevity
# load relevent modules
LoadModule dav_module modules/mod_dav.so
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so
LoadModule python_module modules/mod_python.so
# ...
<VirtualHost *:80>
  ### ...
  ### trac
  Alias /trac/ "/srv/trac/"
  <Directory "/srv/trac">
    Options Indexes FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all

    # mod_python speeds things up considerably
    SetHandler mod_python
    PythonHandler trac.web.modpython_frontend
    PythonOption TracEnvParentDir "/srv/trac"
    PythonOption TracUriRoot "/trac"

    # authentication
    AuthType Digest
    AuthName "wiki-server"
    AuthDigestDomain /trac
    AuthDigestFile "/etc/httpd/conf/digestpw"
    Require valid-user
    # authorization is handled internally by trac
  </Directory>

  ### subversion
  <Location "/svn">
    DAV svn
    SVNParentPath /srv/svn
    
    Order allow,deny
    Allow from all

    # authentication
    AuthType Digest
    AuthName "wiki-server"
    AuthDigestDomain /svn
    AuthDigestFile "/etc/httpd/conf/digestpw"
    Require valid-user

    # authorization
    AuthzSVNAccessFile "/etc/httpd/conf/svn-auth.ini"
  </Location>
</VirtualHost>

Adding a Trac

Instantiating Trac and Subversion

The process for adding a new Trac instance requires several steps. The easiest way to list them is in the language of the Unix shell:

### subversion
# create the repo; use the filesystem backend
svnadmin create /srv/svn/projectname --fs-type fsfs
# give Apache user ownership
chown -R apache /srv/svn/projectname
# tell everyone to go away
chmod -R go-rwx /srv/svn/projectname
# tell SELinux this is valid web content
chcon -R -u system_u -t httpd_sys_content_t /srv/svn/projectname

### trac
# create the instance
trac-admin /srv/trac/projectname initenv
# assign group ownership to Apache
chgrp -R apache /srv/trac/projectname
# give Apache total ownership of a few important directories
chown -R apache /srv/trac/projectname/{attachments,db,log}
# tell everyone else to go away
chmod -R o-rwx /srv/trac/projectname
# tell SELinux this is valid web content
chcon -R -u system_u -t httpd_sys_content_t /srv/trac/projectname

Configuring trac.ini

After instantiating the new Trac, its trac.ini configuration file needs to be tweaked according to local conventions and project needs. Most of the default settings are acceptable, though we always try to use UTF-8 charsets whenever possible. (UTF-8 is also the default charset in the stock CentOS Apache configuration.)

[trac]
default_charset = UTF-8

Authorization settings

Apache handles general user authentication (agreeing that you are who you say you are), but Trac and Subversion will also try to authorize your ability to do different tasks: read, write, commit, delete, etc. Trac provides a much wider range of permissions than Subversion, and it requires some thought to figure out who can do what. Each application uses a different tool for configurating authorization. Trac uses the trac-admin command-line tool. Subversion relies on a text file (specified in the sample Apache configuration above as /etc/httpd/conf/svn-auth.ini).

In general, the configuration process consists of three steps: identifying users and privileges, using trac-admin to alter basic Trac permissions, and editing svn-auth.ini to specify Subversion privileges.

The first step is to identify users who will administer this Trac/Subversion instance, any non-admin users who have some elevated privileges, and the base privileges for everyone else. The TracPermissions help page contains a list of the various settings that can be tweaked. You’ll also want to decide if you want to apply special controls to any areas of your Subversion repository.

An important question is the status of anonymous users. On a corporate intranet, we don’t have to worry too much about spambots and malicious users. On the wider Internet, however, you’ll have to decide if anonymous users should be able to post content.

It’s possible, for example, to use trac-admin to remove all write privileges for anonymous users, add TRAC_ADMIN privileges for administrators, add any other elevated privileges, and tweak base privileges for all other authenticated users:

# remove write privileges for anonymous visitors
trac-admin /srv/trac/projectname permission remove anonymous \
  TICKET_CREATE TICKET_MODIFY WIKI_CREATE WIKI_MODIFY

for n in adminuser1 adminuser2; do
  trac-admin /srv/trac/projectname permission add $n TRAC_ADMIN
done

for n in projectuserA projectuserB projectuserC; do
  trac-admin /srv/trac/projectname permission add $n WIKI_DELETE
done

trac-admin /srv/trac/projectname permission add authenticated \
  BROWSER_VIEW CHANGESET_VIEW FILE_VIEW LOG_VIEW MILESTONE_VIEW \
  REPORT_SQL_VIEW REPORT_VIEW ROADMAP_VIEW SEARCH_VIEW \
  TICKET_CREATE TICKET_MODIFY TICKET_VIEW TIMELINE_VIEW \
  WIKI_CREATE WIKI_MODIFY WIKI_VIEW

Note that the default permissions don’t allow people to delete anything, since deletion is a non-reversible action in Trac.

Finally, edit /etc/httpd/conf/svn-auth.ini (or whatever you choose to call it) to specify Subversion permissions. This file uses the syntax for Subversion’s per-directory access control. Optionally, you might also want to create groups of users to simplify things a bit.

[groups]
projectadmins = adminuser1, adminuser2
othercoolfolks = projectuserA, projectuserB, projectuserC

# repository (r = read, w = write, or none)
[projectname:/]
@projectadmins = rw
@othercoolfolks = rw
* = r

[projectname:/admin-only/]
@projectadmins = rw
@othercoolfolks = r
* = none

Role-based access for Trac wiki

If all those special instructions aren’t enough, our local Trac installation also makes use of a third-party patch that provides role-based access control (RBAC) over specific sections of wiki content.

In general, it’s worth noting that the RBAC patch is fairly complex. The configuration outline provided below presumes that you’ve read the its documentation.

Applying the patch

After applying the patch, the updated web_ui.py and rbac.py files need to be compiled and have their SELinux contexts reset:

python -c 'from trac.wiki import web_ui, rbac'
chcon -u system_u -r object_r -t lib_t \
  /usr/lib/python2.3/site-packages/trac/wiki/*

RBAC configuration

The RBAC patch requires some mandatory additions to trac.ini.

[wiki]
authz_svn_module_name = projectname-wiki
authorization_mode = require_all
authz_file = /etc/httpd/conf/svn-auth.ini

You can set authz_svn_module_name to just about any abritrary string. In our setup, we put wiki authorization stuff into the Subversion authorization file, so we make sure Subversion and the wiki have different namespaces.

There’s little reason for us to set authorization_mode to anything but require_all, but your needs may require otherwise.

As mentioned, we point authz_file at Subversion’s configuration file. For us, it cuts down on overhead; your mileage may vary. Here’s what an expanded configuration might look like.

[groups]
projectadmins = adminuser1, adminuser2
othercoolfolks = projectuserA, projectuserB, projectuserC

### repository (r = read, w = write, or none)
[projectname:/]
@projectadmins = rw
@othercoolfolks = rw
* = r

[projectname:/admin-only/]
@projectadmins = rw
@othercoolfolks = r
* = none

### wiki (a = admin, r = read, w = write,
###       c = create, d = delete, or none)
[projectname-wiki:/]
@projectadmins = a
@othercoolfolks = rwcd
* = rw

[projectname-wiki:/PrivateStuff/]
@projectadmins = a
@othercoolfolks = rw
* = none

The RBAC patch is subtractive only. It can only limit permissions granted via trac-admin; it cannot add them. In this example, for instance, the * = rw setting for the wiki doesn’t allow anonymous users write access, since they were denied that by the earlier trac-admin invocations. On the other hand the settings for wiki pages beginning with /PrivateStuff/ will prohibit users in the othercoolfolks group from creating or deleting pages in that tree and will prohibit all other users, whether anonymous or authenticated, from reading them.

Redhat  Linux