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

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

지금까지 프로젝트 진행하면서서 기반시스템(svn, jenkins, sonarqube, redmine, nexus...)은 개별 시스템 별로 유저를 관리하거나 admin 계정이나 다른 하나의 계정으로만 사용을 해왔었다.

몇명 안되는 개발자들 데리고 일할 때는 큰 문제가 되지 않았는데 2~3년전부터 점점 프로젝트 규모수행하는 인원도 커지다 보니 이게 매번 개별 시스템 별로 계정을 생성하거나 관리하는게 아주 귀찮은 일이 되버렸다.

단적으로 아래와 같이 몇가지 마음을 심란하게 만드는 괴랄한 상황들이 나타나기 시작했다.

  • 시스템 별로 아이디나 비밀번호를 달리하는 개발자... "아니 왜??"
  • 심지어 아이디나 비밀번호를 자꾸 까먹는 개발자... "아니 왜왜왜??"
  • 작년의 경우에는 개발자가 많을 땐 70명정도 되고 수시로 나갔다 들어왔다 중간에 하도급 바뀌고 개발자 교체 ㅜㅜ
  • 기타등등.. 수도 없다..

그래서 새로 시작하는 프로젝트에서는 그동안 바쁘고 귀찮다는 핑계로 미뤄왔던 LDAP을 기반으로 하는 중앙 계정관리를 위한 디렉토리 서비스를 구축해서 운영하고 있다.

진작에 좀 할걸! 올해 프로젝트 진행하면서 정말 크게 느낀점이다. 진작 해 놓을 걸 왜 또 찾아보기 귀찮고 그 동안의 습관이나 관례로 그냥 버텨왔던게 어리석을 따름이다.

LDAP Directory Service를 사용한 중앙인증 시작하기

구축작업을 시작하기 앞서 LDAPDirectory Service에 대해 간략히 정리해 본다.

LDAP이란

LDAP(Lightweight Directory Access Protocol)이란 네트워크 상에서 조직이나 개인정보 혹은 파일이나 디바이스 정보 등을 찾아 보는 것을 가능하게 만든 소프트웨어 프로토콜이다.

LDAP은 네트워크 상의 디렉토리 서비스 표준인 X.500DAP(Directory Access Protocol)를 기반으로한 경량화(Lightweight)된 DAP 버전이다.

X.500의 DAP는 OSI 전체 프로토콜 스택을 지원하며 운영에 매우 많은 컴퓨팅 자원을 필요로 하는 아주 무거운 프로토콜이다. 이런 DAP의 복잡성을 줄이기 위해 만들어진 LDAP은 TCP/IP 레벨에서 더 적은 비용으로 DAP의 많은 기능적인 부분을 조작할 수 있도록 설계되었다고 한다.

초창기에는 X.500의 DAP를 액세스하기 위한 게이트웨이로 많이 쓰였다고 하는데 최근엔 X.500 DAP보다 더 일반적으로 디렉토리 서비스를 추축하기 위해 사용되고 있다고 한다.

더 자세한 관련된 RFC 스펙들은 공통 LDAP RFC을 확인하면 된다. (MS가 정리 깔끔하게 해놨네)

Lightweight Directory

Lightweight Directory는 우리가 흔히 접하는 데이터베이스와 유사한 데이터베이스(?) 의 일종이다라고 표현해 볼 수 있겠다. (명확하게는 데이터베이스가 아니다! 라는 사람들도 있지만 이해의 편의를 위해..)

LDAP 요청의 99%는 검색(Lookup)에 대한 요청이다.

  • 홍길동의 전화번호를 달라
  • 사원 그룹의 이름들을 달라
  • 산출물 그룹의 문서를 달라
  • ...

Directory 안에는 연락처, 유저, 파일, code 뭐가 됐든 일단 넣을 수는 있고 insert나 update보단 빠른 검색 요청에 특화되어 있다.

일반 데이터베이스(RDBMS)와는 다르게 검색에 특화되어 있기 때문에 트랜잭션 기능이나 롤백 기능이 없고, 복잡한 관계 등을 설정하지도 않는다. 또한 신뢰성이나 가용성을 개선하기 위해 쉽게 복제 될 수 있는 아키텍처로 이루어져 있다.

디렉토리 정보(entry)는 계층적 트리(hierarchical tree-like) 구조로 아래와 같이 구성된다.

dc:         com
             |
           domain         ## (Organisation)
          /      \
ou:   People   servers    ## (Organisational Units)
      /    \     ..
uid: ..  H.Kwon           ## (OU-specific data)

