OpenLDAP을 활용한 기반시스템 중앙 인증관리 #2

openldap Mar 11, 2016

OpenLDAP을 활용한 기반시스템 중앙 인증관리 #1에서 기반시스템과 연결을 위한 디렉토리 서비스를 구축하였다.

2편에서는 구축된 OpenLDAP 서비스를 활용하여 기반시스템을 인증처리 하는 것에 대해 정리해 본다.

보통 개발환경을 구축하게 되면 가장 많이 사용되는 기반시스템은 아래와 같다.

  • 형상관리 시스템
    • SubVersion
    • Git(Gitlab)
  • 이슈관리 시스템
    • Redmine
  • 코드 품질 점검 시스템
    • Sonarqube
  • CI(Continuis Intergration)
    • Jenkins
  • Reposiory manager
    • Nexus

형상관리 시스템은 최근엔 git이 대세이긴 하지만 아직까지 많은 현장에선 svn을 형상관리 시스템으로 많이 사용하고 있다.

특히나 SI 개발현장에서는 외부 인터넷이 단절되어 일하는 경우도 허다하니 github를 쓰는 건 더욱더 먼나라 얘기 인것 같고, 외주 개발자들이 많은 SI현장에서는 기존에 svn에 너무나도 익숙한 개발자들이 많기 때문에 쉽사리 git을 도입하는 사례가 많은 것 같진 않다.

그래도 최근엔 다니고 있는 회사에서 최근 형상관리+코드리뷰 시스템으로 git+gitlab을 활용해서 프로젝트를 진행해봤는데 사업초반엔 시행착오가 있긴 했지만 나름 적응해보니 "적용해 볼만 하다"라는 결론을 내놓긴 했다.

들어가기 앞서

예전에야 가상환경을 설치하고 운영하기 힘들 때라 한 머신에 다 때려 넣던지 2~3개 머신에 나누어서 환경 구성을 실시하곤 했는데, 최근엔 워낙 Xen Server, Docker, Virtual Box 같은 가상환경 구성이 많이 활성화 되어 있고 특히나 개발환경이나 기반시스템 구성은 적은 머신으로도 여러개의 서비스를 되도록 깔끔하게 구성할 수 있어 나도 최근엔 Xen Server로 기반 및 개발테스트 환경을 구성하고 있다.

개인적으로는 한 머신이미지에 다른 서비스는 추가하지 않고 여러 이미지로 관리하는게 가장 깔끔하게 기반시스템들을 운영하는 것 같다.

구성한 장비들이 모두 폐쇄망에서 구성을 해서 설정이나 구성 내용을 베껴오기가 쉽지 않아서 다시 한번 리마인드 차 아래의 샘플들은 전부다 osx에서 Virtual Box를 사용해서 시스템 별로 vm 만들고 설치 및 설정하는 것으로 구성하였으니 참고 바란다.

설치 환경은 Ubuntu 14.04 Server를 기준으로 작성하였다.

OpenLDAP + Subversion + Apache2

이제 Subversion을 설치하고 OpenLDAP에 연결하여 인증처리를 구성해 보자

설치

먼저 서비스할 내부 도메인을 설정한다.

FILE: /etc/hosts
127.0.1.1       svn.example.com svn
192.168.56.101  ldap.example.com ldap  #ldap 머신의 내부 dns 설정
192.168.56.102  svn.example.com svn

아래의 command로 subversion 접속을 위한 패키지를 모두 설치한다.

$ sudo apt-get update
$ sudo apt-get install subversion subversion-tools libapache2-svn apache2-utils apache2 libapache2-modsecurity libapache2-mod-perl2 libapache-dbi-perl libauthen-simple-ldap-perl

그리고 apache2 Global configuration에 ServerName 지시자를 추가한다.

$sudo vi /etc/apache2/apache2.conf
...
# Global configuration
ServerName svn.example.com
...

subversionOpenLDAP 연결을 위해 아래의 파일을 편집한다.

$ sudo vi /etc/apache2/mods-available/dav_svn.conf

기본 예제 설정 부분을 설정할 repository path에 맞게 수정하고 LDAP 설정 부분을 추가한다.

# Enables connection pooling (very useful for checkouts with many files)
PerlModule Apache::DBI
PerlOptions +GlobalRequest

# Enable Subversion logging
CustomLog ${APACHE_LOG_DIR}/svn_logfile "%t %u %{SVN-ACTION}e" env=SVN-ACTION

# Work around authz and SVNListParentPath issue
RedirectMatch ^(/repos)$ $1/
   
<Location /repos>

  # Uncomment this to enable the repository
  DAV svn

  # Set this to the path to your repository
  # 여러개 repository를 운영할 예정이므로 SVNPath 대신 SVNParentPath 설정
  # (/var/lib/svn/repo1, /var/lib/svn/repo2, ...).
  SVNParentPath /var/lib/svn

  # Basic Authentication is repository-wide. 
  AuthType Basic
  AuthName "Subversion Repository"
  
  # LDAP 사용을 위한 설정
  AuthType Basic
  AuthName "Subversion Repository"
  AuthBasicProvider ldap
  AuthLDAPUrl "ldap://ldap.example.com:389/ou=users,dc=example,dc=com?uid"
  AuthLDAPBindDN  cn=admin,dc=example,dc=com
  AuthLDAPBindPassword secret
  LDAPReferrals Off
  
  # 인증에 성공한 사용자는 모든 작업 가능
  Require valid-user

  # To enable authorization via mod_authz_svn (enable that module separately):
  #<IfModule mod_authz_svn.c>
  #AuthzSVNAccessFile /etc/apache2/dav_svn.authz
  #</IfModule>
  
  # WebDAV/DeltaV protocol 사용을 제한하는 경우 사용
  #<Limit GET PROPFIND OPTIONS REPORT>
  #  Require valid-user
  #</LimitExcept>
  #<LimitExcept GET PROPFIND OPTIONS REPORT>
  #  Require valid-user
  #</LimitExcept>

