LDIF 를 넣을 때 다음이 나오며 항목이 들어가지 않는다.
ldap_add: Constraint violation (19)
additional info: some attributes not unique
it would result in an attribute value not being unique
LDAP 스키마 자체는 uidNumber 의 유일성을 강제하지 않는다. 이 오류는 unique overlay 가 적용돼 있을 때 난다. OpenLDAP 의 unique 오버레이는 지정한 속성이 지정 범위 안에서 겹치지 않도록 검사한다.
스키마가 막는 것과 오버레이가 막는 것은 다르다. 진짜로 유일해야 하는 것은 DN 뿐이며, 나머지는 운영 정책으로 강제하는 것이다.
ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config \
"(objectClass=olcUniqueConfig)"
설정돼 있으면 이렇게 나온다.
dn: olcOverlay={0}unique,olcDatabase={2}mdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcUniqueConfig
olcOverlay: {0}unique
olcUniqueURI: ldap:///dc=example,dc=com?uidNumber?sub
olcUniqueURI: ldap:///dc=example,dc=com?mail?sub
출력이 없으면 오버레이가 없는 것이므로 오류 원인은 다른 곳(대개 DN 중복 entryAlreadyExists (68))이다.
쿠버네티스에 올린 경우에는 파드 안에서 같은 명령을 실행한다.
kubectl exec -it <openldap-pod> -n <ns> -- \
ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config "(objectClass=olcUniqueConfig)"
olcUniqueURI 의 형식은 ldap:///<base>?<속성>?<범위> 다. 즉 위 예는 "dc=example,dc=com 아래 전체에서 uidNumber 와 mail 이 겹치면 안 된다"는 뜻이다.
제약을 푸는 것보다 값을 제대로 주는 편이 맞다. 같은 uidNumber 를 가진 계정이 여럿이면 파일 소유권과 권한이 뒤섞여 OS 수준에서 사고가 난다.
# 현재 쓰이는 번호
ldapsearch -x -LLL -b "dc=example,dc=com" "(uidNumber=*)" uidNumber \
| awk '/^uidNumber:/{print $2}' | sort -n | uniq
# 가장 큰 값
ldapsearch -x -LLL -b "dc=example,dc=com" "(uidNumber=*)" uidNumber \
| awk '/^uidNumber:/{print $2}' | sort -n | tail -1
번호를 자동으로 붙이려면 unique 대신 autogroup 이 아니라 slapo-dds 도 아닌 전용 오버레이가 필요하다. OpenLDAP 에는 번호 자동 채번 기능이 기본 제공되지 않으므로, 보통은 프로비저닝 스크립트가 최대값을 조회해 +1 을 붙이거나 FreeIPA · 389 Directory Server 처럼 DNA(Distributed Numeric Assignment) 를 가진 제품을 쓴다.
이관 작업처럼 일시적으로 필요한 경우가 있다. 범위를 최소로 줄인다.
# unique-drop-uidnumber.ldif
dn: olcOverlay={0}unique,olcDatabase={2}mdb,cn=config
changetype: modify
delete: olcUniqueURI
olcUniqueURI: ldap:///dc=example,dc=com?uidNumber?sub
sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f unique-drop-uidnumber.ldif
delete 로 지울 때는 등록된 값과 한 글자도 다르지 않게 적어야 한다. 조회 결과를 그대로 복사한다.
dn: olcOverlay={0}unique,olcDatabase={2}mdb,cn=config
changetype: delete
mail 까지 겹칠 수 있게 되므로 되도록 피한다. 작업이 끝나면 다시 넣는다.
dn: olcOverlay=unique,olcDatabase={2}mdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcUniqueConfig
olcOverlay: unique
olcUniqueURI: ldap:///dc=example,dc=com?uidNumber?sub
olcUniqueURI: ldap:///dc=example,dc=com?mail?sub
slapd.conf 를 쓰는 구성이면 해당 database 블록의 overlay unique 와 unique_uri 줄을 주석 처리하고 재기동한다.
차트 값으로 오버레이를 켰다면 위 방법으로 지워도 파드가 다시 뜰 때 되살아난다. 부트스트랩 LDIF 를 담은 ConfigMap 이나 values 에서 해당 항목을 빼야 영구적이다. 값을 바꿨는데 반영되지 않으면, 설정(cn=config)이 PVC 에 저장돼 초기화 스크립트가 건너뛰는 경우를 확인한다.
ldapadd 는 LDIF 하나에 여러 항목을 담을 수 있다. 빈 줄로 구분한다.
ldapadd -x -D "cn=admin,dc=example,dc=com" -W -f users.ldif
# 중간에 하나가 실패해도 나머지를 계속 처리
ldapadd -c -x -D "cn=admin,dc=example,dc=com" -W -f users.ldif
-c 옵션이 없으면 첫 실패에서 멈춘다. 대량 반입은 어디까지 들어갔는지 확인할 수 있도록 로그를 남긴다.
서비스를 멈출 수 있다면 slapadd 가 훨씬 빠르다. 다만 slapd 를 내린 상태에서 실행해야 하며 파일 소유권을 맞춰야 한다.
systemctl stop slapd
sudo -u ldap slapadd -n 2 -F /etc/openldap/slapd.d -l users.ldif
systemctl start slapd