Entry 정보 참조는 RDN(Relative Distinguished Name)이나 DN(Distinguished Name)을 사용해서 정보를 얻어올 수 있다. 예를 들면 아래와 같이 H.Kwon 유저 정보를 조회할 수 있다.

  • RDN uid=H.Kwon
  • DN of uid=H.Kwon,ou=People,dc=domain,dc=com.

어떤 경우에 사용하는게 좋을까?

특정 데이터를 중앙에서 일괄 관리하는 일반적인 경우에 사용할 수 있다.

  • 유저 권한 관리
  • 주소록
  • 조직도
  • 사용자 정보 관리
  • 어플리케이션/시스템 설정 정보
  • 공개 키 인프라스트럭처
  • DHCP, DNS등의 저장소
  • 문서 관리
  • 이미지 저장소
  • Code
  • ...

위처럼 중앙관리가 필요하고 검색에 최적화된 서비스 용도라면 다른 어떤 경우라도 사용은 가능할 것 같다.

이 포스팅은 유저 인증 관리를 중앙에서 할 목적으로 LDAP을 활용해 Directory 서비스를 활용하는 것으로 계속 이어가겠다.

LDAP 서버 구축 - OpenLDAP

Directory 서비스를 위한 LDAP 서버를 구축하기 위해선 여러가지 옵션이 존재한다. Windows Server 라이센스를 가지고 있다면 Active Directory가 적합할 것이고 여러가지 상용 제품군도 존재한다.

오픈소스 중에는 OpenLDAPApache DS, OpenDJ, 389 Directory Server가 가장 많이 쓰이며 이 중에서 이미 수많은 리눅스 배포판에도 패키징되어 있고 비교적 다른 오픈소스보다 문서화가 잘되어 있고, 트러블 슈팅(StackOverflow에도 tag수가 가장 많다.)에도 수월한 OpenLDAP을 선정하여 진행했다.

설치에 사용된 환경은 Ubuntu 14.04 server LTS 을 사용했고 이하 샘플은 모두 해당 환경에서 작성되었다.

OpenLDAP, 관련 Helper 유틸리티 설치

$ sudo apt-get update
$ sudo apt-get install slapd ldap-utils

포스팅 시점엔 OpenLDAP은 2.4.44 버전까지 릴리즈 되어 있는데 Ubuntu 기본 레파지토리에는 2.4.31버전이 올라와 있으므로 더 최신 버전을 사용하려면 직접 소스를 받아 설치하면 된다.
하지만 특별한 버그 리포팅 사유가 없는한 정신건강을 위해 패키지 관리자 사용을 권한다;;

설치 중간에 LDAP administrator 패스워드를 물어보는데 나중에 설정을 통해 변경할 수 있으니 설치 시점엔 아무값이나 입력해도 상관없다.

OpenLDAP 재설정

기본 설치 시에는 관리자 패스워드 말고는 세부설정을 할 수 없으므로 패키지 설치 후 기본설정을 유지하지 않고 재설정을 진행한다.

$ sudo dpkg-reconfigure slapd
 * Stopping OpenLDAP slapd                           [ OK ]
  Moving old database directory to /var/backups:
  - directory unknown... done.
  Creating initial configuration... done.
  Creating LDAP directory... done.
 * Starting OpenLDAP slapd                           [ OK ]
Processing triggers for libc-bin (2.19-0ubuntu6.6) ...

재설정을 진행하면 LDAP 서버를 구성하기 위한 중요한 몇가지 정보들을 설정할 수 있다.

  • Omit OpenLDAP server configuration?
    • No
    • 말그대로 생략하지 않고 설정 바로 GO
  • DNS domain name:
    • example.com
    • LDAP 디렉토리의 base DN 값을 설정하기 위한 DNS 이름을 넣는다.
    • 예를 들어 "example.com"의 base DN은 "dc=example, dc=com"이 된다.
  • Organization name:
    • devops
    • LDAP 디렉토리의 Base DN이 사용하는 조직 이름을 알맞게 넣는다.
  • Administrator password:
    • secret
    • LDAP 디렉토리의 admin 엔트리의 패스워드를 입력/재입력한다.
  • Database backend to use:
    • HDB
    • 사용할 데이터베이스 유형을 설정하는데 HDB를 권고하고 있다. HBD와 BDB는 유사한 저장 포맷이지만 HDB는 서브트리 재설정으르 지원한다고 한다. 둘 다 같은 설정을 지원하기 때문에 나중에 저장 포맷을 변경해도 문제는 되지 않는 것 같다.
    • 두 포맷에 대한 자세한 내용은 /usr/share/doc/slapd/README.DB_CONFIG.gz 를 확인하면 된다.
  • Do you want the database to be removed when slapd is purged?
    • No
    • slapd를 삭제하였을 때 데이터베이스를 삭제할지에 대한 옵션이다.
    • 사람일이라는게 어떻게 될지 모르니 No를 선택한다.
  • Move old database?
    • Yes
    • 이미 /var/lib/ldap에 데이터베이스가 생성되어 있는 경우 이전 데이터베이스를 이동시킨다.
    • 이전 데이터베이스는 /var/backups로 이동된다.
  • Allow LDAPv2 protocol?
    • No
    • 현재 LDAP 프로토콜 버전은 LDAPv3이고 slapd는 기본적으로 LDAPv2 프로토콜은 사용 가능하지 않는 상태로 설정된다. 기존에 LDAPv3버전을 지원하지 않는 클라이언트 프로그램이 있다면 Yes로 선택한다.
    • 나중에 필요한 경우 slapd.conf 파일에서 'allow bind_v2' 옵션을 사용해 설정할 수 있다.