</Location>
NOTE: 대량의 파일을 업데이트 받는 경우 REPORT request 수행 시 413 Request Entity Too Large 메세지를 만날 수 있다. 
서버에서 허용하는 request size를 넘어가는 경우에 발생하는데 해당 오류는 <Location...> 태그 안에 "LimitXMLRequestBody 0" 설정을 통해 피할 수 있다. 

<Location ...>
  LimitXMLRequestBody 0  # disable size limit
</Location>

추가가 완료되면 관련 모듈들을 enable 시킨다.

# mod_dav_svn 모듈 활성화
$ sudo a2enmod dav_svn

# ldap 모듈 활성화
$ sudo a2enmod ldap
$ sudo a2enmod authnz_ldap

# perl 모듈 활성화
$ sudo a2enmod perl

Subversion Repository 생성

Apache2 설정을 완료하고 Subversion Repository를 생성하고 권한을 변경한다.

$ sudo mkdir /var/lib/svn
$ cd /var/lib/svn
$ sudo svnadmin create example
$ sudo chown -R www-data:www-data example

샘플로 example repository를 생성했고 이제 apache2를 재시작한다.

$ sudo service apache2 restart

최종 연결 확인

브라우저를 열어서 http://svn.example.com/svn/example로 접속한다.

로그인이 되면 아래처럼 repository를 사용할 수 있다.

테스트로 trunk 디렉토리를 만들어 보자.

$ svn mkdir http://svn.example.com/repos/example/trunk --parents -m "Create initial trunk directory" --username hkwon --password secret

Access Control

Subversion Repository의 권한을 관리하는 방법은 여러가지가 있는데 앞서 세팅한 부분은 ldap의 users에 등록된 모든 사용자는 어떤 Repository라도 모든 권한(rw)을 가지고 있다. (사실 내부에서만 사용할 용도이고 개발자가 많지 않다면 이 정도 설정에서 사용해도 무방한 것 같다.)

이 외에 몇가지 Access Control하는 방법을 간단히 정리해 보면 아래와 같으나 사실 LDAP group으로 편하게 권한 관리를 할 수 있는 방법은 없는 것 같다;; 개인적으로는 권한관리가 필요한 경우에는 AuthzSVNAccessFile 를 그냥 사용하는 편이 좋을 것 같다.

mod_authz_svn의 AuthzSVNAccessFile 지시어 사용

인터넷에 떠도는 거의 모든 샘플들은 AuthzSVNAccessFile 지시어를 사용하여 access를 관리하는 예제로 되어 있다. 한가지 마음에 안드는 점은 중앙에서 관리할 목적으로 ldap 을 사용하는데 그룹이나 유저별로 또 다른 설정 파일(AuthzSVNAccessFile)을 작성하고 관리해야하는 불편함이 있다.

Repository별로 Location 지시지를 생성하지 않아도 권한을 설정할 수 있어서 여러모로 좋긴 한데, 이 그룹이나 유저들이 LDAP DN 값으로 세팅이 되지 않고 수작업으로 넣어야 한다.

하지만 repository별로 유저나 그룹의 권한을 강력하게 관리해야 하는 경우는 별다른 대안은 또 찾기 어려웠다. repository별로 상세한 권한 설정을 원한다면 이것 외엔 대안은 없어보인다.

그룹이나 계정 별로 AuthzSVNAccessFile을 사용하려면 아래와 같이 한다.

$ sudo vi /etc/apache2/mods-available/dav_svn.conf
...
# 주석을 해제한다.
AuthzSVNAccessFile /etc/apache2/dav_svn.authz

/etc/apache2/dav_svn.authz을 다음과 같은 룰로 작성해서 repository 별 권한을 작성할 수 있다.

# 기본적인 문법
[reponame:repopath]
user = access

# 샘플
[example:/]
hkwon = r
user1 = rw
user2 =   # empty 면 액세스 불가

그룹 별로도 설정이 가능하다.

[groups]
dev = hkwon, user1

[example:/]
user2 = r
@dev = rw

종합해보면 아래처럼 사용이 가능하다.

[groups]
admin = hkwon
dev = hkwon, user1, user2

[/]
* = r

[example:/]
user3 = r
@dev = rw
@admin = rw

관리를 빡세개 하는 것도 중요하지만 관리 포인트가 한군데 더 늘어나는 것도 문제라면 문제 일 수 있다. 개인적으로 가능한 그룹별로 최대한 레파지토리 접근이 가능하도록 그룹 정책을 세우는 것이 해당 파일을 작성하는 것 보단 좋을 것 같다.

그래도 굳이 사용해야 한다면 Using LDAP Groups With Subversion's Authz File를 참조(ldap으로 붙어서 group 정보를 sync 맞춰와 파일로 생성해주는 파이썬 스크립트)하여 sync를 맞추고 작업할 수 있는 환경을 만들어 두고 관리하는 것이 좋을 듯 싶다.

혹은 * = rw 권한을 모두 주고 접속을 막을 사용자만 관리하는 것도 방법 일 수 있겠다.

AuthnProviderAlias 사용

또 한가지 ldap 그룹별로 repository 접속을 강제하는 설정은 AuthnProviderAlias 지시자를 활용하여 아래처럼 사용하면 될 것 같다.(테스트 해보진 않았음) 원래는 여러개의 ldap머신을 연결하는 경우 사용하는 설정인데 아래처럼 사용 가능해 보인다.

혹은 Require ldap-group, AuthLDAPSubGroupDepth, AuthLDAPUrl filter 등을 사용하여 그룹 별로 권한을 줄 수도 있는 것 같다

좀 더 자세한 내용은 Apache Module mod_authnz_ldap에서 확인해 볼 수 있다.

<AuthnProviderAlias ldap ldap-alias1>
    AuthLDAPBindDN  cn=admin,dc=example,dc=com
    AuthLDAPBindPassword secret
    AuthLDAPUrl "ldap://ldap.example.com:389/cn=admin,ou=groups,dc=example,dc=com?uid"
</AuthnProviderAlias>
<AuthnProviderAlias ldap ldap-other-alias>
    AuthLDAPBindDN  cn=admin,dc=example,dc=com
    AuthLDAPBindPassword secret
    AuthLDAPUrl "ldap://ldap.example.com:389/cn=dev,ou=groups,dc=example,dc=com?uid"
