Инженер-программист компьютерных систем и сетей
0,0
рейтинг
28 декабря 2015 в 13:44

Разработка → Окружение разработки: Redmine + Git + ownCloud из песочницы

Данная статья появилась с целью обобщить довольно длительные попытки собрать удобное окружение для работы над проектами. Несомненно, существует множество сервисов готовых предоставить схожую функциональность, но их использование не всегда удобно и по различным причинам, может быть неприемлемо. Если возникла такая ситуация, надеюсь, представленная в статье конфигурация окажется полезной.



Сценарий использования данной связки, можно кратко описать следующим образом:

  • Файлы проекта хранятся в Git репозитории;
  • Репозиторий содержит настройки, исходники и другие файлы проекта, наличие которых удобно и допустимо в коллективном репозитории;
  • В корне расположена директория cloud, исключенная в .gitignore, в которую через WebDAV монтируется ownCloud папка, для остальных файлов;
  • Содержимое Git репозитория отслеживается в системе управления проектами Redmine.


План развертывания системы включает настройку следующих сервисов:

  1. OpenLDAP — единая учётная запись для всех сервисов;
  2. Redmine — запуск в Docker контейнере, создание и привязка Git репозитория, LDAP аутентификация;
  3. NGINX — доступ к Git репозиторию через HTTPS и LDAP аутентификация;
  4. ownCloud — LDAP аутентификация и монтирование папки через davfs2.


Жёсткой привязки к дистрибутиву и операционной системе, здесь нет. Однако у меня на сервере Linux дистрибутив Gentoo, на клиенте — Kubuntu, поэтому некоторые примеры будут иметь специфические особенности.

Для удобства воспроизведения часть примеров содержит предустановленные пароли. Поэтому настоятельно рекомендую вместо метки [ВНЕШНИЙ_IP] использовать локальный IP, не доступный извне, либо сразу менять пароли на надёжные.

OpenLDAP



LDAP — это протокол доступа к данным, организованным в виде директорий. Здесь будет рассмотрена его реализация — OpenLDAP. Данный сервис представляет собой по сути базу данных оптимизированную для хранения древовидных структур, таких как каталоги. В данном случае важно, что LDAP хорошо подходит для хранения данных пользователя и является стандартом, который так или иначе поддерживает большинство сервисов работающих с учетными записями пользователей.

Минимально необходимая конфигурация:

# /etc/openldap/slapd.conf

include		/etc/openldap/schema/core.schema
include		/etc/openldap/schema/cosine.schema
include		/etc/openldap/schema/inetorgperson.schema
include		/etc/openldap/schema/nis.schema

# Необходимо разрешить чтение записи cn=Subschema для всех.
access to dn.base="" by * read
access to dn.base="cn=Subschema" by * read

# Разрешение на чтение для cn=manager,dc=example,dc=com.
# Нужно, чтобы не использовать rootdn при настройке сторонних сервисов.
access to dn.regex=".+,dc=example,dc=com$"
	by self write
	by dn.exact="cn=manager,dc=example,dc=com" read
	by anonymous auth

# Всем остальным разрешить только авторизацию и изменение своих записей.
access to *
	by self write
	by anonymous auth
	by * none

pidfile		/var/run/openldap/slapd.pid
argsfile	/var/run/openldap/slapd.args

# Бинарное поле задающие уровень отладочной информации в логах.
# Обычно хватает 1 или 2, в тяжелых случаях - 256 (максимум 2048).
loglevel 0

modulepath    /usr/lib64/openldap/openldap

# Сертификаты для поддержки LDAPS.
TLSCertificateFile	/etc/ssl/openldap/server.pem
TLSCertificateKeyFile	/etc/ssl/openldap/server.key

### Основная база данных

