Nov 22, 2008
It's possibile to configure an HTTPS access to Subversion repositories, using a webserver like Apache2.2, with WebDAV functionalities provided by the DAV apache modules. The SSL connection provides a secure tunnel and users will authenticate against a OpenLDAP directory service authenticating only users pertaining to a allowed group.
The HTTPS will be made available by a front-end web server, Nginx, HTTP reverse-proxying to Apache2 on port 80, that will take care of users authetication and authorization, accessing the subversion repositories. The Apache2.2 virtual host will be running as a system user owning the repositories and thus having the needed read and write permissions.
Nginx will be listening on the public IP interface on port 443 (or another port of choice) making the SSL connection using self signed certificate and key. Apache2.2 can be installed on the same machine and listening on the loopback, or can be installed on another virtual or physical machine in a private IP network, listening on port 80. Having the back-end server on a private network is a choice of network design, it can be varied on particular needings as well, but it will be the only one discussed here.
The operating system of choice is GNU/Linux, having a SLES10.3 SP1 running on the front-end machine and a Ubuntu 8.10 server edition on the back-end server.
In the Nginx compilation and installation wiki page there's thorough documentation giving details on the process, here will be showed an example of how to compile with the required SSL module, so get in the /usr/local/ directory and download the sources tar.gz package:
wget http://sysoev.ru/nginx/nginx-0.6.32.tar.gz
and unpack it:
tar -xzf nginx-0.6.32.tar.gz
before running the configure script it can be useful to check for latest updates to the configuration process:
./configure --help
get in the source directory and run the configure script:
./configure --with-http_ssl_module
and then compile:
make
make install
the contents of the sources dir should be as follows:
1 2 3 4 5 6 7 | client_body_temp/ conf/ fastcgi_temp/ html/ logs/ proxy_temp/ sbin/ |
having the nginx binary in the sbin/ directory.
An init script is needed in order to manage the sevice and correctly boot-up:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | #! /bin/sh ### BEGIN INIT INFO # Provides: nginx # Required-Start: $all # Required-Stop: $all # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: starts the nginx web server # Description: starts nginx using start-stop-daemon ### END INIT INFO PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/local/sbin/nginx NAME=nginx DESC=nginx test -x $DAEMON || exit 0 # Include nginx defaults if available if [ -f /etc/default/nginx ] ; then . /etc/default/nginx fi set -e case "$1" in start) echo -n "Starting $DESC: " start-stop-daemon --start --quiet --pidfile /usr/local/nginx/logs/nginx.pid --exec $DAEMON -- $DAEMON_OPTS echo "$NAME." ;; stop) echo -n "Stopping $DESC: " start-stop-daemon --stop --quiet --pidfile /usr/local/nginx/logs/nginx.pid echo "$NAME." ;; restart|force-reload) echo -n "Restarting $DESC: " start-stop-daemon --stop --quiet --pidfile /usr/local/nginx/logs/nginx.pid --exec $DAEMON sleep 1 start-stop-daemon --start --quiet --pidfile /usr/local/nginx/logs/nginx.pid --exec $DAEMON -- $DAEMON_OPTS echo "$NAME." ;; reload) echo -n "Reloading $DESC configuration: " start-stop-daemon --stop --signal HUP --quiet --pidfile /usr/local/nginx/logs/nginx.pid \ --exec $DAEMON echo "$NAME." ;; *) N=/etc/init.d/$NAME echo "Usage: $N {start|stop|restart|force-reload}" >&2 exit 1 ;; esac exit 0 |
edit it as needed then copy the above script in the /etc/init.d/ directory and add it to the default runlevels using chkconfig command:
`chkconfig --add /etc/init.d/nginx
` as a facility, create the symlink to the boot script in the SLES style:
`ln -s /etc/init.d/nginx /usr/sbin/rcnginx
` before starting the Nginx web server, a minimum configuration of the main nginx.conf file is needed, giving the webserver a name through the server_name directive; if a DNS hostname is not yet available, it's possibile to configure a static route (fake host in the /etc/hosts file in the local desktop computer in the case of unix based OSes) just for testing/learning before releasing, and make sure the listen directive is, for now, with value 80 and then, as root,
start the server:
`root# rcnginx start
` and using a web-browser verify that a 200 http response is received, usually displaying the default static page.
A private key and certificate for the nginx server are needed in order to make the SSL connection possible, in this a self signed-certificate will be created and used, it's assumed that a OpenSSL installation is already available in the running SLES10.
Generating the key:
`root# openssl genrsa -out privkey 1024
` generating the certificate request:
`root# openssl req -new -key privkey -out signing_request
` note: a few params will be requested, the most important is the 'Common Name' which has to be the server name otherwise the certificate will not be accepted, having the nginx unable to initiate the SSL connection itself.
generating the self-signed certificate:
`root# openssl x509 -req -days
` issuing the last opennsl command will generate the certificate to be configured in the nginx server, for a deeper and complete OpenSSL documentation refer to the local installation Docs and/or make a websearch.
In order to have Nginx correctly initiate and establish a HTTPS connection, the generated certificate file and key must be installed.
The Virtual Hosts configuration will be kept in separate files and location than the nginx.conf, in a directory contained under the conf/ dir of the Nginx installation:
1 2 3 | /usr/local/nginx/conf/sites-available /usr/local/nginx/conf/sites-enabled |
as can be noted the Debian style won. In the sites-available directory will be put the Virtual Host files holding the host specific configurations, while in the sites-enabled will be put the symlinks pointing to the hosts wanted to be live. In the nginx.conf main configuration file will be specified the directive to include the sites-enabled contents, as following:
1 2 3 | # Virtual hosts a la Debian include sites-enabled/*; |
in the sites-available directory, copy a file as the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | server { listen 443; server_name hostname.domain; ssl on; ssl_certificate /etc/ssl/certs/server_certificate; ssl_certificate_key /etc/ssl/certs/privkey; access_log logs/hostname.domain_access.log; error_log logs/hostname.domain_error.log; location / { root html; index index.html index.htm; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # proxy_set_header Host $http_host; # proxy_pass http://IP_Addr; # proxy_redirect off; set $dest $http_destination; if ($http_destination ~ "^https://(.+)") { set $dest http://$1; } } } |
by reading the ssl_certificate and ssl_certificate_key directives values, the locations of certificate file and key can be found, after editing the configuration file, symlink this file from the sites-enabled directory to make them included and restart the nginx server.
After restarting nginx, open a https connection in the web-browser and verify the SSL connection working without errors.
The Nginx configuration can be considerd complete and working, later on nginx will be configured to reverse-proxy to apache2.
In order to have every Virtual Host running under a separate user, apache2 mpm-itk will be installed on the Ubuntu back-end server:
`root# aptitude install apache2-mpm-itk
`
On the machine hosting the central repositories, there will be the need to create and administer the subversion repositories themselves, for this reason a special user, dedicated to the purpose, will be created:
1 2 3 | root# addgroup --system scm-local root# adduser --system --home /path/to/repos -g scm-local scm |
in this way, the directory trees starting from the scm home dir will have a coherent permissions scheme, and the scm user will be the user the VirtualHost will be running as. The group is named scm-local because there is a already created and populated LDAP group named scm.
The basic apache2 virtual host configuration will be similar to:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <VirtualHost IP_addr:80> ServerName hostname.dominio ErrorLog /path/to/logs/scm_error CustomLog /path/to/logs/scm_access combined # assign the scm user to this VH AssignUserID scm scm-local # only needed for testing DocumentRoot /scm/home/dir </VirtualHost> |
after testing the acces, on the local listening IP interface, using a web- browser(elinks) and verified that everything is running, the next step will be to configure Nginx to reverse proxy to apache2
In the nginx virtual host configuration file uncomment the proxy_* directives and comment the root and index directives and test by accessing the https://hostname.domain from the outside, the default apache2 static page, in the DocumentRoot should be displayed while apache should give a 200 http response.
It is now time to get on the Apache2.2 SVN and LDAP configuration.
On the back-end server install the modules for LDAP authentication, as root:
root# a2enmod authnz_ldap
then modify the virtual host configuration:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <VirtualHost IP_addr:80> ServerName hostname.domain ErrorLog /path/to/logs/error CustomLog /path/to/logs/access combined # assign the scm user to this VH AssignUserID scm scm-local DocumentRoot /scm/home/dir UseCanonicalName on AuthType basic AuthUserFile /dev/null AuthBasicProvider ldap AuthName "SCM auth" AuthzLDAPAuthoritative on AuthLDAPURL "ldap://IP_addr:PORT/ou=people,DC=hostname,DC=domain?uid?sub?" require valid-user require ldap-group cn=Group_name,ou=group,dc=hostname,dc=domain </VirtualHost> |
as usual, make a test accessing the hostname.domain trying to authenticate a user with correct credenials and group membership, then with un unprivileged user and be sure to get success and error responses.
as root:
root# a2enmod dav_svn
and modify the virtual host configuration as following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | <VirtualHost IP_addr:80> ServerName hostname.domain ErrorLog /path/to/logs/error CustomLog /path/to/logs/access combined # assign the scm user to this VH AssignUserID scm scm-local UseCanonicalName on <Location /repos> DAV svn SVNParentPath /path/to/repos SVNListParentPath on AuthType basic AuthUserFile /dev/null AuthBasicProvider ldap AuthName "SCM auth" AuthzLDAPAuthoritative on AuthLDAPURL "ldap://IP_Addr:Port/ou=people,DC=hostname,DC=domain?uid?sub?" require valid-user require ldap-group cn=Scm,ou=group,dc=hostname,dc=domain </Location> </VirtualHost> |
after these changes to the configuration it's possible to use the repositories as either using the svn CLI or web access. The use of UseCanonicalName on is in conjunction with the set destination Nginx configuration, in order to make DAV correctly operating on files and destinations.
Since Subversion 1.5 has been released, i took the chance to migrate the repositories to the new version:
on the back-end server, which hosts the SVN repositories, become the 'scm' user and start creating the new repositories:
scm$ svnadmin create repo1
it is a good time now for testing the access to the newly created repository and make some test commit/update just to be sure all the structure is working as wanted;
to migrate the repositories a dump of the old ones is needed, so get on the old svn central repositories machine and issue a dump:
scm$ svnadmin dump repo_name > repo_name_oldversion.dump
and transfer the file containing the dump on the back-end server in the 'scm' home directory, maybe by using a scp copy;
before loading the dump create the repository named as the old one which the dump comes from:
scm$ svnadmin create repo_name
and then load the dump:
scm$ svnadmin load repo_name < repo_name_oldversion.dump
this was a brief example of subversion dump/load cycle.
This was quite a fast tour in configuring such a structure, by following it are not excluded issues, but in this way it should be possible to use a subversion repositories collection by either svn cli or web-access.
Hope it helps.
Moon at -62:37:37.0, 15:37:08.4 observing from Rome, IT
Powered by Moonwatcher.it ShortPosts.