</AuthnProviderAlias>

<Directory "/example">
    AuthBasicProvider ldap-other-alias  ldap-alias1
    
    AuthType Basic
    AuthName "LDAP Protected Place"
    Require valid-user
    # Note that Require ldap-* would not work here, since the 
    # AuthnProviderAlias does not provide the config to authorization providers
    # that are implemented in the same module as the authentication provider.
</Directory>

OpenLDAP + Gitlab

github를 사용하지 못하는 폐쇄망 환경 등의 아주 몰상식한 상황에서는 그 대안으로 gitlab을 많이들 사용하고 있다. 어느 정도 이슈관리도 되고 코드리뷰에서도 약간의 강점을 보이고 있으니 생짜로 git server를 운영하는 것보단 훨씬 많은 이득이 있어 보인다.

이제 gitlab을 설치하고 LDAP 서버에 연결해 보자

설치

먼저 서비스할 내부 도메인을 설정한다.

FILE: /etc/hosts
127.0.1.1       gitlab.example.com svn
192.168.56.101  ldap.example.com ldap  #ldap 머신의 내부 dns 설정
192.168.56.103  gitlab.example.com gitlab  

설치형 오픈소스 버전인 GitLab Community Edition (CE) ubuntu 14.04 옴니버스 패키지로 설치를 진행한다.

설치 전에 기본 메일서버를 postfix로 사용하기 때문에 의존성이 걸려 있는 패키지를 먼저 설치한다.

$ sudo apt-get update
$ sudo apt-get install curl openssh-server ca-certificates postfix

postfix 설치는 인터넷 사이트 메일 호스트는 example.com으로 초기 설정하였다.

이제 gitlab에서 제공하는 설치 스크립트로 설치를 시작한다.

$ curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash
Detected operating system as Ubuntu/trusty.
Checking for curl...
Detected curl...
Running apt-get update... done.
Installing apt-transport-https... done.
Installing /etc/apt/sources.list.d/gitlab_gitlab-ce.list...done.
Importing packagecloud gpg key... done.
Running apt-get update... done.

The repository is setup! You can now install packages.
$ sudo apt-get install gitlab-ce
$ sudo add-apt-repository ppa:saiarcot895/myppa
$ sudo apt-get update
$ sudo apt-get -y install apt-fast
$ sudo apt-fast install gitlab-ce

설치가 완료되면 설정을 시작한다.

sudo gitlab-ctl reconfigure

인스톨이 완료되었으면 서버가 제대로 시작되었는지 확인한다.

$ sudo gitlab-ctl status
run: nginx: (pid 972) 7s; run: log: (pid 971) 7s
run: postgresql: (pid 962) 7s; run: log: (pid 959) 7s
run: redis: (pid 964) 7s; run: log: (pid 963) 7s
run: sidekiq: (pid 967) 7s; run: log: (pid 966) 7s
run: unicorn: (pid 961) 7s; run: log: (pid 960) 7s

시작과 종료는 아래의 command로 가능하다.

# Start all GitLab components
$ sudo gitlab-ctl start

# Stop all GitLab components
$ sudo gitlab-ctl stop

# Restart all GitLab components
$ sudo gitlab-ctl restart

초기 설정은 기본적으로 ldap 기능은 disable된 상태이다. ldap 연결 활성화를 위해 설정 파일을 수정한다. 설정 파일 위치는 옴니버스 패키지 설치 시 아래와 같다.

$ sudo vi /etc/gitlab/gitlab.rb

앞서 설치한 ldap 정보로 변경한다.

## For setting up LDAP
## see https://gitlab.com/gitlab-org/omnibus-gitlab/blob/629def0a7a26e7c2326566f0758d4a27857b52a3/README.md#setting-up-ldap-sign-in
## Be careful not to break the identation in the ldap_servers block. It is in
## yaml format and the spaces must be retained. Using tabs will not work.

gitlab_rails['ldap_enabled'] = true
gitlab_rails['ldap_servers'] = YAML.load <<-'EOS' # remember to close this block with 'EOS' below
  main: # 'main' is the GitLab 'provider ID' of this LDAP server
    label: 'LDAP'
    host: 'ldap.example.com'
    port: 389
    uid: 'uid'
    method: 'plain' # "tls" or "ssl" or "plain"
    bind_dn: 'CN=admin,DC=example,DC=com'
    password: 'secret'
    active_directory: false
    allow_username_or_email_login: true
    block_auto_created_users: false
    base: 'OU=users,DC=example,DC=com'
    user_filter: ''
    attributes:
      username: ['uid', 'userid', 'sAMAccountName']
      email:    ['mail', 'email', 'userPrincipalName']
      name:       'cn'
      first_name: 'givenName'
      last_name:  'sn'

설정 값은 별다르게 주의할 점은 없어보이고 알맞은 값만 주의해서 넣어주면 될 것 같다. 설정이 완료되면 gitlab재구성하고 재시작한다. 설정 파일은 실시간으로 반영은 안되고 reconfigure를 해줘야 반영이 된다.

$ sudo gitlab-ctl reconfigure
$ sudo gitlab-ctl restart

이제 http://gitlab.example.com으로 접속한다.

LDAP 로그인 탭이 보이고 이제 LDAP에 등록된 유저로 로그인이 가능하다. 하지만 먼저 신규 가입 기능 제거 등의 어드민 설정을 위해서 Standard 모드로 root 유저로 로그인 한다.

  • Username : root
  • Password : 5iveL!fe(초기패스워드)

초기 패스워드는 위와 같고 로그인 후 새로운 패스워드를 입력한다.

새로운 패스워드를 입력하면 새로 root유저로 로그인을 수행한다.

로그인 후에 오른쪽 상단에 스패너 아이콘을 클릭하고 왼쪽 Settings 메뉴를 클릭해서 _Sign-in Restrictions_에서 Sign-up enabledLDAP에 등록된 유저로만 사용하기 위해서 체크 해제한다. Save버튼으로 저장하는걸 잊지 말도록 한다.(두번이나 왜 저장 안되지 했네;;)

