1. 호스트 제어 구현 방식
OpenLDAP에서 호스트 접근 제어를 구현하는 방법은 두 가지가 있다. 첫 번째는 시스템의 access 모듈을 활용하는 방식으로, 사용자 로그인 제한을 구현할 수 있지만 설정이 복잡하고 유연성이 부족하다. 두 번째는 OpenLDAP 서버 측에서 스키마와 오브젝트 클래스를 정의하고 사용자 엔트리 속성을 추가한 후, 클라이언트 설정과 결합하는 방식이다. 이 방법은 관리 측면에서简便하고 유연성이 높다.
2. Linux-PAM 모듈을 활용한 제어
2.1 Linux-PAM 아키텍처
기본적으로 UNIX/Linux 시스템에 로그인할 때, PAM(Pluggable Authentication Modules) 모듈이 사용자의 신원 검증과 비밀번호 확인을 담당한다. Linux-PAM의 구성은 다음과 같다:
+----------------+
| application: X |
+----------------+ / +----------+ +================+
| authentication-[---->--\--] Linux- |--<--| PAM config file|
| + [----<--/--] PAM | |================|
|[conversation()][--+ \ | | | X auth .. a.so |
+----------------+ | / +-n--n-----+ | X auth .. b.so |
| | | __| | | _____/
| service user | A | | |____,-----'
| | | V A
+----------------+ +------|-----|---------+ -----+------+
+---u-----u----+ | | |
| auth.... |--[ a ]--[ b ]--[ c ]
+--------------+
| acct.... |--[ b ]--[ d ]
+--------------+
| password |--[ b ]--[ c ]
+--------------+
| session |--[ e ]--[ c ]
+--------------+
2.2 PAM 설정 파일 문법
PAM 설정 파일 경로:
$ ls /etc/pam.conf # 구버전
$ ls /etc/pam.d/* # 신버전
PAM 모듈 경로:
$ ls /lib64/security/ # x86_64
$ ls /lib/security/ # x86_32
기본 시스템 설정 파일:
/etc/pam.d/system-auth
3. Access 제어를 통한 사용자 관리 실습
3.1 pam_access 모듈 기능 개요
pam_access 모듈은 특정 머신에 대한 로그인 접근을 제어하는 역할을 한다. 기본적으로 /etc/security/access.conf 파일을 참조하여 다양한 접근 제어를 적용한다. access.conf 파일이 작동하려면 /etc/pam.d/login 파일에 pam_access.so 모듈이 로드되어 있어야 한다.
3.2 Access 설정 문법
pam_access.so 모듈은 access.conf 파일에 정의된 조건에 따라 인증을 처리한다. 설정 형식은 다음과 같다:
permission: user: origin
각 파라미터 의미:
-
permission: "+"는 허용, "-"는 거부. EXCEPT 키워드를 활용하면 전체 거부 후 일부 허용 가능
-
user: 허용 또는 거부할 사용자 또는 그룹. "all"은 모든 사용자 지정
-
origin: 로그인 대상 위치로, local(로컬), console(콘솔), all(전체), 네트워크 주소 등 지정 가능
3.3 실제 설정 적용
pam_access.so 모듈 로드
제한이 필요한 클라이언트 머신에서 /etc/pam.d/sshd 파일을 편집한다. account 섹션의 최상위에 다음 내용을 추가한다:
[root@dir01 ~]# vim /etc/pam.d/sshd
#%PAM-1.0
auth required pam_sepermit.so
auth substack password-auth
auth include postlogin
-auth optional pam_reauthorize.so prepare
account required pam_access.so # 새로 추가하는 account는 최상위에 위치해야 함
account required pam_nologin.so
account include password-auth
password include password-auth
접근 규칙 설정
[root@server01 ~]# vim /etc/security/access.conf
-:testuser1:ALL # testuser1 사용자의 server01.example.com 접근 차단
검증
[root@server01 ~]# ssh testuser1@192.168.1.132
testuser1@192.168.1.132's password:
Permission denied, please try again.
[root@server01 ~]# tail /var/log/secure
Apr 23 00:02:01 server01 sshd[38953]: fatal: Access denied for user testuser5 by PAM account configuration [preauth]
Apr 24 22:27:33 server01 sshd[46999]: Accepted password for root from 192.168.1.1 port 1366 ssh2
Apr 24 22:27:33 server01 sshd[46999]: pam_unix(sshd:session): session opened for user root by (uid=0)
Apr 24 22:37:34 server01 sshd[47514]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=server01.example.com user=testuser1
여러 사용자의 접근을 관리하려면 OpenLDAP 서버에서 해당 사용자를 특정 그룹에 포함시킨 후, access.conf에서 그룹 단위로 제어를 설정하면 된다. 모든 인증 정보는 OpenLDAP 서버에서 조회된다.
4. OpenLDAP 서버 측 호스트 제어 규칙
OpenLDAP 서버에서는 커스텀 모듈과 호스트 설정을 통해 사용자별 로그인 권한을 세밀하게 제어할 수 있다.
4.1 olcModuleList 객체 정의
# olcModuleList 객체 확인 (기존 module{0}.ldif 파일이 있으면 생략 가능)
$ cat << EOF | ldapadd -Y EXTERNAL -H ldapi:///
dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
EOF
4.2 모듈 경로 추가
$ cat << EOF | ldapadd -Y EXTERNAL -H ldapi:///
dn: cn=module{0},cn=config
changetype: modify
add: olcModulePath
olcModulePath: /usr/lib64/openldap/
EOF
4.3 호스트 제어 모듈 로드
[root@dir01 ~]# cat << EOF | ldapmodify -c -Y EXTERNAL -Q -H ldapi:///
dn: cn=module{0},cn=config
add: olcModuleLoad
olcModuleLoad: dynlist.la
EOF
modifying entry "cn=module{0},cn=config"
4.4 호스트 오브젝트 클래스 정의
[root@dir01 ~]# cat << EOF | ldapadd -Y EXTERNAL -H ldapi:///
dn: olcOverlay=dynlist,olcDatabase={2}hdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcDynamicList
olcOverlay: dynlist
olcDlAttrSet: inetOrgPerson labeledURI
EOF
4.5 ldapns 스키마 정의
[root@dir01 ~]# cat << EOF | ldapadd -Y EXTERNAL -H ldapi:///
dn: cn=ldapns,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: ldapns
olcAttributeTypes: {0}( 1.3.6.1.4.1.5322.17.2.1 NAME 'authorizedService' DESC 'IANA GSS-API authorized service name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
olcAttributeTypes: {1}( 1.3.6.1.4.1.5322.17.2.2 NAME 'loginStatus' DESC 'Currently logged in sessions for a user' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch ORDERING caseIgnoreOrderingMatch SYNTAX OMsDirectoryString )
olcObjectClasses: {0}( 1.3.6.1.4.1.5322.17.1.1 NAME 'authorizedServiceObject' DESC 'Auxiliary object class for adding authorizedService attribute' SUP top AUXILIARY MAY authorizedService )
olcObjectClasses: {1}( 1.3.6.1.4.1.5322.17.1.2 NAME 'hostObject' DESC 'Auxiliary object class for adding host attribute' SUP top AUXILIARY MAY host )
olcObjectClasses: {2}( 1.3.6.1.4.1.5322.17.1.3 NAME 'loginStatusObject' DESC 'Auxiliary object class for login status attribute' SUP top AUXILIARY MAY loginStatus )
EOF
4.6 호스트 그룹 정의
호스트 그룹(ou)을 구성하여 효율적인 관리 가능한다. servers OU 하에 apphost와 dbahost 서브 OU를 생성하고, 각각的应用 시스템과 데이터베이스 시스템을 분류한다. 예를 들어, 앱 사용자는 JBOSS, Tomcat, Nginx, OpenStack 등 앱 서버와 Cacti, Nagios, Zabbix 같은 모니터링 시스템에만 접근 가능하도록 하고, DB 사용자는 Oracle, MySQL, MariaDB 등 데이터베이스 서버만 접근하도록 제한할 수 있다.
[root@dir01 ~]# cat << EOF | ldapadd -x -D "cn=admin,dc=dir01,dc=example,dc=com" -w password123 -H ldap://dir01.example.com
dn: ou=servers,dc=dir01,dc=example,dc=com
objectClass: organizationalUnit
ou: servers
dn: ou=apphost,ou=servers,dc=dir01,dc=example,dc=com
objectClass: organizationalUnit
objectClass: hostObject
ou: apphost
host: server01.example.com
EOF
OU 생성 시 hostObject 클래스를 적용하고 host 속성에 호스트 정보를 지정하여 apphost 그룹에 server01.example.com을 포함시킨다.
4.7 사용자 그룹 및 사용자 정의
사용자를 특정 그룹에 할당하여 그룹 단위로 호스트 접근을 제어한다. 예: appgroup 그룹과 appuser1 사용자
그룹 추가
cat << EOF | ldapadd -x -D "cn=admin,dc=dir01,dc=example,dc=com" -w password123 -H ldap://dir01.example.com
dn: cn=appgroup,ou=Group,dc=dir01,dc=example,dc=com
objectClass: posixGroup
cn: appgroup
gidNumber: 10010
EOF
사용자 추가 및 호스트 연결
[root@dir01 ~]# cat add_user.ldif
dn: uid=appuser1,ou=People,dc=dir01,dc=example,dc=com
uid: appuser1
cn: appuser1
sn: app
objectClass: person
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
objectClass: inetOrgPerson
userPassword: password123
shadowLastChange: 19096
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/bash
uidNumber: 1010
gidNumber: 10010
homeDirectory: /home/appuser1
labeledURI: ldap:///ou=apphost,ou=servers,dc=dir01,dc=example,dc=com?host
[root@dir01 ~]# ldapadd -x -D "cn=admin,dc=dir01,dc=example,dc=com" -w password123 -H ldap://dir01.example.com -f add_user.ldif
검증
[root@dir01 ~]# ldapsearch -x -D "cn=admin,dc=dir01,dc=example,dc=com" -w password123 -H ldap://dir01.example.com -b "uid=appuser1,ou=People,dc=dir01,dc=example,dc=com"
# extended LDIF
#
# LDAPv3
# base with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# appuser1, People, dir01.example.com
dn: uid=appuser1,ou=People,dc=dir01,dc=example,dc=com
uid: appuser1
cn: appuser1
sn: app
objectClass: person
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
objectClass: inetOrgPerson
userPassword:: e1NTSEF9STZZcjZhV0FOdTh6UkpUNEV5eVB2Y3dGUzNmeCtRMnU=
shadowLastChange: 19096
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/bash
uidNumber: 1010
gidNumber: 10010
homeDirectory: /home/appuser1
labeledURI: ldap:///ou=apphost,ou=servers,dc=dir01,dc=example,dc=com?host
host: server01.example.com
[root@dir01 ~]# ldapsearch -x -D "cn=admin,dc=dir01,dc=example,dc=com" -w password123 -H ldap://dir01.example.com "host=server01.example.com"
# extended LDIF
#
# LDAPv3
# base with scope subtree
# filter: host=server01.example.com
# requesting: ALL
#
# jboss, People, dir01.example.com
dn: uid=jboss,ou=People,dc=dir01,dc=example,dc=com
objectClass: account
objectClass: posixAccount
objectClass: shadowAccount
cn: jboss
uid: jboss
uidNumber: 20006
gidNumber: 10005
userPassword:: amJvc3M=
homeDirectory: /home/jboss
loginShell: /bin/bash
host: server01.example.com
# apphost, servers, dir01.example.com
dn: ou=apphost,ou=servers,dc=dir01,dc=example,dc=com
objectClass: organizationalUnit
objectClass: hostObject
ou: apphost
host: server01.example.com
# search result
search: 2
result: 0 Success
# numResponses: 3
# numEntries: 2
4.8 인덱스 추가
[root@dir01 ~]# grep olcDbIndex /etc/openldap/slapd.d/cn\=config/olcDatabase\=\{2\}hdb.ldif
[root@dir01 ~]# cat << EOF | ldapadd -Y EXTERNAL -H ldapi:///
dn: olcDatabase={2}hdb,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: host eq
EOF
5. 클라이언트에서 LDAP 호스트 제어 규칙 활성화
CentOS 6
$ cat >> /etc/pam_ldap.conf << EOF
pam_check_host_attr yes
EOF
CentOS 7
cat >> /etc/nslcd.conf << EOF
pam_authz_search (&(objectClass=posixAccount)(uid=\$username)(|(host=\$hostname)(host=\$fqdn)(host=\\\*)))
EOF
$ systemctl restart nslcd