Web UI LDAP 관리 프로그램 설치

모든 LDAP설정은 command line에서 설정/관리가 가능하지만 빈번히 관리 작업이 일어나기도 하고 내부시스템에서만 사용하기 때문에 적절히 쉽게 관리가 가능한 UI 기반 관리 툴을 설치한다.

만약 실제 프로덕션 환경에서 사용해야 하는 경우에는 적절히 command line tool이나 상용제품 혹은 보안에 주의해서 오픈소스를 사용하면 될 것 같다.

몇가지 많이 쓰이는 UI기반 관리 툴을 찾아봤는데 아래와 같다.

나는 php를 조금 다룰줄 알고 정상동작을 잘 못하는 경우나 필요한 경우 뭔가 조치가 가능해보이는 phpLDAPadmin을 설치했다. 본인에 입맛에 맞게 위키 리스트를 참조하여 설치하면 된다.

phpLDAPadmin(PLA) 설치

phpLDAPadmin은 php 기반의 web ui client이기 때문에 php가 동작할 수 있는 웹서버가 필요하다. 기존에 apache httpd가 깔려 있는 환경이라면 기존의 환경을 활용하면 되고 아니어도 걱정은 없다. apt-get으로 phpldapadmin 설치 시 관련 apache2, mod-php5, php5관련 모듈이 디펜던시가 걸려 있어 쉽게 설치 할 수 있다.

sudo apt-get install phpldapadmin
패키지 목록을 읽는 중입니다... 완료
의존성 트리를 만드는 중입니다
상태 정보를 읽는 중입니다... 완료
다음 패키지를 더 설치할 것입니다:
  apache2 apache2-bin apache2-data libapache2-mod-php5 libapr1 libaprutil1
  libaprutil1-dbd-sqlite3 libaprutil1-ldap php5-cli php5-common php5-json
  php5-ldap php5-readline ssl-cert
제안하는 패키지:
  apache2-doc apache2-suexec-pristine apache2-suexec-custom apache2-utils
  php-pear php5-user-cache openssl-blacklist
다음 새 패키지를 설치할 것입니다:
  apache2 apache2-bin apache2-data libapache2-mod-php5 libapr1 libaprutil1
  libaprutil1-dbd-sqlite3 libaprutil1-ldap php5-cli php5-common php5-json
  php5-ldap php5-readline phpldapadmin ssl-cert
  ....설치 진행~

세상 참 좋아졌는지 예전에는 apache configuration 수정 하려면 한땀한땀 매뉴얼 봐가며 설정했었는데 apt-get 으로 설정하면 자동으로 /etc/apache2/conf-enabled/phpldapadmin.conf 파일도 생기며 웹서버 관련 설정은 대부분 기본 파일들을 생성해 준다.

내부적으로 hosts파일에 도메인을 적용해서 사용할 예정이므로 hosts파일에 적절히 도메인 이름을 설정한다.

FILE: /etc/hosts
127.0.1.1	ldap.example.com ldap

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

FILE: /etc/apache2/apache2.conf
# Global configuration
ServerName ldap.example.com

이제 웹서버는 기본적인 세팅이 되었고 phpLDAPadmin도 위에서 생성한 openLDAP을 바라보도록 설정을 변경한다.

phpLDAPadmin(PLA) 설정

apt-get으로 phpLDAPadmin을 설치하면 기본 설정 파일은 /etc/phpldapadmin에 설치된다. 선호하는 편집기로 편집을 시작 한다.

$  sudo vi /etc/phpldapadmin/config.php

config.php 파일에는 LDAP 서버 관리에 필요한 정보를 설정할 수 있다. 해당 설정파일에는 2가지 카테고리 별로 설정을 진행할 수 있다.

  • Appearance and Functionality - 기본값을 사용하도록 한다.
  • LDAP server definitions. - 설치한 OpenLDAP 서버 정보를 설정한다.