이제 다시 로그아웃 하면 다음과 같이 신규 가입 구역은 나오지 않는다 .

이제 Gitlab을 사용할 기본적인 환경은 구성이 되었고 LDAP으로 로그인이 가능하다.

SSL인증

만약 self-signed된 인증서로 https로 서비스를 해야 한다면 아래의 절차에 따라 구성한다.

sudo mkdir -p /etc/gitlab/ssl
sudo chmod 700 /etc/gitlab/ssl

#1편에서 ssl 구성했던 것과 동일한 절차로 인증서를 생성한다.

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/gitlab/ssl/gitlab.example.com.key -out /etc/gitlab/ssl/gitlab.example.com.crt

# Country Name (2 letter code) [AU]:KR
# State or Province Name (full name) [Some-State]:Seoul
# Locality Name (eg, city) []:Seoul
# Organization Name (eg, company) [Internet Widgits Pty Ltd]:Example Company
# Organizational Unit Name (eg, section) []:Example Section
# Common Name (e.g. server FQDN or YOUR name) []:gitlab.example.com
# Email Address []:admin@example.com

인증서 생성이 되면 gitlab.rb파일의 설정을 변경한다.

$ sudo vi /etc/gitlab/gitlab.rb
external_url 'https://gitlab.example.com'
...
################
# GitLab Nginx #
################
...
nginx['redirect_http_to_https'] = true
...

설정 파일을 수정 했으니 다시 시작한다.

$ sudo gitlab-ctl reconfigure
$ sudo gitlab-ctl restart

개인 별 ssh key 관리

git 서버에 pushpull 작업을 진행 할 땐 ssh key가 필요하다. Gitlab EE 버전에는 ldapssh key를 넣어두면 sync해 올 수 있는 기능이 있던데 아쉽게도 ce 버전에는 해당 기능은 없다~

처음 도입 시에는 관리자가 유저 별로 키 생성을 직접 하고 일괄 등록하는 프로세스로 일했는데 이 보단 개발자가 직접 로그인해서 자기 PC에서 키 생성(SSH help page 참조)하여 입력하는 프로세스로 처리하는 것이 서로서로에게 편할 것 같다.

git clone이나 https로 repository 연결 시 self signed 인증서 처리는 정광섭님의 개인위키에 정리를 잘해놓으셨으니 git 에서 https repository 연결시 SSL 인증서 오류 해결법를 참고 바란다.

osx의 경우에는 #1편에서 나와 있듯이 키체인에 등록되면 다 잘된다 ㅎㅎ

OpenLDAP + Redmine

다음은 프로젝트 관리 용도로 가장 많이들 쓰고 있는 Redmine을 설치하고 LDAP을 적용해 본다.

설치

먼저 서비스할 내부 도메인을 설정한다.

FILE: /etc/hosts
127.0.1.1       redmine.example.com redmine
192.168.56.101  ldap.example.com ldap  #ldap 머신의 내부 dns 설정
192.168.56.104  redmine.example.com gitlab  

Redmin 설치는 수동 설치부터 Bitnami package 설치까지 몇가지 옵션이 있는데 그간 신규 프로젝트 마다 여러가지 방법으로 설치해봤지만.. 여러모로 정신건강을 위해서는 Bitnami Redmine stack으로 설치하는 것을 강력하게 추천한다.

설치에 필요한 패키지를 미리 설치한다.

$ sudo apt-get update
$ sudo apt-get install wget ruby-dev make g++ gcc libssl-dev

포스팅 시점엔 3.2.02 버전이 recommended 버전이고 기존에 쓰고 있던 플러그인이 최신버전에서 문제 없이 동작한다면 최신버전을 설치한다.

$ wget https://bitnami.com/redirect/to/93261/bitnami-redmine-3.2.0-2-linux-x64-installer.run

기존에 gitlab을 설치했으므로 subversion, git, phpmyadmind은 설치하지 않고 redmine 만 설치하도록 한다. 자주 애용하던 플러그인 최신버전에서 동작하지 않는다면 해당 버전의 인스톨 버전을 다운받아야 한다.

$ sudo ./bitnami-redmine-3.2.0-2-linux-x64-installer.run
Language Selection

Please select the installation language
[1] English - English
[2] Spanish - Español
[3] Japanese - 日本語
[4] Korean - 한국어
[5] Simplified Chinese - 简体中文
[6] Hebrew - עברית
[7] German - Deutsch
[8] Romanian - Română
[9] Russian - Русский
Please choose an option [1] : 4
---------------------------------------------
Bitnami Redmine Stack 설치 마법사를 시작합니다.

---------------------------------------------
설치할 구성 요소를 선택하십시오. 설치하지 않을 구성 요소는 선택을 취소하십시오. 계속할 준비가 되면 다음을 클릭하십시오.

Subversion [Y/n] :n

PhpMyAdmin [Y/n] :n

Redmine : Y (Cannot be edited)

Git [Y/n] :n

위의 선택이 정확합니까? [Y/n]: y

---------------------------------------------
설치 경로

Bitnami Redmine Stack의 설치 경로를 선택하세요.

폴더 선택 [/opt/redmine-3.2.0-2]:

---------------------------------------------
Admin 계정 생성

Bitnami Redmine Stack 관리자 계정을 생성합니다.

이름 [User Name]: admin

이메일 주소 [user@example.com]: admin@example.com

로그인 계정명 [user]: admin

패스워드 :
패스워드를 재입력 :
---------------------------------------------
기본 데이터 설정에 사용할 언어

기본 데이터 설정 시 사용할 언어를 선택하세요.

[1] 불가리아어
[2] 체코어
[3] 독일어
[4] 영어
[5] 스페인어
[6] 프랑스어
[7] 히브리어
[8] 이탈리아어
[9] 일본어
[10] 한국어
[11] 네덜란드어
[12] 폴란드어
[13] 포르투갈어
[14] 포르투갈어/브라질어
[15] 루마니아어
[16] 러시아어
[17] 세르비아어
[18] 스웨덴어
[19] 중국어
[20] 중국어/대만어
옵션을 선택하십시오. [10] : 10