database	hdb
# Директория должна существовать и иметь права 700 и владельца ldap:ldap.
directory	/var/lib/openldap-data
# Суффикс запросов, предназначенных этой базе.
suffix		"dc=example,dc=com"
# DN (Distinguished Name) на которую не распространяются ограничения в правах.
# Физическое наличие в БД этой записи не обязательно.
rootdn		"cn=admin,dc=example,dc=com"
# Пароль к rootdn, создается с помощью slappasswd -s [пароль]
# Здесь для примера использован пароль: passwd
rootpw		{SSHA}70m8+2axDu++Adp6EOLPVpISPxbMVPFv

# Оверлей для добавление к записи пользователя атрибута memberOf с DN группы, в которой он упомянут.
moduleload memberof.la
overlay memberof
memberof-group-oc groupOfUniqueNames
memberof-member-ad uniqueMember
memberof-refint true

# Оверлей для поддержания ссылочной целостности.
# При удалении пользователя, записи о нем в группах, также удаляются.
moduleload refint.la
overlay refint
refint_attributes uniqueMember
# Пустая группа не допустима. Очевидное решение, добавить администратора.
refint_nothing "cn=admin,dc=example,dc=com"

# Индексы для базы данных.
index   objectClass                             eq
index   uid,uidNumber,gidNumber,memberUid       eq


Для наглядности конфигурация здесь записана в файле slapd.conf, однако начиная с OpenLDAP версии 2.4 данный файл объявлен устаревшим. Новый формат называется OLC (on-line configuration) и представлен в виде базы данных config. Удобен он тем, что изменение настроек больше не требует перезагрузки сервиса.

Для миграции на OLC необходимо в конец файла slapd.conf добавить:

### База данных с настройками

# Изменять настройки разрешено только суперпользователю (root) через сокет.
# Ex: ldapadd/ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f [config_update].ldif
database config
access to *
	by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
	by * none


И выполнить команды:

mkdir -p /etc/openldap/slapd.d
# Если slapd ещё не запускался, ошибку об отсутствии файла базы данных можно игнорировать.
slaptest -f /etc/openldap/slapd.conf -F /etc/openldap/slapd.d
chown ldap:ldap -R /etc/openldap/slapd.d /var/lib/openldap-data /etc/openldap/slapd.conf
chmod 750 /etc/openldap/slapd.d && chmod 640 /etc/openldap/slapd.conf


Настройки будут записаны в указанную папку, по прежнему в текстовом виде, но редактировать вручную их уже не стоит.

Далее необходимо изменить параметры запуска демона, чтобы он читал настройки из базы данных вместо файла. В Gentoo для этого нужно изменить файл /etc/conf.d/slapd:

# /etc/conf.d/slapd

# Читать настройки из файла.
#OPTS_CONF="-f /etc/openldap/slapd.conf"
# Читать настройки из базы данных.
OPTS_CONF="-F /etc/openldap/slapd.d"
# Сервис доступен извне по протоколу ldaps; локально - ldap либо через сокет (%2f - так нужно).
OPTS="${OPTS_CONF} -h 'ldaps://[ВНЕШНИЙ_IP]:636 ldap://127.0.0.1:389 ldapi://%2fvar%2frun%2fopenldap%2fslapd.sock'"


Теперь можно запустить сервис и добавить данные:

Содержимое файла backup.ldif
dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
dc: example
o: Example.com

dn: ou=people,dc=example,dc=com
objectClass: organizationalUnit
ou: People

dn: ou=groups,dc=example,dc=com
objectClass: organizationalUnit
ou: Groups

dn: uid=example,ou=people,dc=example,dc=com
cn: Example User
givenName: User
sn: Example
uid: example
uidNumber: 1001
gidNumber: 1000
homeDirectory: /var/www/example.com
mail: example@example.com
objectClass: top
objectClass: posixAccount
objectClass: shadowAccount
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
loginShell: /sbin/nologin
userPassword: {SSHA}1zGVasPHdQ7LXhBJxzAOseflZiqlecKT