이제 OpenLDAP 서버 정보를 /etc/phpldapadmin/config.php에 설정한다.

FILE: /etc/phpldapadmin/config.php
/*********************************************
 * Define your LDAP servers in this section  *
 *********************************************/
 
/* 트리뷰어에 표시되는 User-Friendly한 LDAP 서버 이름을 설정한다. */
$servers->setValue('server','name','example.com LDAP Server');

/* OpenLDAP이 설치된 서버의 IP나 도메인명을 입력한다.
   샘플은 ldap.example.com로 호스트 이름에 설정하였으므로 ldap.example.com로 입력한다.
   Examples:
   'ldap.example.com',
   'ldaps://ldap.example.com/',
   'ldapi://%2fusr%local%2fvar%2frun%2fldapi'
           (Unix socket at /usr/local/var/run/ldap) */
$servers->setValue('server','host','ldap.example.com');

/* 
   기본포트인 389가 아닌 다른 포트를 사용한 경우
   포트 정보를 입력한다.
*/
// $servers->setValue('server','port',389);

/* 
   LDAP 서버의 Base DN 값을 입력한다. 
   빈 공백으로 설정하면 phpLDAPadmin이 자동으로 Base DN을 찾는다.
 */
$servers->setValue('server','base',array('dc=example,dc=com'));

/* The DN of the user for phpLDAPadmin to bind with. For anonymous binds or
   'cookie','session' or 'sasl' auth_types, LEAVE THE LOGIN_DN AND LOGIN_PASS
   BLANK. If you specify a login_attr in conjunction with a cookie or session
   auth_type, then you can also specify the bind_id/bind_pass here for searching
   the directory for users (ie, if your LDAP server does not allow anonymous
   binds. */
$servers->setValue('login','bind_id','cn=admin,dc=example,dc=com');

custom이나 Appearance 속성은 취향에 맞게 운영하면서 적절히 수정하면 되고, 템플릿 파일 관련되서 쓰잘데기 없는 Warning message가 많이 나오므로 hide_template_warning 속성을 true로 설정한다.

/*********************************************
 * Appearance                                *
 *********************************************/
$config->custom->appearance['hide_template_warning'] = true;

기본적으로 주석이 잘 달려 있으므로 원하는 설정을 변경하는 건 쉬운편이고, 좀 더 자세한 설정은 phpldapadmin documatation wiki를 참조하면 된다.

SSL 인증서 생성 및 적용

기본적인 설치는 이제 완료 했고, 내부시스템에서 활용하는 경우라면 굳이 ssl을 적용하지 않아도 되지만 외부에서 사용하면 ssl인증이 필요하므로 ssl 인증서를 생성하고 적용하도록 한다.

인증서는 self-signed된 인증서를 사용하도록 하며 인증서 생성을 위해 openssl 패키지가 설치되어 있어야 한다. openssl 패키지는 최신판의 리눅스 배포판은 모두 기본적으로 가지고 있다. 만약 설치되지 않았거나 삭제된 상태라면 설치를 먼저 진행한다.

$ apt --installed list | grep openssl
libgnutls-openssl27/now 2.12.23-12ubuntu2.2 amd64 [installed,upgradable to: 2.12.23-12ubuntu2.4]
openssl/now 1.0.1f-1ubuntu2.15 amd64 [installed,upgradable to: 1.0.1f-1ubuntu2.16]
python-openssl/trusty,now 0.13-2ubuntu6 amd64 [installed]

# 만약 설치가 되어 있지 않다면 설치한다.
$ sudo apt-get install openssl

이제 apache2 httpd 에서 key와 인증서를 저장할 디렉토리를 생성한다.

$ sudo mkdir /etc/apache2/ssl

그리고 key 파일과 인증서 파일을 openssl을 통해 생성한다.

$ sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/apache2/ssl/example.com.key -out /etc/apache2/ssl/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) []:ldap.example.com
Email Address []:exampleuser@example.com

다른 정보는 크게 중요하지 않는데 Common Name (e.g. server FQDN or YOUR name)LDAP서비스하는 머신의 도메인 네임을 정확히 지정해야 하니 주의한다.

샘플은 hosts파일에 등록한 ldap.example.com을 지정하였다.

Apache2 httpd 서버 인증서 적용

이제 key파일과 인증서 파일을 Apache2 웹서버에 적용한다.

ssl적용을 위해서는 mod-ssl이 필요하니 a2enmod 를 통해 해당 모듈을 설정한다. 해당 모듈은 apahce2 설치 시 함께 설치되고 /etc/apache2/mods-available에 있는 모듈 파일을 /etc/apache2/mods-enabled로 심볼릭 링크로 걸어주는 역할을 한다.