사용하시겠습니까? [y/N]: y

---------------------------------------------
SMTP 설정

어플리케이션에서 통보가 가능하도록 이메일 지원 기능을

기본 이메일 서비스 제공자

[1] GMail
[2] 사용자 정의
옵션을 선택하십시오. [1] : 2

---------------------------------------------
SMTP 설정

This data is stored in the application configuration files and may be visible to
others. For this reason, it is recommended that you do not use your personal
account credentials.

사용자명 []: admin

패스워드 :
재입력 :
SMTP 호스트 []: smpt.example.com

SMTP 포트 번호 [587]:

보안 접속

[1] 없음
[2] SSL
[3] TLS
옵션을 선택하십시오. [1] :

---------------------------------------------
이제 컴퓨터에 Bitnami Redmine Stack을(를) 설치할 준비가 되었습니다.

계속하시겠습니까? [Y/n]: y

설치가 완료되면 내부 dns 정보를 설정한다.

$ sudo vi /opt/redmine-3.2.0-2/apache2/conf/httpd.conf

ServerName 지시자를 수정한다.

...
#ServerName localhost:80
ServerName redmine.example.com
...

그리고 main page가 install page로 되어 있어 url로 접근하는데 매번 귀찮으로 기본적으로 접근하는 url이 /redmine으로 접근되도록 rewrite rule을 추가한다.

$ sudo vi /opt/redmine-3.2.0-2/apache2/conf/bitnami/bitnami.conf
...
<VirtualHost _default_:80>
  DocumentRoot "/opt/redmine-3.2.0-2/apache2/htdocs"
  # rewrite rule 추가
  RedirectMatch ^/$ http://redmine.example.com/redmine

  <Directory "/opt/redmine-3.2.0-2/apache2/htdocs">
    Options Indexes FollowSymLinks
    AllowOverride All
    <IfVersion < 2.3 >
      Order allow,deny
      Allow from all
    </IfVersion>
    <IfVersion >= 2.3 >
      Require all granted
    </IfVersion>
  </Directory>
...

이제 재시작하고 메인 화면에 접근해 본다.

sudo /opt/redmine-3.2.0-2/ctlscript.sh restart apache

테마 파일 적용

구관이 명관이라는 옛말을 나는 참 좋아한다. 이왕 쓰는거 좀 더 이쁘고 보기 좋은 것이 생산성 향상에도 도움이 된다고 믿기 때문에 좀 더 어여쁜 테마로 변경하도록 한다.

괜찮은 테마로는 A1, Circle, Flatly light, Highrise, flat, gitmike 등이 있고(나는야 테마 매니아;;) 2016년에 새로 등록된 Dwarf라는 테마가 상당히 미려하고 hd화면에서 아주 훌륭하게 보여준다. 해당 테마로 설치해보도록 한다.

임시 디렉토리에 Dwarf 프로젝트를 git clone하고 themes 디렉토리로 복사한다.

다른 테마들도 다운로드 받아서 themes 디렉토리로 복사하고 재시작하면 테마를 변경할 수 있다.

$ git clone https://github.com/themondays/Dwarf.git
$ cd Dwarf/production
$ sudo cp -R dwarf /opt/redmine-3.2.0-2/apps/redmine/htdocs/public/themes/dwarf
$ cd /opt/redmine-3.2.0-2/apps/redmine/htdocs/public/themes
$ sudo chown -R root:daemon /opt/redmine-3.2.0-2/apps/redmine/htdocs/public/themes/dwarf
$ sudo chmod -R 775 /opt/redmine-3.2.0-2/apps/redmine/htdocs/public/themes/dwarf

다시 한번 재시작 후 admin유저로 로그인 해서 관리>설정>표시방식>테마 를 변경한다.

스크린샷 2016-03-07 오후 2.46.42.jpg

그럼 이제 예쁘게 테마가 적용된 화면을 볼 수 있다.

LDAP 연결

자 이제 설치는 완료 했으니 LDAP 유저로 로그인 할 수 있도록 설정을 진행해 본다.

설정>>LDAP인증>>인증공급자 메뉴에서 새 인증 공급자 를 클릭한다.

LDAP 인증 공급자 정보 아래와 같이 입력하고 저장한다.

  • 이름
    • 인증 공급자로 등록할 이름을 등록한다.
    • example.com LDAP
  • 호스트
    • LDAP서버 호스트 정보를 입력한다.
    • ldap.example.com
  • 포트
    • LDAP서버 포트 정보를 입력한다.
    • 389
  • 계정
    • 기본 바인딩할 유저 dn 정보를 입력한다.
    • cn=admin,dc=example,dc=com
  • 비밀번호
    • 기본 바인딩할 유저의 패스워드 정보를 입력한다.
    • secret
  • 기본DN
    • 사용자를 조회할 기본 DN값을 입력한다.
    • ou=users,dc=example,dc=com
  • LDAP 필터
    • 그룹 필터 등을 넣을 경우 해당 필터를 입력한다. 샘플은 필터를 넣지 않는다.
  • 타임아웃
    • 기본 타임아웃 시간을 사용한다. 필요한 경우 타임아웃 시간을 입력한다.
  • 동적사용자 생성
    • Redmine은 기본적으로 자체 유저 패스워드 인증을 진행한다. 이 값이 체크되어 있지 않다면 기본DB에서 패스워드 인증만 되므로 LDAP 공급자를 사용하려면 반드시 해당 값을 체크해야 한다.
    • 체크!
  • 로그인 속성
    • Redmine에서 사용할 아이디 정보를 입력한다. cn 값이 아닌 uid를 사용하도록한다
    • uid
  • 이름 속성
    • 이름 속성에 맵핑되는 속성 정보를 입력한다.
    • givenName
  • 성 속성
    • 성 속성에 맵핑되는 속성 정보를 입력한다.
    • sn
  • 메일 속성
    • 메일 속성에 맵핑되는 속성 정보를 입력한다.
    • mail

