Журнал Системный Администратор, Ноябрь 2005

Журнал Системный Администратор

Ноябрь 2005

Цена: $4.5 US

  Подписаться

Зарегистриванные пользователи, пожалуйста следуйте этой ссылке

Версия для печати Вернуться к оглавлению

Развертываем сервер Subversion на платформе FreeBSD

Андрей Шетухин, Ольга Никулина

Прогресс в области разработки систем контроля версий не стоит на месте. Представляем вам Subversion современную замену устаревшей системы CVS.

Что такое Subversion?

Если коротко, Subversion это свободно распространяемая система контроля версий, призванная заменить собой устаревшую систему CVS. Subversion используется такими программистскими коллективами, как команда разработчиков компиляторов GNU, KDE Development Team, разработчиками СУБД Ingres, Apache Software Foundation, Samba и многими, многими другими. Далеко не полный список проектов, исходные коды которых хранятся в Subversion, доступен поссылке: http://subversion.tigris.org/testimonials.htm.

CVS vs Subversion

Поскольку Subversion разрабатывалась как продвинутая замена CVS, изначально ставилась задача: сохранить всю привычную функциональность придобавлении новых возможностей. Поэтому большинство широкоиспользуемых команд Subversion имеют такой же синтаксис, какиCVS. Переход на Subversion несложен и не требует долгого привыкания.

n Атомарное принятие изменений. Поддержка атомарных коммитов позволяет либо принимать весь измененный код, либо не принимать изменения вовсе, если транзакция по каким-либо причинам (например, из-за падения канала) не была завершена. Subversion поддерживает такой режим работы и гарантирует, что репозиторий небудет содержать в себе несовместимых данных либо репозиторий останется неизмененным, либо обновление будет полным.

n Переименование, перенос и копирование файлов икаталогов безпотери версионирования иистории изменений. В отличие отCVS, которая требует вмешательства администратора сервера и ручного копирования файлов, Subversion изначально обладает такой возможностью, а при установке модуля SVN::Mirror, разработанного Chia-Ling Kao, Subversion также обучается клонировать данные из текущего в произвольный удаленный репозиторий.

n Права доступа к репозиторию. Выможете назначать пользователям права доступа к различным частям репозитория, простым редактированием текстового конфигурационного файла.

n Комментарии к каждому измененному объекту. Теперь вы можете оставлять комментарий в журнале коммита к любому измененному вами файлу.

n Простота развертывания системы. Для построения полноценной работоспособной системы Subversion вбольшинстве случаев необходим только веб-сервер Apache2 и интерпретатор PHP, а минимальный набор утилит Subversion, позволяющий работать по протоколам SVN и SVN + SSH, вообще не требует установки стороннегоПО.

n Простота интеграции в существующую инфраструктуру сети. Доступ крепозиторию Subversion может осуществляться по протоколам HTTP, HTTPS, SVN, SVN+SSH, изнабора которых вы сможете легко выбрать наиболее подходящий для заданной конфигурации сети.

n Разнообразные веб-интерфейсы для доступа крепозиторию.Натекущий момент доступно около десятка программ для работы с репозиторием SVN: ViewCVS, SVN::Web, WebSVN, ViewSVN, mod_svn_view, Chora, Trac, SVN::RaWeb::Ligh, SVN Browser, Insurrection и т. д. Вданной статье мы рассмотрим настройку WebSVN как наиболее простого ивто же время функционального инструмента.

n Кроме утилит командной строки, доступны также графические интерфейсы: кроссплатформенный RapidSVN, TortoiseSVN плагин для MS Windows Explorer, а также Jsvn, написанный на Java и доступный везде, гдеесть Java-машина.

n Ну и, наконец, лицензия. Subversion программное обеспечение с открытым кодом и распространяется полицензии Apache/BSD-style.

Что входит в состав пакета Subversion

n svn клиент Subversion. Представляет собой утилиту командной строки, осуществляющую доступ к репозиторию Subversion.

n svnversion программа, показывающая состояние компонент текущего репозитория.

n svnlook утилита для контроля репозитария Subversion.

n svnadmin утилита для создания, управления и восстановления репозитария Subversion.

n svndumpfilter программа фильтрации дампов репозитория Subversion.

n mod_dav_svn модуль для веб-сервера Apache2, предоставляющий доступ в репозиторий Subversion по протоколам HTTP и HTTPS.

n svnserve программа-сервер, запускающаяся как одиночный демон или из inetd и предоставляющая доступ к репозиторию Subversion по протоколу SVN илиSSH.