dn: cn=manager,dc=example,dc=com
cn: Manager
objectClass: top
objectClass: simpleSecurityObject
objectClass: organizationalRole
userPassword: {SSHA}KihawPs8IchHTS/Lc7aqKGd1rfkpEKyi

dn: cn=developers,ou=groups,dc=example,dc=com
objectClass: groupOfUniqueNames
cn: developers
description: Developers
uniqueMember: uid=example,ou=people,dc=example,dc=com


ldapadd -x -D 'cn=admin,dc=example,dc=com' -w 'passwd' -f backup.ldif


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

slappasswd -s [пароль]


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

Проверить, что OpenLDAP корректно настроен и работает как было задумано, можно командой:

ldapsearch -D 'cn=manager,dc=example,dc=com' -w 'passwd' -b 'ou=people,dc=example,dc=com' '(uid=example)' memberOf


Ответ должен быть следующим:

…
dn: uid=example,ou=people,dc=example,dc=com
memberOf: cn=developers,ou=groups,dc=example,dc=com

# search result
search: 2
result: 0 Success
…


Кроме тестового пользователя, здесь был также добавлен cn=manager,dc=example,dc=com, который будет использован в дальнейшем для доступа к базе данных. Права его должны быть минимально необходимыми, а пароль отличаться от пароля cn=admin,dc=example,dc=com, так как его придётся указывать чистым текстом в файлах настроек. Здесь использован пароль passwd, что несомненно является плохим примером.

Работа с записями в OpenLDAP далеко не самое удобное и очевидное дело, но Apache Directory Studio может существенно с этим помочь.

Redmine



Для управления проектами очень хорошо подходит веб приложение Redmine. Однако его установка требует большого числа зависимостей языка Ruby. Моя деятельность не связана с Ruby или Rails, поэтому установка на сервер дополнительных 76 пакетов, которые требовал ebuild, была не желательна. Приемлемый вариант нашёлся очень быстро — Docker контейнер sameersbn/docker-redmine.

Контейнеры удобно настраивать и запускать с помощью docker-compose. Данная утилита позволяет объединить параметры командной строки Docker в один конфигурационный файл и управлять запущенными контейнерами.

Возможности настройки docker-redmine очень широкие и работу с ним лучше сразу начать с официальной документации. Приведённый ниже пример, лишь один из вариантов, который оказался удобным в моём случае:

Настройки Redmine контейнера
# /var/www/redmine.example.com/docker-compose.yml

redmine:
  image: quay.io/sameersbn/redmine:3.2.0-2
  # Автоматически запускать при старте системы и перезапускать в случае падения
  restart: always
  environment:
    - TZ=Europe/Moscow
    # Использовать в контейнере uid:gid локального пользователя, чтобы 
    # владелец файлов, на хосте в смонтированных томах, был предсказуем.
    - USERMAP_UID=[NGINX_UID]
    - USERMAP_GID=[NGINX_GID]
    - DB_TYPE=postgres
    # Docker-у требуется существенное время, чтобы поднять bridge IP (172.17.0.1), и лучше
    # с ним не связывать сервисы запускаемые при старте системы. Выставлять сервис наружу,
    # без крайней необходимости, тоже плохая идея. Можно добавить на сетевой интерфес IP,
    # который не маршрутизируется наружу и обращаться к нему из контейнеров.
    - DB_HOST=10.0.10.10
    - DB_USER=redmine
    - DB_PASS=[ПАРОЛЬ]
    - DB_NAME=redmine_production
    - REDMINE_HTTPS=true
    - REDMINE_PORT=10083
    - SMTP_ENABLED=true
    - SMTP_OPENSSL_VERIFY_MODE=none
    # Локальная MTA доверяет подсети Docker-а 172.17.0.0/16, что в данном случае приемлемо.
    - SMTP_HOST=[ВНЕШНИЙ_IP]
    - SMTP_PORT=25
    - IMAP_ENABLED=false
  ports:
    - "127.0.0.1:10083:80"
  volumes:
    - /var/www/redmine.example.com/data:/home/redmine/data
    # Чтобы далеко не ходить за логами.
    - /var/www/redmine.example.com/logs:/var/log/redmine