이제 저장하고 admin 유저 로그 아웃 후 hkwon 유저로 로그인 해본다.

이제 LDAP 유저로 로그인 되었다. 이제 열심히 프로젝트 진행하면 된다 ㅎㅎ

플러그인 파일 적용

많이들 사용하고 있는 agile, people, checklist, [Redmine Git Hosting](Redmine Git Hosting) 등 플러그인들은 매뉴얼을 참조해서 원하는 플로그인을 설치한다.

레파지토리 관리 및 이슈관리에 대해서

사실 이 부분이 가장 애마한 부분이다. gitlab 자체에도 이슈관리로 사용하기에는 훌륭한 시스템이 준비되어 있기 때문에 redmine에서 굳이 소스에 관련된 이슈 관리 및 저장소 보기를 지원할 것인가는 고민해봐야 할 문제 같다. 이슈관리의 통합을 위해서는 모든 이슈는 Redmine에서 관리하는 것도 방법 일 순 있는데, 그렇다고 하면 Gitlab을 사용하는 이유가 별로 없어 보인다.

해서 직접 소스 수정과 관련된 버그/이슈 관리는 gitlab을 통해서 진행하고, 프로젝트 마일스톤이나 프로젝트 관리에 따르는 기타 이슈들은 Redmine에서 관리하는 것으로 진행하는 것도 방법일 것 같다.

정답은 없는 것 같고 개발자와 관리자가 편한 방법으로 진행하면 될 것 같다.

개인적은로는 git 지원이 아직 원할한것 같진 않고 gitlab을 병행해서

Redminegit 연동과 관련해 잘 정리 해놓은 몇가지 블로그들의 주소를 남겨 놓는다.

OpenLDAP + Sonarqube

다음은 품질점검 도구로 가장 많이 쓰이는 Sonarqube를 설치하고 LDAP 연동을 진행해보겠다.

설치 및 LDAP 연결

먼저 서비스할 내부 도메인을 설정한다.

FILE: /etc/hosts
127.0.1.1       sonarqube.example.com sonarqube
192.168.56.101  ldap.example.com ldap  #ldap 머신의 내부 dns 설정
192.168.56.106  sonarqube.example.com sonarqube  

Sonarqube는 LTS 버전과 Lastest 버전으로 항상 나뉘어서 릴리즈 되는데 오랫동안 써와서인지 굳이 LTS 버전을 설치할 이유는 없어 보이고 시스템 자체가 미션크리티컬한 시스템은 아니다 보니 최신기능이 많이 포함되어 있는 마지막 버전을 설치하는 편이다.

포시팅 시점엔 5.3 버전까지 나와 있고 설치를 진행해 본다.

Sonarqube는 패키지 버전은 없고 공식홈페이지에서 제공하는 zip 버전을 unzip하면 되고, 관리용도의 DB가 필요하다. DB는 mysql을 설치하도록 한다.

mysql 설치 및 유저 생성

mysql 및 필요소프트웨어 설치를 진행한다.

$ sudo apt-get update
$ sudo apt-get install mysql-server unzip default-jdk
# root 패스워드는 꼭 잊지말자 ㅎㅎ
$ wget https://sonarsource.bintray.com/Distribution/sonarqube/sonarqube-5.3.zip

Sonarqube 용도의 유저를 생성한다.

$ mysql -u root -p
mysql> CREATE DATABASE sonar CHARACTER SET utf8 COLLATE utf8_general_ci;
mysql> CREATE USER 'sonar' IDENTIFIED BY 'sonar';
mysql> GRANT ALL ON sonar.* TO 'sonar'@'%' IDENTIFIED BY 'sonar';
mysql> GRANT ALL ON sonar.* TO 'sonar'@'localhost' IDENTIFIED BY 'sonar';
mysql> FLUSH PRIVILEGES;

Sonarqube 배포판 다운로드 및 설치 위치 변경

$ wget https://sonarsource.bintray.com/Distribution/sonarqube/sonarqube-5.3.zip
$ unzip sonarqube-5.3.zip
$ sudo mv sonarqube-5.3 /opt/sonar

서비스 등록

관리의 편의를 위해 init.d 서비스로 등록한다.

$ sudo cp /opt/sonar/bin/linux-x86-64/sonar.sh /etc/init.d/sonar
$ sudo vi /etc/init.d/sonar

가장 첫 라인에 아래의 내용을 추가하고 수정한다.

...
# 절대 경로로 운영하기 위한 변수 추가
SONAR_HOME=/opt/sonar
PLATFORM=linux-x86-64
...
# Wrapper
WRAPPER_CMD="${SONAR_HOME}/bin/${PLATFORM}/wrapper"
WRAPPER_CONF="${SONAR_HOME}/conf/wrapper.conf"
...
# Location of the pid file.
PIDDIR="/var/run"
...

이제 서비스로 등록한다.

$ sudo update-rc.d -f sonar remove
$ sudo chmod 755 /etc/init.d/sonar
$ sudo update-rc.d sonar defaults

Sonarqube 설정 파일 수정

db, 웹서버, ldap 설정을 위해 설정 파일을 편집한다.

$ sudo vi /opt/sonar/conf/sonar.properties
# User credentials.
# Permissions to create tables, indices and triggers must be granted to JDBC user.
# The schema must be created first.
sonar.jdbc.username=sonar
sonar.jdbc.password=sonar

#----- MySQL 5.x
# Only InnoDB storage engine is supported (not myISAM).
# Only the bundled driver is supported. It can not be changed.
sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance

#----- WEB SERVER
sonar.web.host=sonarqube.example.com
sonar.web.port=80
...

LDAP 플러그인 설치 및 설정

LDAP과의 연결을 위해서는 LDAP Plugin을 다운받아 플러그인 설치를 해야 한다. 플러그인 설치는 해당 jar파일을 SONARQUBE_HOME/extensions/plugins에 넣고 재시작하면된다.

$ cd /opt/sonar/extensions/plugins
$ wget https://sonarsource.bintray.com/Distribution/sonar-ldap-plugin/sonar-ldap-plugin-1.5.1.jar