План установки Subversion

n Установка необходимого ПО. В этом разделе будут описаны установка и запуск FreeBSD Jail, установка веб-сервера Apache 2.X, Subversion, PHP4 и WebSVN.

n Создание сертификатов и конфигурация серверного ПО. Здесь мы рассмотрим создание собственного самоподписанного сертификата (Certificate Authority, CA), создание сертификата сервера и создание клиентских сертификатов.

n Настройка клиентов SVN на *nix и Windows. Этот раздел посвящен работе с Subversion на платформе *nix (Linux/FreeBSD/Solaris ), а также установке на Windows-машину клиента TortoiseSVN.

Создаем и устанавливаем Jail

Jail необходим для того, чтобы система контроля версий жила в собственном мире и никак не пересекалась состальными приложениями. Кроме того, используя jail, выповышаете общий уровень защищенности системы: если обнаружится уязвимость в пакетах Subversion, Apache илиPHP, основная система не пострадает. Jail будет также полезен в том случае, если на основной системе установлен Apache 1.3.X.

Если для Subversion используется выделенный сервер, этот пункт можно смело пропустить.

Собираем jail. Обратите внимание, что на FreeBSD 5.3 команда make world DESTDIR=$D из jail(8) не работает. Вместо нее следует воспользоваться командами:

make buildworld

make installworld DESTDIR=$D

Итак, в нашем случае сборка jail будет выглядеть так:

# cd /usr/src

# mkdir -p /usr/home/jails/svn

# make buildworld

# make installworld DESTDIR=/usr/home/jails/svn

# cd etc

# make distribution DESTDIR=/usr/home/jails/svn

В файл /etc/rc.conf добавляем следующие строчки:

jail_enable="YES" # Включаем загрузку jail

jail_list="svn" # Список всех jail, которые есть в системе

jail_set_hostname_allow="NO" # Запрещаем изменение hostname из jail

jail_socket_unixiproute_only="YES" # Разрешаем для jail обмен только по TCP/IP

jail_sysvipc_allow="NO" # Запрещаем SystemV IPC внутри jail

 

# Для jail с именем "svn"

jail_svn_rootdir="/usr/home/jails/svn" # Каталог jail

jail_svn_hostname="svn.reki.ru" # Имя хоста jail

jail_svn_ip="XX.YY.XX.TT" # IP адрес

jail_svn_exec="/bin/sh /etc/rc" # Скрипт инициализации

jail_svn_devfs_enable="YES" # Монтировать devfs в jail

Добавляем пользователя, под которым мы будем заходить в jail. Для этого можно воспользоваться командой:

# vipw -d /usr/home/jails/svn/etc

либо:

# pw -V /usr/home/jails/svn/etc useradd admin -g 0 -d /usr/home/jails/svn/usr/home/admin -s /bin/csh -h 0 -m

Для удобства работы присваиваем пользователю группу 0 (wheel) и разрешаем в jail запуск sshd. В файл /usr/home/jails/svn/etc/rc.conf добавляем строчку sshd_enable=YES изапускаем jail командой /etc/rc.d/jail start. Если все сделано правильно, команда jls(8) выведет примерно следующее:

# jls

JID IP Address Hostname Path

1 XX.YY.XX.TT svn.reki.ru /usr/home/jails/svn

Заходим в jail по ssh, получаем права суперпользователя, выкачиваем и разворачиваем архив дерева портов:

# ssh XX.YY.XX.TT -l admin

# su - root

# cd /usr

# fetch ftp://ftp.freebsd.org/pub/FreeBSD/ports/ports/ports.tar.gz

# tar -xzf ports.tar.gz

Начиная с этого момента jail представляет собой полноценную виртуальную машину, доступную для администрирования по ssh.

Устанавливаем веб-сервер Apache2

Для повышения общего уровня безопасности, будем авторизовывать клиента через подписанный нами сертификат; поэтому нам следует воспользоваться опцией FakeBasicAuth. При входе клиента с выданным нами сертификатом на сервер Apache произведет псевдоавторизацию, основываясь на данных сертификата.

Надо отметить, что при подобной авторизации имя пользователя выглядит как строка свойств сертификата. Соответственно при коммите через HTTPS имя пользователя будет не stellar, а /C=RU/ST=-/L=Moscow/O=Reki.ru/OU=SVN/CN=stellar/emailAddress=stellar@reki.ru. Понятно, что наличие в двух ипостасях одного и того же пользователя никого устроить не может и хорошим решением было бы взять в качестве логина часть строки данных сертификата. Дляэтого в Apache предусмотрена директива SSLUserName и... увы иах, мир несовершенен: без исправлений кода mod_ssl опции FakeBasicAuth и SSLUserName вместе не работают.