Запуск контейнера производится командой:

docker-compose -f /var/www/redmine.example.com/docker-compose.yml up -d


Для того, чтобы Redmine автоматически создавал учётные записи на базе аккаунтов из OpenLDAP и использовал его механизм аутентификации необходимо добавить соответствующий метод в Administration → LDAP authentication → New authentication mode:

Name *: Example.com LDAP
Host *: [ВНЕШНИЙ_IP]
Port *: 636; LDAPS: x
Account: cn=manager,dc=example,dc=com
Password: passwd
Base DN *: ou=people,dc=example,dc=com
LDAP filter: (&(objectClass=person)(memberOf=cn=developers,ou=groups,dc=example,dc=com))
Timeout (in seconds):
On-the-fly user creation: x

Login attribute *: uid
Firstname attribute: givenName
Lastname attribute: sn
Email attribute: mail


В Redmine проект можно добавлять только уже существующие Git репозитории, поэтому папка с репозиториями должна быть доступна из контейнера. Поскольку в данном случае нужно отслеживать только локально расположенные репозитории, можно ограничиться монтированием в контейнер папки с репозиториями, но это не удобно. Если потребуется подключить внешний репозиторий, то его клон придётся разместить в директории с собственными репозиториями, кроме этого монтировать в контейнер системную директорию не красиво.

В итоге у меня получились следующий набор скриптов для работы с локальными репозиториями:

Скрипт для создания нового Git репозитория
#!/bin/bash
set -e

# /var/git/create_repo.sh

LOCAL_GIT_DIR="/var/git"
SCRIPT_NAME=`basename $0`
E_OPTERROR=65

function usage()
{
	echo "USAGE:"
	echo "    $SCRIPT_NAME [repo_name]"
	echo "OPTIONS:"
	echo "    repo_name - name of the new Git repository."
	exit $E_OPTERROR
}

function fatal_error()
{
	echo "$1" > /dev/stderr
	exit 1
}