LDAP 설정을 위해 다시 한번 sonar.properties 파일을 편집하고 아래의 내용을 추가한다.

#---------------------------------------------
# LDAP congiguration
# General Congifuration
sonar.security.realm=LDAP
sonar.security.savePassword=true
sonar.security.updateUserAttributes=true
sonar.authenticator.createUsers=true

# User Congiguration
ldap.authentication=simple
ldap.url=ldap://ldap.example.com:389
ldap.bindDn=cn=admin,dc=example,dc=com
ldap.bindPassword=ekfskfk11

ldap.user.baseDn=ou=users,dc=example,dc=com
ldap.user.request=(&(objectClass=inetOrgPerson)(uid={login}))
ldap.user.realNameAttribute=cn
ldap.user.emailAttribute=mail

기존에 계속 설정해왔던 것과 마찬가지로 bindDn과 baseDn 값을 유의하여 작성하면 된다.

이제 모든 설정이 완료 됐고 Sonarqube를 시작한다.

$ sudo ufw allow http
$ sudo service sonar start
Starting SonarQube...
Started SonarQube.

브라우저에서 http://sonarqube.example.com 로 접속한다.

로그인 버튼을 눌러서 LDAP 유저로 로그인을 시도한다.

hkwon 유저로 로그인이 정상처리되는 것을 볼 수 있다.

주제가 인증과 관련된 주제라 Sonarqube 관련한 코드 품질점검과 관련해서는 나중에 별도에 포스트로 한번 정리해 볼 예정이다. ^^

OpenLDAP + Jenkins

이제 뭐 Jenkins 없는 개발은 상상할 수 없을 정도로 CI 서버도 기반시스템 구축작업에 있어서 빠지지 않는 단골 손님이다. 빌드부터 배포까지 맘만 먹으면 못하는게 없을 정도로 팔방미인이 되버렸다. 더군다나 엄청난 플러그인이 현재까지도 계속 만들어지고 있으니 개발자의 삶을 아주 윤택하게 해주는 통합 빌드 도구다.

할 수 있는게 막강한 만큼 보안에도 신경을 많이 써야 하기 때문에 일단 LDAP을 통해 중앙인증을 실시하도록 한 후 Job들의 권한이나 기타 설정은 상황에 맞게 잘 설정해야 한다.

본 포스팅에서는 권한 관리까지는 가지 않고 LDAP 연결만 진행하도록 하겠다.

설치

먼저 서비스할 내부 도메인을 설정한다.

FILE: /etc/hosts
127.0.1.1       jenkins.example.com jenkins
192.168.56.101  ldap.example.com ldap  #ldap 머신의 내부 dns 설정
192.168.56.107  jenkins.example.com jenkins

Debian 계열의 리눅스 배포판은 apt-repository를 제공해줘서 쉽게 패키지로 설치가 가능하다. 설치 자체가 크게 어렵지 않아서 패키지 설치가 아니더라도 공식 홈페이지의 설치 문서만 보고도 쉽게 설치가 가능하다.

$ wget -q -O - https://jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -
$ sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list'
$ sudo apt-get update
$ sudo apt-get install jenkins

설치 시 다음과 같은 오류 발생시 아래와 같이 조치하면 된다.

처리하는데 오류가 발생했습니다:
 jenkins
E: Sub-process /usr/bin/dpkg returned an error code (1)

$ sudo apt-get clean
$ sudo apt-get purge jenkins-common
$ sudo apt-get install jenkins

포트 번호는 기본적으로 8080을 사용하므로 80포트로 변경한다.

기본적으로 java로 실행하기 때문에 80 포트에 대한 권한이 없어서 proxy 해줄 수 있는 웹서버를 두던지 포트포워딩을 해야한다.

공식 설치 문서에서는 포트포워딩하는 법으로 나와 있으니 그대로 수행하면 된다.

$ sudo vi /etc/rc.local

멀티레벨 유저로 로그인 시 iptable에 등록하면 되고 라우팅을 고정으로 세팅해도 된다.

# Requests from outside
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080
# Requests from localhost
iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 8080

이제 서비스를 시작하고 브라우저로 접근하면 사용할 준비가 되었다.

 $ sudo service jenkins start

LDAP 플러그인은 기본적으로 설치되어 있기 때문에 보안설정에서 LDAP 관련 설정을 진행할 수 있다.

Jenkins 관리>Configure Global Security 로 들어간다. 아마 처음 설치 시에는 보안 관련 warning 메세지가 보이고 보안설정 버튼을 클릭해도 된다.

Enable security를 체크하고 아래의 같이 LDAP 정보를 입력한다. 입력되는 정보는 지금까지 설치한 시스템과 거의 동일하게 세팅하면 된다.

  • 서버 : ldap://ldap.example.com:389
  • root DN : dc=example,dc=com
  • User search base : ou=users
  • User search filter : uid={0}
  • Manager DN : cn=admin,dc=example,dc=com
  • Manager Password : secret
  • Display Name LDAP attribute : displayName
  • Email Address LDAP attribute : mail

자세한 설정 정보를 아래의 url을 참조하면 된다.

이제 로그인을 해보자.

정상적으로 로그인이 되는 것을 확인 할 수 있다.

LDAP으로 로그인한 유저는 기본적으로 ROLE_ADMIN 권한을 가지고 있으므로 관리자는 보안 설정에서 Matrix-based security 등 Authorization 설정을 통해 사용자 별 권한을 별도로 관리해야 한다.

OpenLDAP + Nexus Repository Manager

드디어 마지막 Nexus 설치 및 LDAP 연동을 진행해보자.

maven이나 gradle을 빌드툴로 사용한다면 nexus 사용은 거의 필수적이다.

내부 라이브러리나 maven central repository에서 제공되지 않는 라이브러리 등을 사용하거나 매우 빌어먹을 폐쇄망 환경에서 일하는 경우 반드시 설치해서 운영해야 하는 기반시스템 중에 하나이다.

설치

먼저 서비스할 내부 도메인을 설정한다.