К счастью, по URL http://reki.ru/products/subversion/patch-server-ssl_engine_kernel.c, теперь доступен патч, исправляющий это недоразумение.

Для сборки Apache с поддержкой FakeBasicAuth + SSLUserName надо скачать патч и положить его в каталог /usr/ports/www/apache2/files. Если предполагается, чторепозиторий Subversion будет храниться в BerkeleyDB, намтакже будет необходимо включить поддержку BerkeleyDB дляApache.

Итак, устанавливаем необходимые переменные окружения и запускаем установку Apache.

# cd /usr/ports/www/apache2

# setenv WITH_BERKELEYDB db42

# cd files

# fetch http://reki.ru/products/subversion/patch-server-ssl_engine_kernel.c

# cd ../

# make install clean

Устанавливаем систему контроля версий Subversion

Поскольку предполагается, что доступ к SVN будет осуществляться по протоколу HTTPS, нам следует установить модуль mod_dav_svn. По умолчанию репозиторий SVN создается в каталоге /home/svn/repos.

# cd /usr/ports/devel/subversion

# setenv WITH_MOD_DAV_SVN yes

# setenv WITH_APACHE2_APR yes

# make install clean

Если требуется подсветка синтаксиса исходных файлов, устанавливаем программу enscript. В этом случае в файле конфигурации WebSVN следует включить поддежку enscript.

# cd /usr/ports/print/enscript-a4

# make install clean

Устанавливаем PHP4

PHP4 нам понадобится для WebSVN веб-фронтэнда репозитория. Для работы WebSVN необходимо установить расширения PHP для поддержки zlib и pcre.

# cd /usr/ports/lang/php4

# make install clean

# cd /usr/ports/lang/php4-extensions

# make install clean

Устанавливаем и настраиваем WebSVN

По умолчанию WebSVN устанавливается в /usr/local/www/data/WebSVN. Для наших целей придется скопировать его содержимое в каталог /usr/home/www/svn/svn.reki.ru/www.

# cd /usr/ports/devel/websvn

# make install clean

# mkdir -p /usr/home/www/svn/svn.reki.ru/www

# mkdir -p /var/log/apache/www/svn.reki.ru

# cp -r /usr/local/www/data/WebSVN /usr/home/www/svn/svn.reki.ru/www

// Правим файл конфигурации фронтэнда

# vi /usr/home/www/svn/svn.reki.ru/www/include/config.inc

Примерный вид файла конфигурации следующий:

// Указываем пути к программам svn, diff, sed, tar и gzip

$config->setSVNCommandPath("/usr/local/bin");

$config->setDiffPath("/usr/bin");

$config->setSedPath("/usr/bin");

$config->setTarPath("/usr/bin");

$config->setGZipPath("/usr/bin");

// Перечисляем все те репозитории, которые должны быть доступны через фронтэнд

$config->addRepository("Example Repository #1", "/usr/home/svn/example");