$ sudo a2enmod ssl

phpLDAPadmin apache 설정 수정

phpLDAPadmin과 관련된 apache2설정은 /etc/apache2/conf-available 디렉토리에서 심볼릭 링크로 /etc/phpldapadmin/apache.conf로 걸려 있으므로 해당 파일을 편집한다.

$ sudo vi /etc/phpldapadmin/apache.conf

첫번째로 기본 서비스 URL인 /phpldapadmin은 이미 많이 알려져 있는 URL이기 때문에 bot 등의 ramdom login 공격이 들어 올 수 있기 때문에 변경하는 것이 좋다고는 하나... 나는 내부에서만 사용 하기 때문에 변경을 안하려고 했으나 너무 길다;; 짧게 변경 하도록 한다.

<IfModule mod_alias.c>
    Alias /ldap /usr/share/phpldapadmin/htdocs
</IfModule>

# You can also use phpLDAPadmin as a VirtualHost
# <VirtualHost *:*>
#     ServerName ldap.example.com
#     ServerAdmin root@example.com
#     DocumentRoot /usr/share/phpldapadmin
#     ErrorLog logs/ldap.example.com-error.log
#     CustomLog logs/ldap.example.com-access.log common
# </VirtualHost>

Virtual Host 설정

Virtual Host 설정은 해당 파일에서 주석을 제외하고 사용해도 되지만 만약 다른 Virtual Host설정들도 추가되는 경우가 있으므로 통일성을 위해 site-* 설정 파일에서 수정하도록 한다.

$ sudo vi /etc/apache2/sites-enabled/000-default.conf

self-signed 인증서를 발급 받아서 ssl로 서비스하기로 했으니 https로만 접근하도록 Redirect 지시지와 VirtualHost 설정을 아래와 같이 추가한다.

<VirtualHost *:80>
    ServerAdmin webmaster@ldap.example.com
    ServerName ldap.example.com
    DocumentRoot /usr/share/phpldapadmin
    Redirect permanent /ldap https://ldap.example.com/ldap
    ErrorLog ${APACHE_LOG_DIR}/ldap.example.com-error.log
    CustomLog ${APACHE_LOG_DIR}/ldap.example.com-access.log combined
</VirtualHost>

HTTPS 설정

SSL과 관련된 Virtual Host 설정파일은 기본적으로 활성화 되지 않으므로 활성화 시킨다.

$ sudo a2ensite default-ssl.conf

/etc/apache2/sites-enabled 디렉토리에 심볼릭 링크가 생겼고 이제 해당 파일을 수정한다.

$ sudo vi /etc/apache2/sites-available/default-ssl.conf

ServerName 지시지를 추가하고, 이전에 생성한 SSL key 파일과 인증서 파일 경로를 설정한다.

<IfModule mod_ssl.c>
    <VirtualHost _default_:443>
        ServerAdmin webmaster@ldap.example.com
        ServerName ldap.example.com

        DocumentRoot /usr/share/phpldapadmin
        
        ErrorLog ${APACHE_LOG_DIR}/ssl.ldap.example.com.error.log
        CustomLog ${APACHE_LOG_DIR}/ssl.ldap.example.com.access.log combined
        
        SSLEngine on
        
        SSLCertificateFile /etc/apache2/ssl/example.com.crt
        SSLCertificateKeyFile /etc/apache2/ssl/example.com.key
        
        <FilesMatch "\.(cgi|shtml|phtml|php)$">
                SSLOptions +StdEnvVars
        </FilesMatch>
        <Directory /usr/lib/cgi-bin>
                SSLOptions +StdEnvVars
        </Directory>
        
        BrowserMatch "MSIE [2-6]" \
        nokeepalive ssl-unclean-shutdown \
        downgrade-1.0 force-response-1.0
        
        # MSIE 7 and newer should be able to use keepalive
        BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
    </VirtualHost>
</IfModule>

이제 모든 설정을 끝마쳤으므로 Apache2를 재시작한다.

$ sudo service apache2 restart
* Restarting web server apache2                               [ OK ]

# 80,443, 389 포트가 모두 LISTEN 되어 있는 것을 확인 할 수 있다. 
$ netstat -an | grep LISTEN
tcp6       0      0 :::443                  :::*                    LISTEN
tcp6       0      0 :::389                  :::*                    LISTEN
tcp6       0      0 :::80                   :::*                    LISTEN

phpLDAPadmin으로 LDAP 관리하기

이제 모든 설정을 마치고 웹서버도 정상적으로 동작되는 것을 확인 했으니 브라우저를 열어서 접속을 해본다.

https://ldap.example.com/ldap

스크린샷 2016-02-19 오후 5.05.48.jpg