# Проверить входные параметры.
if [ $# -ne 1 ]; then
	echo "Wrong number of arguments specified."
	usage
fi

REPO_NAME=$1

cd ${LOCAL_GIT_DIR}
if [ -d "${REPO_NAME}" ]; then
	fatal_error "Error: the repository already exists!"
fi

# Создать чистый репозиторий.
mkdir ${REPO_NAME}
cd ${REPO_NAME}
git --bare init
git update-server-info -f

# Установить хук синхронизирующий Redmine копию репозитория с данным.
cd ..
cp ./post-update "${REPO_NAME}/hooks/"
chmod 755 "${REPO_NAME}/hooks/post-update"
chown -R nginx:nginx ${REPO_NAME}

echo "Git repository successfully created."
exit 0



Скрипт для миграции существующего Git репозитория
#!/bin/bash
set -e

# /var/git/migrate_repo.sh

LOCAL_GIT_DIR="/var/git"
REDMINE_GIT_DIR="/var/www/redmine.example.com/data/git"
SCRIPT_NAME=`basename $0`
E_OPTERROR=65

function usage()
{
	echo "USAGE:"
	echo "    $SCRIPT_NAME [repo_name]"
	echo "OPTIONS:"
	echo "    repo_name - name of the existing Git repository."
	exit $E_OPTERROR
}

function fatal_error()
{
	echo "$1" > /dev/stderr
	exit 1
}

# Проверить входные параметры.
if [ $# -ne 1 ]; then
	echo "Wrong number of arguments specified."
	usage
fi

REPO_NAME=$1

if [ ! -d "${LOCAL_GIT_DIR}/${REPO_NAME}" ]; then
	fatal_error "Error: the repository does not exists!"
fi

# Проверить, что ничего не будет сломано.
if [ -f "${LOCAL_GIT_DIR}/${REPO_NAME}/hooks/post-update" ]; then
	fatal_error "Error: post-update hook already exists! The repository already migrated or should be migrated manually."
fi

if [ -d "${REDMINE_GIT_DIR}/${REPO_NAME}" ]; then
	fatal_error "Error: redmine already contains the repository with the same name!"
fi

# Установить хук синхронизирующий Redmine копию репозитория с данным.
cp "${LOCAL_GIT_DIR}/post-update" "${LOCAL_GIT_DIR}/${REPO_NAME}/hooks/"
chown nginx:nginx "${LOCAL_GIT_DIR}/${REPO_NAME}/hooks/post-update"
chmod 755 "${LOCAL_GIT_DIR}/${REPO_NAME}/hooks/post-update"

# Создать Redmine копию репозитория.
cd "${REDMINE_GIT_DIR}"
git clone --mirror "${LOCAL_GIT_DIR}/${REPO_NAME}" ${REPO_NAME}

echo "Git repository successfully migrated."
exit 0



Хук для синхронизации Redmine копии репозитория с локальным
#!/bin/bash

# /var/git/post-update

# Запускается на сервере после того, как git push успешно отработает в локальном репозитории.

REDMINE_GIT_DIR="/var/www/redmine.example.com/data/git"
REPO_PATH=${PWD}
REPO_NAME=$(basename "${REPO_PATH}")
LOG_FILE="/var/log/nginx/git_hooks_log"

function log_message()
{
	echo `date '+%d-%m-%y %H:%M:%S'` "$1" >>"${LOG_FILE}"
}

if [ -d "${REDMINE_GIT_DIR}" ]; then
	cd "${REDMINE_GIT_DIR}"
	if [ -d "${REPO_NAME}" ]; then
		# Если копия репозитория уже создана, загрузить изменения.
		cd "${REPO_NAME}"
		log_message "UPDATED: ${PWD}"
		exec git fetch -q --all -p &>>"${LOG_FILE}"
	else
		# Иначе создать клон репозитория.
		log_message "NEW: ${REPO_PATH} : ${REPO_NAME} : ${PWD}"
		exec git clone -q --mirror ${REPO_PATH} ${REPO_NAME} &>>"${LOG_FILE}"
	fi
fi



В случае необходимости подключить внешний репозиторий, например GitHub, его также необходимо будет клонировать в папку /var/www/redmine.example.com/data/git, затем установить задачу в cron для периодической синхронизации Redmine копии с удаленным репозиторием.

NGINX



Далее необходимо открыть доступ к репозиториям по HTTPS. К сожалению, из коробки NGINX не поддерживает LDAP авторизацию, для этого его необходимо собрать со сторонним модулем kvspb/nginx-auth-ldap.

В Gentoo для этого достаточно скопировать ebuild в локальный portage (PORTDIR_OVERLAY) и добавить в него данный модуль. В официальном ebuild подключается множество модулей, добавить ещё один не составит труда. Для актуальной на данный момент версии NGINX, у меня получился следующий патч:

Patch добавляющий модуль http_auth_ldap для nginx-1.8.0.ebuild
--- nginx-1.8.0.ebuild	2015-08-05 14:31:19.000000000 +0300
+++ nginx-1.8.0.ebuild.new	2015-08-07 08:19:35.899578187 +0300
@@ -126,6 +126,12 @@
 HTTP_MOGILEFS_MODULE_URI="http://www.grid.net.ru/nginx/download/nginx_mogilefs_module-${HTTP_MOGILEFS_MODULE_PV}.tar.gz"
 HTTP_MOGILEFS_MODULE_WD="${WORKDIR}/nginx_mogilefs_module-${HTTP_MOGILEFS_MODULE_PV}"
 
+# http_auth_ldap (https://github.com/kvspb/nginx-auth-ldap, ??? license)
+HTTP_AUTH_LDAP_MODULE_PV="master"
+HTTP_AUTH_LDAP_MODULE_P="ngx_http_auth_ldap-${HTTP_AUTH_LDAP_MODULE_PV}"
+HTTP_AUTH_LDAP_MODULE_URI="https://github.com/kvspb/nginx-auth-ldap/archive/${HTTP_AUTH_LDAP_MODULE_PV}.tar.gz"
+HTTP_AUTH_LDAP_MODULE_WD="${WORKDIR}/nginx-auth-ldap-${HTTP_AUTH_LDAP_MODULE_PV}"
+
 inherit eutils ssl-cert toolchain-funcs perl-module flag-o-matic user systemd versionator multilib
 
 DESCRIPTION="Robust, small and high performance http and reverse proxy server"
@@ -148,7 +154,8 @@
 	nginx_modules_http_security? ( ${HTTP_SECURITY_MODULE_URI} -> ${HTTP_SECURITY_MODULE_P}.tar.gz )
 	nginx_modules_http_push_stream? ( ${HTTP_PUSH_STREAM_MODULE_URI} -> ${HTTP_PUSH_STREAM_MODULE_P}.tar.gz )
 	nginx_modules_http_sticky? ( ${HTTP_STICKY_MODULE_URI} -> ${HTTP_STICKY_MODULE_P}.tar.bz2 )
-	nginx_modules_http_mogilefs? ( ${HTTP_MOGILEFS_MODULE_URI} -> ${HTTP_MOGILEFS_MODULE_P}.tar.gz )"
+	nginx_modules_http_mogilefs? ( ${HTTP_MOGILEFS_MODULE_URI} -> ${HTTP_MOGILEFS_MODULE_P}.tar.gz )
+	nginx_modules_http_auth_ldap? ( ${HTTP_AUTH_LDAP_MODULE_URI} -> ${HTTP_AUTH_LDAP_MODULE_P}.tar.gz )"
 
 LICENSE="BSD-2 BSD SSLeay MIT GPL-2 GPL-2+
 	nginx_modules_http_security? ( Apache-2.0 )
@@ -180,7 +187,8 @@
 	http_push_stream
 	http_sticky
 	http_ajp
-	http_mogilefs"
+	http_mogilefs
+	http_auth_ldap"
 
 IUSE="aio debug +http +http-cache ipv6 libatomic luajit +pcre pcre-jit rtmp
 selinux ssl userland_GNU vim-syntax"
@@ -220,7 +228,8 @@
 	nginx_modules_http_auth_pam? ( virtual/pam )
 	nginx_modules_http_metrics? ( dev-libs/yajl )
 	nginx_modules_http_dav_ext? ( dev-libs/expat )
-	nginx_modules_http_security? ( >=dev-libs/libxml2-2.7.8 dev-libs/apr-util www-servers/apache )"
+	nginx_modules_http_security? ( >=dev-libs/libxml2-2.7.8 dev-libs/apr-util www-servers/apache )
+	nginx_modules_http_auth_ldap? ( net-nds/openldap )"
 RDEPEND="${CDEPEND}
 	selinux? ( sec-policy/selinux-nginx )
 "
@@ -440,6 +449,11 @@
 		myconf+=" --add-module=${HTTP_MOGILEFS_MODULE_WD}"
 	fi
 
+	if use nginx_modules_http_auth_ldap; then
+		http_enabled=1
+		myconf+=" --add-module=${HTTP_AUTH_LDAP_MODULE_WD}"
+	fi
+
 	if use http || use http-cache; then
 		http_enabled=1
 	fi



Вариант конфигурации NGINX для хоста git.example.com:

# /etc/nginx/conf.d/git.example.com.ssl.conf

# Сокет сервиса fcgiwrap, должен быть доступен на запись пользователю nginx:nginx.
upstream fastcgi-server {
	server unix:/run/fcgiwrap.sock-1;
}

ldap_server ldap_git_users {
	# ldap[s]://hostname:port/base_dn?attributes?scope?filter
	url "ldap://127.0.0.1:389/ou=people,dc=example,dc=com?uid?sub?(objectClass=person)";
	# DN с ограниченными правами.
	binddn "cn=manager,dc=example,dc=com";
	binddn_passwd passwd;
	# Поиск пользователей непосредственно в группе без использования memberOf оверлея.
	group_attribute uniqueMember;
	# Атрибут должен содержать полный DN участника группы.
	group_attribute_is_dn on;
	# satisfy any;
	require group "cn=developers,ou=groups,dc=example,dc=com";
}

# Связь репозитория с пользователем в LDAP.
# $repo - репозиторий полученный из URL в location; $repo_login - авторизованный пользователь.
map $repo $repo_login {
	default "";
	# Можно разрешить доступ одному пользователю к нескольким репозиториям.
	"example.com" "example";
}

# Редирект на HTTPS
server {
	listen [ВНЕШНИЙ_IP]:80;

	server_name git.example.com;
	return 301 https://git.example.com$request_uri;
}

# HTTPS
server {
	listen [ВНЕШНИЙ_IP]:443 ssl;

	add_header Strict-Transport-Security max-age=2592000;

	server_name git.example.com;
	charset utf-8;

	ssl_certificate /etc/ssl/nginx/git.example.com.pem;
	ssl_certificate_key /etc/ssl/nginx/git.example.com.key;
	ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

	access_log /var/log/nginx/nginx_git.example.com-ssl_access_log main;
	error_log /var/log/nginx/nginx_git.example.com-ssl_error_log info;

	# Директория по умолчанию для аутентифицированных пользователей.
	# Если пользователь не авторизован для доступа в репозиторий, в этой папке он и останется.
	root /var/git/empty;

	# Статичные файлы Git репозитория.
	location ~ "^/(?<repo>[^/]+)/objects/([0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))$" {
		auth_ldap "git::repository";
		auth_ldap_servers ldap_git_users;
		# значение переменной $repo_login получается сопоставлением в map переменной $repo
		if ($remote_user = $repo_login) {
			root /var/git;
		}
	}

	# Запросы к репозиторию, которые необходимо направить на git-http-backend.
	location ~ "^/(?<repo>[^/]+)/(HEAD|info/refs|objects/info/[^/]+|git-(upload|receive)-pack)$" {
		auth_ldap "git::repository";
		auth_ldap_servers ldap_git_users;

		fastcgi_param SCRIPT_FILENAME /usr/libexec/git-core/git-http-backend;
		fastcgi_param PATH_INFO $uri;
		fastcgi_param GIT_HTTP_EXPORT_ALL "";
		fastcgi_param GIT_PROJECT_ROOT /var/git;
		fastcgi_param REMOTE_USER $remote_user;
		include fastcgi_params;

		if ($remote_user = $repo_login) {
			fastcgi_pass fastcgi-server;
		}
	}

	# Если репозиторий не найден вернуть 404.
	location / {
		return 404;
	}
}


ownCloud



Облачное хранилище ownCloud уже содержит всё необходимое для работы с LDAP. Достаточно зайти в Apps → Not enabled найти «LDAP user and group backend» и нажать Enable. В результате в настройках появится пункт LDAP. Нужно перейти на него и, в закладке Server, указать уже привычные настройки:

SERVER: 127.0.0.1; Port: 389
DN: cn=manager,dc=example,dc=com
PASS: passwd
BASEDN: ou=ou=people,dc=example,dc=com


Для того, чтобы на следующей закладке заработал выбор группы, нужно зайти в Advanced → Directory Settings и изменить следующие настройки:

Group Display Name Field: cn
Base Group Tree: ou=groups,dc=example,dc=com
Group-Member association: uniqueMember


Однако даже после этого у меня нашлась только одна posixGroup, что было явно не достаточно. Поскольку настройки позволяют указать все фильтры вручную, то проще и надёжнее воспользоваться именно этой функцией. Для этого на закладке Server желательно включить настройку «Manually enter LDAP filters», затем прописать все фильтры вручную:

Users: (&(objectClass=person)(memberOf=cn=developers,ou=groups,dc=example,dc=com))
Login Attributes: (&(objectClass=person)(memberOf=cn=developers,ou=groups,dc=example,dc=com)(uid=%uid))
Groups: здесь ничего указывать не нужно, эта настройка добавляет в ownCloud дополнительные группы пользователей.


Закончив с этим, можно перейти в Users и убедиться, что все необходимые пользователи присутствуют в списке.

Для монтирования ownCloud папки с помощью davfs2, необходимо на стороне клиента добавить следующие строки в файлы:

/etc/davfs2/davfs2.conf

use_locks 0

/etc/davfs2/secrets

/home/<user>/workspace/example/cloud example "passwd"

/etc/fstab

https://cloud.example.com/remote.php/webdav /home/<user>/workspace/example/cloud davfs user,noauto 0 0


И, наконец, пример альяса wo (work on) для активации рабочего окружения на примере Django проекта:

# ~/.bashrc

alias wo=" \
    mkdir -p ~/workspace/example/cloud && \
    (mountpoint -q ~/workspace/example/cloud || mount ~/workspace/example/cloud) && \
    cp -u ~/workspace/example/cloud/deploy/settings_local.py ~/workspace/example/src/project/settings_local.py && \
    source ~/VEnvs/example/bin/activate && \
    cd ~/workspace/example/src \
"


Все файлы конфигураций и скрипты, использованные в статье, можно найти на GitHub

Александр Борисенко @custos
карма
9,0
рейтинг 0,0
Инженер-программист компьютерных систем и сетей
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (7)

  • 0
    Эмм, ну это коненчо круто, но больше бы хотелось статью как это всё использовать в повседневной практике, а не как настроить (гуглить все умеют).
    • +1
      Практика тут как раз совсем простая. В репозитории не удобно хранить весь хлам сопутствующий проекту. Например: заметки, документацию, временные файлы, оставлять там пароли тоже не желательно, а иметь к этим файлам такой же простой доступ как к репозиторию, хочется. Проблема как раз собрать это всё в кучу… например Redmine хорошо работает с SVN, но подключить к нему Git репозиторий не просто. Централизованного хранить учетные записи удобно, но NGINX настроить для этого целая проблема, ровно как и остальные сервисы, LDAP он такой и т.п. и т.д.
      гуглить все умеют

      Эта статья точно бы не появилась, если бы у меня сходу всё нагуглилось и заработало.

      Если есть конкретные вопросы, я с радостью отвечу. Дело в том, что пользуюсь этим уже полгода и только утряс все проблемы, может уже что-то примелькалось…
  • +3
    Redmine отлично интегрировался с гитом, в том числе и с gitlab'ом, что более эффективный вариант т.к. в гитлабе есть merge request'ы. Плюс у нас ещё mediawiki использовалась.
    • 0
      Да, интегрирован он хорошо, меня всё устраивает. Сложность была в том, что в отличии от Subversion, он не умеет создавать Git репозитории, поэтому спрятать всё в контейнер не было возможности.
      Спасибо за упоминание gitlab, пока с ним не сталкивался, обязательно попробую.
  • +1
    Для обновления локального git репозитория для Redmine из Gitlab, мы используем Web hooks на Push events. Довольно удобно получается. В Redmine используем для этого плагин Redmine GitLab Hook plugin.
    • 0
      Интересная схема, спасибо. Ушел разбираться с gitlab.
  • +2
    Можно еще посмотреть phabricator.org

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.