$config->addRepository(Example Repository #2", "/usr/home/svn/example2");

// Язык веб-интерфейса

include("languages/russian.inc");

// Кодировки веб-интерфейса

$config->setInputEncoding("windows-1251");

$config->setOutputEncoding("windows-1251");

// Включить кэширование данных для фронтэнда

$config->setCachingOn();

// Разрешить скачивание проекта в виде tar.gz-архива

$config->allowDownload();

// Включить подсветку синтаксиса программой enscript

$config->setEnscriptPath("/usr/local/bin");

$config->useEnscript();

Создаем сертификаты и конфигурируем серверное ПО

Создаем собственный самоподписанный сертификат (Certificate Authority, CA). Используя этот сертификат, мыбудем подписывать сертификат сервера и все клиентские сертификаты.

# openssl req -new -newkey rsa:1024 -x509 -days 3650 -nodes -out ca.crt -keyout ca.key -subj /C=RU/ST=-/L=Moscow/O=Reki.ru/OU=Certificate_Issuer/CN=reki.ru/emailAddress=admin@reki.ru

 

Перечислим список команд:

n req запрос на создание нового сертификата.

n -new cоздание запроса на сертификат (Certificate Signing Request, CSR).

n -newkey rsa:1024 длина RSA ключа сертификата.

n -x509 создание самоподписанного сертификата вместо создания CSR.

n -days 3650 срок действия сертификата (10 лет). Этозначение должно быть больше срока действия создаваемого сертификата сервера и клиентских сертификатов.

n -nodes флаг, указывающий не шифровать ключ.

n -out ca.crt сертификат.

n -keyout ca.key закрытый ключ сертификата.

n -subj данные сертификата.

 

Строка subj имеет следующие поля:

n С код страны (Country). Двухбуквенная аббревиатура.

n ST название республики, региона или округа (State Name).

n L название города/деревни (Locality Name).

n O организация (Organization Name).

n OU отдел организации (Organization Unit).

n CN имя. Для сервера ServerName; для клиентского сертификата что угодно.

n emailAddress почтовый адрес администратора сервера.

Для создания серверного и клиентских сертификатов вам понадобится либо воспользоваться стандартным файлом конфигурации openssl.cnf, который, как правило, находится в каталоге /etc/ssl, либо вручную создать собственный файл конфигурации (название файла ca.config):

[ca]

default_ca = CA_CLIENT

 

[CA_CLIENT]

dir = ./db # Рабочий каталог для базы данных клиентских ключей

certs = $dir/certs # Каталог для новых сертификатов

new_certs_dir = $dir/newcerts # Каталог, куда будут складываться выписанные сертификаты

 

database = $dir/index.txt # Индекс базы данных выписанных ключей

serial = $dir/serial # Номер текущего ключа

certificate = ./ca.crt # Собственный самоподписанный сертификат CA

private_key = ./ca.key # Закрытый ключ сертификата CA

 

default_days = 365 # Время, на которое выписывается клиентский сертификат

 

default_crl_days = 7 # Срок действия CRL

default_md = md5 # Алгоритм подписи

policy = policy_anything # Название секции политики

 

[policy_anything]

countryName = optional # Разрешаем не указывать код страны

stateOrProvinceName = optional # ------ // ------- название штата или округа

localityName = optional # ------ // ------- название города/деревни

organizationName = optional # ------ // ------- название организации

organizationalUnitName = optional # ------ // ------- название отдела

commonName = supplied # Обязательно указать имя.

emailAddress = optional # Почтовый адрес можно не указывать

Создаем структуру каталогов, описанную в секции [CA_CLIENT]

# mkdir -p /usr/local/etc/crt

# cd /usr/local/etc/crt

// Создаем и редактируем файл конфигурации

# vi ca.config

# mkdir ./db

# mkdir ./db/certs

# mkdir ./db/newcerts

# touch ./db/index.txt

# echo "01" > ./db/serial

Создаем сертификат сервера:

# openssl req -new -newkey rsa:1024 -nodes -keyout server.key -out server.csr -subj /C=RU/ST=-/L=Moscow/O=Reki.ru/OU=SVN/CN=svn.reki.ru/emailAddress=svn@svn.reki.ru

Для сертификата сервера тег CN должен содержать егоServerName. В данном случае это svn.reki.ru.

Подписываем сертификат собственным CA:

# openssl ca -config ca.config -in server.csr -out server.crt -batch

Устанавливаем сертификаты:

# cp server.crt /usr/local/etc/apache2/ssl.crt/server.crt

# cp server.key /usr/local/etc/apache2/ssl.key/server.key

# cp ca.crt /usr/local/etc/apache2/ssl.crt/ca.crt

Конфигурируем веб-сервер. Создаем необходимую структуру каталогов:

# mkdir -p /var/log/apache/www/svn.reki.ru

# mkdir -p /usr/home/www/svn/svn.reki.ru/www

В файл /usr/local/etc/apache2/ssl.conf прописываем конфигурацию виртуального веб-сервера:

<VirtualHost *:443>

 

DocumentRoot /usr/home/www/svn/svn.reki.ru/www

ServerName svn.reki.ru:443

ServerAdmin admin@svn.reki.ru

 

ErrorLog /var/log/apache/www/svn.reki.ru/error_log

CustomLog /var/log/apache/www/svn.reki.ru/access_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

 

SSLEngine on

 

SSLCipherSuite

ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL

 

SSLCertificateFile /usr/local/etc/apache2/ssl.crt/server.crt

SSLCertificateKeyFile /usr/local/etc/apache2/ssl.key/server.key

 

SSLCACertificateFile /usr/local/etc/apache2/ssl.crt/ca.crt

 

SSLVerifyClient require

# Пускаем только тех пользователей, которые имеют подписанные нами сертификаты

SSLVerifyDepth 1

 

<Location />

SSLVerifyClient require

# Для совместной работы этих опций

SSLOptions +FakeBasicAuth

SSLUserName SSL_CLIENT_S_DN_CN # необходим патч

AuthName "SVN"

AuthType Basic

AuthUserFile /usr/home/www/svn/svn.reki.ru/.htpasswd_ssl

require valid-user

</Location>

 

<Location /svn>

DAV svn # Обработчик DAV - svn

# общий каталог для репизиториев

SVNParentPath /usr/home/svn

 

AuthzSVNAccessFile /usr/home/www/svn/svn.reki.ru/.htauth_svn

 

require valid-user

</Location>

 

SetEnvIf User-Agent .*MSIE.* nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0

</VirtualHost>

Строчки, выделенные красным, указывает серверу, чтопринимать соединение необходимо только для тех клиентов, которые имеют правильный, то есть выданный нами сертификат. В строках, выделенных зеленым, мы имитируем авторизацию по паролю. Это необходимо для того, чтобы разрешить доступ к репозиторию SVN только тем пользователям, которым выдан личный сертификат SSL. Для этого мы указываем файл паролей, находящийся по адресу: /usr/home/www/svn/svn.reki.ru/.htpasswd_ssl. Его содержимое состоит из строки CN (commonName), которую мызадавали при создании пользовательского ключа, и магического заклинания xxj31ZMTZzkVA, являющегося DES-хэшем слова password.

stellar:xxj31ZMTZzkVA

oniks:xxj31ZMTZzkVA

Заметим, что поскольку это не настоящая авторизация (по-настоящему мы авторизуемся через сертификат), увсех пользователей один и тот же пароль: xxj31ZMTZzkVA: password.

Синие строки указывают, какой путь будет использоваться для https-доступа к SVN. Для нашего случая это https://svn.reki.ru/svn. Ввиду того, что мы планируем использовать Subversion для нескольких разных проектов одновременно, нам потребуется при помощи директивы SVNParentPath указать общий родительский каталог для всех репозиториев. Все репозитории из каталога /usr/home/svn будут доступны как https://svn.reki.ru/svn/имя_репозитория.

Теперь нам остается только раздать пользователям права доступа к проектам. Для этого используется директива AuthzSVNAccessFile, указывающая файл с описанием прав доступа к тому или иному репозиторию.

Формат файла следующий:

# имя репозитория:/путь

[example:/]

# Имена пользователей = права доступа

stellar = rw

oniks = rw

 

[example2:/]

stellar = rw

oniks = r

Пользователь stellar имеет полный доступ к репозиториям example и example1, а пользователь oniks полный доступ к example и право на чтение из example2.

Создаем репозитории

Поскольку мы условились, что будем использовать Subversion для двух проектов с именами example и example2, создаем два репозитория в каталоге /usr/home/svn:

# svnadmin create /usr/home/svn/example

# svnadmin create /usr/home/svn/example2

# chown -R www:www /usr/home/svn/

Структура проекта может быть произвольной, но общепринято создавать три основных каталога: branches для веток, tags для тегов проекта и trunk непосредственную рабочую область для коммитов. Чтобы каждый раз неделать одну и ту же работу, создаем шаблон проекта с основными каталогами и импортируем его в созданные репозитории:

# svnadmin create /usr/home/svn/example

# mkdir -p /usr/local/share/svn/skel

// Каталог с шаблоном репозитория

# cd /usr/local/share/svn/skel

# mkdir branches tags trunk

# svn import /usr/local/share/svn/skel/tree file:///usr/home/svn/example -m "initial import"

В дальнейшем можно создавать каталоги внутри проекта посредством команды svn add, удалять их командой svn delete. Права на каталоги репозиториев должны принадлежать пользователю, от которого запущен Apache.

В файл /etc/rc.conf добавляем строчки:

apache2_enable="YES"

apache2ssl_enable="YES"

и запускаем Apache:

# /usr/local/etc/rc.d/apache2.sh start

Если все сделано правильно, команда ps(1) покажет нечто похожее на это:

# ps axw | grep httpdvv

33928 ?? SsJ 0:03.31 /usr/local/sbin/httpd -k start -DSSL

81260 ?? IJ 0:00.01 /usr/local/sbin/httpd -k start -DSSL

81261 ?? IJ 0:00.00 /usr/local/sbin/httpd -k start -DSSL

81262 ?? IJ 0:00.00 /usr/local/sbin/httpd -k start -DSSL

81263 ?? IJ 0:00.00 /usr/local/sbin/httpd -k start -DSSL

81264 ?? IJ 0:00.00 /usr/local/sbin/httpd -k start -DSSL