하지만 불행하게도 그토록 원하던 메인 화면은 나오지 않는다. self signed된 인증서이기 때문에 사설 인증서를 브라우저에서 신뢰할 있도록 등록시켜줘야 한다.

인증서 수동 등록 방법은 아래의 url을 참고하도록 하고 public 도메인을 가지고 있다면 startssl이나 Let's Encrypt 무료 ssl 인증서를 발급받아도 되고 이렇게까지 해야 하나 싶다면 SSL설정은 생략토록 한다.

거의 관리자급에 해당되는 인원만 접근하면 되기 때문에 한번만 수고하면 된다.

자 이제 인증서를 등록하면 로그인 화면을 볼 수 있다.

스크린샷 2016-02-23 오전 9.26.38.jpg

관리자로 bind된 admin 유저로 로그인을 시도한다.

스크린샷 2016-02-23 오전 9.27.23.jpg

패스워드는 OpenLDAP 재설정에서 생성했던 admin 엔트리의 Administrator password로 설정했던 패스워드를 입력한다.

스크린샷 2016-02-23 오전 9.30.24.jpg

이제 관리자로 로그인이 완료되었다.

조직구분(Organizational Units), 그룹(Groups), 사용자(Users) 등록하기

디렉토리의 구조는 관리자가 원하는데로 사용할 수 있다. 조직이나 그룹 없이도 사용자를 등록할 수도 있고 활용할 수 있다. 본 문서는 가장 일반적인 구조인 조직구분(OU), 그룹(Group), 사용자(User) 단위로 디렉토리 구조를 생성하는 것으로 진행한다.

Organizational Units 생성

Organizational Units은 도메인 바로 아래 최상위 레벨의 논리적인 단위로 오브젝트들의 성격 별로 논리적인 단위로 묶을 있고 OU간에 관계도 설정할 수 있다. 예를 들어 그룹, 유저, 프린터, 어플리케이션 등으로 오브젝트 성격 별로 나누어 관리한다.

Create new entry here 를 선택하고 Generic: Organizational Units을 선택한다.

스크린샷 2016-02-23 오후 2.19.38.jpg

이름 입력란에 "groups" 를 입력하고 Create Object하면

스크린샷 2016-02-23 오후 2.23.42.jpg

Commit 전에 화인 화면이 나타나고 Commit 버튼을 클릭하면 OU가 생성된다.

스크린샷 2016-02-23 오후 2.24.56.jpg

그럼 아래와 같이 OU가 생성된 것을 확인 할 수 있다.

스크린샷 2016-02-23 오후 2.27.53.jpg

똑같은 방법으로 "users" OU를 생성한다.

Group 생성

그룹은 관리자 그룹과 개발자 그룹 2개 그룹으로 나누어 설정한다. 왼쪽 트리에서 ou=groups 를 선택한다.

스크린샷 2016-02-23 오후 2.31.49.jpg

Create a child entry를 클릭하고 Generic: Posix Group으로 선택하고 Group이름은 "admin" 으로 채워넣고 Creae Object 버튼을 클랙해 child entry를 생성한다.

스크린샷 2016-02-23 오후 2.39.58.jpg

왼쪽 트리를 보면 정상적으로 admin 그룹이 생성된 것으로 보인다. 같은 방식으로 dev 그룹도 생성한다.

스크린샷 2016-02-23 오후 2.43.13.jpg

User 생성

이제 유저를 생성할 차례이다. users 그룹에 추가되는 유저 정보 엔트리의 경우에는 보통 posixAccountinetOrgPerson object class를 사용한다. 물론 신규로 object class schema를 작성해서 원하는 속성값만 가져다가 넣어도 되긴 하지만 다른 시스템이나 서비스(혹은 기반시스템의 플러그인들)와 연동은 표준으로 작성되어 있으므로 표준(RFC4519, RFC2307, RFC2798)으로 만들어 놓은 스키마를 사용하기로 한다.

여기서 좀 애를 먹었던게 phpLDAPadmin에서 제공하는 유저 정보 templateGeneric: User Account(posixAccount.xml) Generic: Address Book Entry(inetOrgPerson.xml) 로 제공되고 있는데 Generic: Address Book Entry는 uid정보가 없어서 redmine, jenkins, sonare등의 계정과 연결이 힘드므로 Generic: User Account를 사용하려고 했으나 기본 템플릿에는 email 속성이 없어서 별 수 없이 posixAccout.xml을 기반으로 별도의 템플릿 파일을 아래와 같이 작성했다.

기존 파일을 그대로 수정해도 되지만 업그레이드 되면 템플릿 파일은 덮어씌워진다고 나와 있어 먼저 기존의 posixAccountxml파일을 custom_posixAccount.xml으로 복사하고 편집을 시작한다.