FILE: /etc/hosts
127.0.1.1       nexus.example.com nexus
192.168.56.101  ldap.example.com ldap  #ldap 머신의 내부 dns 설정
192.168.56.107  nexus.example.com nexus  

Sonarqube와 마찬가지로 패키지 설치버전은 제공하지 않으므로 제공되는 zip버전을 해제 후 설치를 진행한다.

$ sudo apt-get update
$ sudo apt-get install unzip default-jdk

# nexus 설치용 유저를 선택한다. optioanl 
$ sudo adduser --no-create-home --disabled-login --disabled-password nexus
$ sudo passwd nexus

$ wget http://download.sonatype.com/nexus/oss/nexus-2.12.0-01-bundle.zip
$ unzip nexus-2.12.0-01-bundle.zip
$ sudo mkdir /opt/nexus-bundle
$ sudo mv nexus-2.12.0-01 /opt/nexus-bundle/nexus
$ sudo chown -R nexus:nexus /opt/nexus

다음은 서버 시작을 위한 설정을 진행한다.

$ sudo vi /opt/nexus-bundle/nexus/bin/nexus
...
# Set this to the root of the Nexus installation
NEXUS_HOME="/opt/nexus-bundle/nexus"
...
# NOTE - This will set the user which is used to run the Wrapper as well as
#  the JVM and is not useful in situations where a privileged resource or
#  port needs to be allocated prior to the user being changed.
RUN_AS_USER=nexus
...
# Location of the pid file.
PIDDIR="/opt/nexus-bundle"

context path도 "/"로 변경한다.

$ sudo vi /opt/nexus-bundle/nexus/conf/nexus.properties
nexus-webapp-context-path=/

서비스 등록

서비스로 등록한다.

$ sudo cp /opt/nexus-bundle/nexus/bin/nexus /etc/init.d/nexus
$ sudo chmod 755 /etc/init.d/nexus
$ sudo chown root /etc/init.d/nexus
$ sudo update-rc.d nexus defaults

포트포워딩

서비스로 등록은 했지만 nexus 유저로는 80으로 서비스가 안되므로 포트포워딩을 실시한다.

포트 번호는 기본적으로 8081을 사용하므로 80포트로 포트포워딩한다.

$ sudo vi /etc/rc.local

멀티레벨 유저로 로그인 시 iptable에 등록하면 되고 라우팅을 고정으로 세팅해도 된다.

# Requests from outside
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080
# Requests from localhost
iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 8080

서버 재시작 후 이제 nexus 서버를 시작한다.

$ sudo service nexus start

이제 브라우저로 http://nexus.example.com 접근해본다.

LDAP 설정

먼저 admin 유저로 로그인 한다. 기본 패스워드는 admin123이다.

어드민 패스워드는 일단 원하는 값으로 변경해 두도록 한다.

LDAP 설정을 하기 위해서는 인증 보안 설정을 먼저 등록해야 한다. Administration>Server>Security Settings 메뉴에서 OSS LDAP Authentication Realem을 활성화 해야한다.(save는 잊지말자)

그리고 Security>LDAP Configuraion 에서 LDAP 설정을 진행한다.

? 버튼을 클릭하면 친절하게 설명해주니 위에서 설정한 것과 동일한 방식으로 설정해주면 된다. 그룹 매핑이 필요한 경우에는 체크 후 설정하면 된다.

  • Connection
    • Protocol : ldap
    • Hostname : ldap.example.com
    • Port :389
    • Search Base : dc=example,dc=com
  • Authentication
    • Authentication Method : Simple Authentication
    • Username : cn=admin,dc=example,dc=com
    • Password : secret
  • User Element Mapping
    • Base DN : ou=users
    • Object Class
    • User ID attribute : uid
    • Real Name attribute : displayName
    • E-mail Attribute : mail

모든 설정값을 넣고 Check User Mapping 버튼을 클릭하면 친절하게 연결 후 속성을 잘 가져오는지 체크할 수 있다.

저장하고 ldap 유저로 로그인 하면 유저 등록은 정상적으로 되는데 Forbidden 오류가 나올 것이다. LDAP 유저는 아무런 권한이 없어서 인데 매뉴얼을 찾아봐도 그룹설정을 하지 않으면 기본 ROLE을 지정할 수 있는 방법은 없는 것 같다.

Security>Users 메뉴에서 관리자가 상응하는 권한을 주면 로그인이 가능하다.

자세한 ROLE 설정이나 권한 설정은 매뉴얼 페이지를 활용바란다.

nexus의 경우에는 관리자 권한을 가진 사람만 거의 접근하기 때문에 일반 개발자는 보통 조회만 하는 편이라 내부에서만 사용하는 경우라면 굳이 LDAP 연결까지는 진행하지 않아도 되지 않을까 싶다.

정리하며

지금까지 OpenLDAP을 활용하여 아래의 기반시스템들의 인증을 중앙관리하는 방법을 정리해보았다.

  • 형상관리 시스템
    • SubVersion
    • Git(Gitlab)
  • 이슈관리 시스템
    • Redmine
  • 코드 품질 점검 시스템
    • Sonarqube
  • CI(Continuis Intergration)
    • Jenkins
  • Reposiory manager
    • Nexus

갈수록 소프트웨어 개발은 복잡해지고 이제는 혼자서 모든걸 개발하는 시대는 거의 종말하지 않았나 싶다.

개발부터 품질점검, 이슈관리, 테스트, 배포 모든 영역에 있어 기반시스템의 사용은 거의 필수적으로 이루어지고 있고, 효율적으로 협업할 수 있도록 지원해주니 사용하지 않을 이유가 없다.

그리고 이러한 기반시스템들과 관련된 오픈소스들도 더 효율적인 방향이나 트렌드에 맞게 시시각각 변화하고 있으니, 한번 해봤다고 잊어버릴게 아니라 꾸준히 관심을 가지고 지켜봐 보는 것도 좋을 것 같다.


최대한 오류 없이 작성해보려고 했는데, 실수를 한 부분도 있으니 오류나 지적사항 있으시며 언제라도 얘기해주세요~

참고

Tags

권혁

백발까지 코딩하고 싶은 상부상조 프로그래머

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.