$ sudo cp /etc/phpldapadmin/templates/creation/posixAccount.xml /etc/phpldapadmin/templates/creation/custom_posixAccount.xml
$ sudo vi /etc/phpldapadmin/templates/creation/custom_posixAccount.xml

기존의 파일에서 변경되는 부분은 아래 주석을 참조하고 변경되지 않는 부분은 그대로 두면 된다. 변경 시 objectClass에 선언된 속성만 사용 가능하므로 다른 속성을 사용하려면 별도의 objectClass 추가하거나 신규 스키마를 생성하면 된다.

템플릿 작성 시 사용할 수 있는 autofil 같은 기능은 phpLDAPadmin Templates WIKI를 참조하면 된다.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE template SYSTEM "template.dtd">

<template>
<askcontainer>1</askcontainer>
<description>Example.com New User Account</description><!-- 설명 태그는 적절히 변경한다. -->
<icon>ldap-user.png</icon>
<invalid>0</invalid>
<rdn>cn</rdn>
<!--<regexp>^ou=People,o=.*,</regexp>-->
<title>example.com: User Account</title><!-- 템플릿 이름으로 나오므로 적절히 변경한다.-->
<visible>1</visible>

<!-- inetOrgPerson, posixAccount 스키마를 같이 사용하는 것을 확인 할 수 있다. -->
<objectClasses>
<objectClass id="inetOrgPerson"></objectClass>
<objectClass id="posixAccount"></objectClass>
</objectClasses>

<attributes>
...
생략
...
<attribute id="loginShell">
	<display>Login shell</display>
	<order>9</order>
	<page>1</page>
	<!-- <value><![CDATA[=php.PickList(/;(&(objectClass=posixAccount));loginShell;%loginShell%;;;;loginShell)]]></value> -->
	<type>select</type>
	<value id="/bin/sh">/bin/sh</value>
	<value id="/bin/csh">/bin/csh</value>
	<value id="/bin/tsh">/bin/tsh</value>
	<value id="/bin/bash">/bin/bash</value><!-- 기존에 bash shell없어 추가한다. -->
</attribute>
...
생략
...
<!-- 본인의 경우에는 핸드폰번호, 이메일, 사진, 표시이름(한글) 속성만 추가하였다.-->
<attribute id="mobile">
	<display>Mobile</display>
	<order>10</order>
	<page>1</page>
</attribute>
<attribute id="mail">
	<display>Email</display>
	<order>11</order>
	<page>1</page>
</attribute>
<attribute id="jpegPhoto">
	<display>Photo</display>
	<order>12</order>
	<spacer>1</spacer>
</attribute>
<attribute id="displayName">
    <display>displayName</display>
    <order>13</order>
    <spacer>1</spacer>
</attribute>
</attributes>

</template>

수정된 파일을 저장하고 왼쪽 트리메뉴에서 ou=users 엔트리를 클릭하고 Create a child entry를 클릭하면 방금 전에 생성한 example.com: User Account 템플릿을 클릭한다.

스크린샷 2016-02-25 오후 4.32.18.jpg

이제 사용자 정보를 입력한다.

스크린샷 2016-02-25 오후 4.28.59.jpg

commit 버튼을 클릭하고 확인 작업을 거친 후 최종 저장한다.

만약 password필드 렌더링 시 phpLDAPadmin Error trying to get a non-existant value (appearance,password_hash) 오류가 난다면 Getting error for setting password field when creating generic user account phpldapadmin의 답변을 참고바란다. PHP5.5 이상 패치되면서 수정이 안된 모양이다.

/usr/share/phpldapadmin/lib/TemplateRender.php 2469라인의 password_hashpassword_hash_custom으로 변경하면 된다 .

2463     protected function drawDefaultHelperPasswordAttribute($attribute,$i) {
2464         $id = 'enc';
2465
2466         if ($val = $attribute->getValue($i))
2467             $default = get_enc_type($val);
2468         else
2469             $default = $this->getServer()-getValue('appearance','password_hash_custom');

이제 다른 유저들도 기존 유저 엔트리를 복사해서 수정하거나 신규로 추가하면 된다.

유저를 그룹에 할당하기

등록된 유저들을 그룹에 할당하기 위해서는 해당 그룹의 속성을 먼저 추가해야 한다.

트리에서 cn=admin을 클릭하고 Add new attribute를 클릭하고 memberUid를 선택한다.

스크린샷 2016-02-25 오후 4.41.06.jpg

그리고 방금 추가한 hkwon 유저를 추가한다. 주의할 것은 cn 값이 아니라 uid로 입력한 값을 입력한다.

스크린샷 2016-02-25 오후 4.43.47.jpg

이제 오브젝트를 업데이트 하면 modify group members 기능을 사용하여 등록된 유저를 해당 그룹으로 관리할 수 있다.

스크린샷 2016-02-25 오후 4.44.37.jpg

OpenLDAP, phpLDAPadmin 설치 완료/검증

ldapsearch 명령어로도 생성된 유저가 제대로 검색되는지 확인한다.

$ ldapsearch -x -W -D "cn=Hyeok Kwon,ou=users,dc=example,dc=com" -H ldapi:/// -b dc=example,dc=com
Enter LDAP Password:
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# example.com
dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
o: devops
dc: example

# admin, example.com
dn: cn=admin,dc=example,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator

# groups, example.com
dn: ou=groups,dc=example,dc=com
objectClass: organizationalUnit
objectClass: top
ou: groups

# users, example.com
dn: ou=users,dc=example,dc=com
objectClass: organizationalUnit
objectClass: top
ou: users

# admin, groups, example.com
dn: cn=admin,ou=groups,dc=example,dc=com
gidNumber: 500
cn: admin
objectClass: posixGroup
objectClass: top
memberUid: hkwon

# dev, groups, example.com
dn: cn=dev,ou=groups,dc=example,dc=com
gidNumber: 501
cn: dev
objectClass: posixGroup
objectClass: top

# Hyeok Kwon, users, example.com
dn: cn=Hyeok Kwon,ou=users,dc=example,dc=com
cn: Hyeok Kwon
mail: hkwon@example.com
givenName: Hyeok
gidNumber: 500
homeDirectory: /home/users/hkwon
sn: Kwon
loginShell: /bin/bash
mobile: 010-000-0000
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
userPassword:: e01ENX10WnhudnhscVIxZ1pIa0wzWm5ET3VnPT0=
uidNumber: 1000
uid: hkwon

# search result
search: 2
result: 0 Success

# numResponses: 8
# numEntries: 7

이제 기본적인 디렉토리 서비스가 가능한 ldap 서버를 구축완료 했고 관리 할 수 있는 토대를 마련했다.

2편에서는 기반시스템(svn, gitlab, jenkins, sonarqube, redmine, nexus..)등과 ldap server 연동 작업을 통해 어떻게 중앙인증 처리하는지에 대해서 다뤄보도록 하겠다.

서버 구성과 관련된 내용은 참조 URL에 있는 digitalocean의 아티클들을 기본적으로 상당부분 많이 참조하였고, 나머지 매뉴얼들을 참조 하였다.

참조

Read more

나의 프로그래밍 폰트 사용 일대기

나의 프로그래밍 폰트 사용 일대기

시작은 2003년 이제 막 프로그래머로써 첫발을 내딛을 때부터 나는 프로그래밍 폰트에 대해서 관심이 많은 편이었다. 화면 붙잡고 매일 글자들과 씨름하는 직업이다보니 당연하게도 좀더 눈에 잘 보이고, 보기에 좀더 미려하고 조화스러운 폰트를 찾는 것이 어찌보면 약간 본능(?)적으로 관심을 가졌던게 아닌가 싶기도 하고 말이다. 최근까지도 이 주체할 수 없는 본능에 따라

By Kevin H. Kwon
Istio 를 통한 path(url) 기반 Local Rate Limit 적용

Istio 를 통한 path(url) 기반 Local Rate Limit 적용

몇 년 전인지는 기억나진 않지만 Rate Limit 적용은 항상 애플리케이션 쪽에서 처리하는 것이 당연하다는 것이 주된 의견이었다. 그래서 그때 당시 Bucket4J 를 통해서 Spring 쪽에서 처리하고 했던 기억이 있다. 이제는 당연하게도 Istio와 같은 Service Mesh쪽에서 처리하는 것이 응당 맞다고 생각되는 것이 개발 세상이 이제 점점 더 클라우드향으로 이동된다는 느낌이다. 강력한

By Kevin H. Kwon
Istio를 통한 header기반 API 라우팅/호출 시 cors preflight request 이슈 트러블슈팅 기록

Istio를 통한 header기반 API 라우팅/호출 시 cors preflight request 이슈 트러블슈팅 기록

현재 개발하고 있는 일부 컨테이너 기반의 서비스들을 Istio를 통해 서비스들을 구성하고 트래픽을 관리하고 있다. 이때 컨테이너 서비스가 같은 규격이 여러개가 같은 url과 port를 할당 받아서 사용해야는 애로 사항이 있어 Istio에서 header 기반으로 특별한 헤더가 있는 경우에만 라우팅이 될 수 있도록 구성하고 테스트를 진행했었다. Istio Request Routing 예제와 같이 header

By Kevin H. Kwon