LDAPのユーザーをまとめてバッチ処理で登録・更新・削除するシェル・プログラム


LDAPのユーザーをバッチ処理でまとめて登録・更新・削除する事例についてまとめます。
発端は、外部の別システムのデータベースで別途管理されているユーザー情報と同期をとって、LDAPのユーザー情報を一括メンテナンスしたいというニーズから必要になった処理です。
したがって、外部システムで別管理されているデータベースからCSVファイルを作成して、それを入力ファイルとしてLDAPを更新するバッチ処理で、日に数回実行して同期を取ります。

1.前提

以下のようなLDAPエントリを例に考えます。

dn: uid=1000000@test,ou=People,dc=company,dc=jp
uid: 1000000@test
cn: 1000000@test
sn: 1000000
description: Test 1000000 's description.
userPassword: test1000000
objectClass: inetOrgPerson

・使用するLDAPスキーマは標準で定義されている inetOrgPerson を使用。
(「objectClass: inetOrgPerson」 と記述している部分)
・「dn:」属性に指定する 「uid=2.使用するLDAPの主要コマンド

まとめてバッチ処理するシェル・プログラムを作成するにあたり、シェルの中で実行するLDAPの基本コマンドを簡単に説明します。

■ユーザー追加コマンド - ldapadd
例) #ldapadd -x -D “cn=Manager,dc=company,dc=jp” -w xxxx -c -f ./input_file.ldif -S ./skip_file.out
■ユーザー更新コマンド - ldapmodify
例) #ldapmodify -x -D “cn=Manager,dc=company,dc=jp” -w xxxx -c -f ./input_file.ldif -S ./skip_file.out

⇒ ldapadd と ldapmodify について
ldapadd(追加)はldapmodify(更新)のハードリンクであり、「 ldapmodify 」を -a オプション付きで実行することと同じです。
しかし、入力データldifファイルの形式は双方で異なるので、バッチ処理では登録と更新でトランザクションを分ける方向で考えます。
更新と登録のトランザクションを1つにすること(=シェルを1つにすること)も不可能ではありませんが、I/Fされてきた入力データのエントリの各々について、既存のLDAPデータ上に存在するか否かによって、登録or更新を自動判別して振り分けるような処理を行うことになります。

■ユーザー削除コマンド - ladpdelete
例) #ldapdelete -x -D “cn=Manager,dc=company,dc=jp” -w xxxx -c -f ./input_file.ldif

■異常データの検知について
ldapmodify(ldapadd) コマンドについては、-Sオプションをつけることによって、異常によりスキップしたデータを一意属性uidとともにファイルに格納してくれるので、これを活用して異常データを出力するしくみが構築可能です。
ldapdeleteコマンドについては、残念ながらありません。標準エラー出力にも、例えば存在しない一意キーだったことは通知されますが、肝心のどの一意キーuid だったかの情報が表示されないので意味がありません。
もし、このような異常データも検知して出力したい場合は、I/Fされる入力データの1件ごとに ldapdelete コマンドを実行するようなシェル・スクリプトにして、スクリプト側でエラー時に必要なuidの情報を出力するような設計にする必要が出てきます。
また、ldapmodify(ldapadd)については、エラーの発生した一意キーは出力されますが、行番号は出力されませんので、もし、エラー行の出力も必要ならば、やはりI/Fされるデータの1件ごとに ldapmodify(ldapadd)コマンドを実行するような設計にする必要がでてきます。
ちなみに、この記事で最後に記載しているシェルスクリプトは、そこまで複雑なことは行っていません。

3.データベースからI/FされてくるCSVファイルの前提イメージ

1000000@test,1000000@test,1000000,Test 1000000 's description.,test1000000
1000001@test,1000001@test,1000001,Test 1000001 's description.,test1000001
・・・・・

1カラム目(1000000@test) = 一意ID。LDAPのuid:に設定
2カラム目(1000000@test) = LDAPのcn:に設定。LDAPでは必須
3カラム目(1000000) = LDAPのsn:に設定。LDAPでは必須
4カラム目(Test 1000000 ‘s description.) = LDAPのdescription:に設定
5カラム目(test1000000) = LDAPのuserPasswordに設定
※1カラム目のユーザーIDと5カラム目のパスワード以外は、固定文字など何でもいい場合もあるかと。。。

4.シェルプログラムの処理手順

■ユーザー一括登録シェルスクリプト
手順1: CSVファイルからユーザー追加用ldifファイルを自動作成する。
↓user_add.ldif ファイルのイメージ

dn: uid=1000000@test,ou=People,dc=company,dc=jp		
uid: 1000000@test		
cn: 1000000@test		
sn: 1000000		
description: Test 1000000 's description.		
userPassword: xxxxx		
objectClass: inetOrgPerson		
・・・ × N件

手順2: ldapadd コマンドを実行 -f オプションの引数は 作成したldifファイル(./user_add.ldif)

■ユーザー一括更新シェルスクリプト
手順1: CSVファイルからユーザー更新用ldifファイルを自動生成する。
↓user_mod.ldif ファイルのイメージ

dn: uid=1000000@test,ou=People,dc=company,dc=jp
changetype: modify
replace: cn
cn: 1000000@test
-
replace: sn	
sn: 1000000	
-	
replace: description	
description: Test 1000000 's description.	
-	
replace: userPassword	
userPassword: xxxxx
・・・ × N件

手順2: ldapmodify コマンドを実行 -f オプションの引数は 作成したldifファイル(./user_mod.ldif)

■ユーザー一括削除シェルスクリプト
手順1: CSVファイルからユーザー更新用ldifファイルを自動生成する。
↓user_del.ldif ファイルのイメージ

uid=1000000@test,ou=People,dc=company,dc=jp
・・・ × N件

手順2: ldapdelete コマンドを実行 -f オプションの引数は 作成したldifファイル(./user_del.ldif)

5.シェル・スクリプト

実際に作成したシェル・スクリプトの内容を示します。
参考にされる場合は自己責任で御願いします。

■LDAPユーザー一括追加シェルプログラム - proc_add.sh

#!/bin/sh
#proc_add.sh
com_add="/usr/bin/ldapadd"
com_search="/usr/bin/ldapsearch"
com_del="/usr/bin/ldapdelete"
com_mod="/usr/bin/ldapmodify"
ldap_admin="cn=Manager,dc=company,dc=jp"
ldap_pass="passl620"
ldap_people="ou=People,dc=company,dc=jp"
user_del_file="./DAT/user_del.ldif"
user_add_file="./DAT/user_add.ldif"
user_mod_file="./DAT/user_mod.ldif"
skipped_file="./DAT/skipped.txt"
DELIM=,
SUFFIX="dc=company,dc=jp"
OU_USERS="ou=People"
OU_GROUPS="ou=Group"
OUT_FILE=./OUT/add.out
SKIP_FILE=./SKIP/add.skip
TMP_FILE=./TMP/add.tmp
echo "" > ${OUT_FILE}
echo "" > ${TMP_FILE}

function start_stamp(){
        START=`date +%s`
}
function stamp() {
 END=`date +%s`
 SS=`expr ${END} - ${START}`
 HH=`expr ${SS} / 3600`
 SS=`expr ${SS} % 3600`
 MM=`expr ${SS} / 60`
 SS=`expr ${SS} % 60`
 echo "${HH}:${MM}:${SS}"
}

start_stamp
filename=$1
lineno=0
while read line
do
  lineno=`expr ${lineno} + 1`
  echo ${lineno}
  uid=`echo ${line} | cut -d ${DELIM} -f 1`
  cn=`echo ${line} | cut -d ${DELIM} -f 2`
  sn=`echo ${line} | cut -d ${DELIM} -f 3`
  des=`echo ${line} | cut -d ${DELIM} -f 4`
  pass=`echo ${line} | cut -d ${DELIM} -f 5`
  echo -e "dn: uid=${uid},${OU_USERS},${SUFFIX}\nuid: ${uid}\ncn: ${cn}\nsn: ${sn}\ndescription: ${des}\nuserPassword: ${pass}\nobjectClass: inetOrgPerson\n" >> ${TMP_FILE}
done < ${filename} stamp >> ${OUT_FILE}
echo "adding ..."
${com_add} -x -D "${ldap_admin}" -w $ldap_pass -c -f ${TMP_FILE} -S ${SKIP_FILE}
if test 0 -ne $? ; then
  echo ERROR OCCURED.
fi

stamp >> ${OUT_FILE}

■LDAPユーザー一括更新シェルプログラム - proc_mod.sh

#!/bin/sh
#proc_mod.sh
START=`date +%s`
com_add="/usr/bin/ldapadd"
com_search="/usr/bin/ldapsearch"
com_del="/usr/bin/ldapdelete"
com_mod="/usr/bin/ldapmodify"
ldap_admin="cn=Manager,dc=company,dc=jp"
ldap_pass="passl620"
ldap_people="ou=People,dc=company,dc=jp"
user_del_file="./DAT/user_del.ldif"
user_add_file="./DAT/user_add.ldif"
user_mod_file="./DAT/user_mod.ldif"
skipped_file="./DAT/skipped.txt"
DELIM=,
SUFFIX="dc=company,dc=jp"
OU_USERS="ou=People"
OU_GROUPS="ou=Group"
OUT_FILE=./OUT/mod.out
SKIP_FILE=./SKIP/mod.skip
TMP_FILE=./TMP/mod.tmp
echo "" > ${OUT_FILE}

filename=$1
echo "" > ${TMP_FILE}

function start_stamp(){
        START=`date +%s`
}
function stamp() {
 END=`date +%s`
 SS=`expr ${END} - ${START}`
 HH=`expr ${SS} / 3600`
 SS=`expr ${SS} % 3600`
 MM=`expr ${SS} / 60`
 SS=`expr ${SS} % 60`
 echo "${HH}:${MM}:${SS}"
}

lineno=0
while read line
do
  lineno=`expr ${lineno} + 1`
  echo ${lineno}
  uid=`echo ${line} | cut -d ${DELIM} -f 1`
  cn=`echo ${line} | cut -d ${DELIM} -f 2`
  sn=`echo ${line} | cut -d ${DELIM} -f 3`
  des=`echo ${line} | cut -d ${DELIM} -f 4`
  pass=`echo ${line} | cut -d ${DELIM} -f 5`
  echo -e "dn: uid=${uid},${OU_USERS},${SUFFIX}\nchangetype: modify\nreplace: cn\ncn: ${cn}\n-\nreplace: sn\nsn: ${sn}\n-\nreplace: description\ndescription: ${des}\n-\nreplace: userPassword\nuserPassword: ${pass}\n" >> ${TMP_FILE}
done < ${filename} stamp >> ${OUT_FILE}
echo "modifing ..."
${com_mod} -x -D "${ldap_admin}" -w $ldap_pass -c -f ${TMP_FILE} -S ${SKIP_FILE}
if test 0 -ne $? ; then
  echo ERROR OCCURED.
fi
stamp >> ${OUT_FILE}

■LDAPユーザー削除シェルプログラム - proc_del.sh

#!/bin/sh
#proc_del.sh
com_add="/usr/bin/ldapadd"
com_search="/usr/bin/ldapsearch"
com_del="/usr/bin/ldapdelete"
com_mod="/usr/bin/ldapmodify"
ldap_admin="cn=Manager,dc=company,dc=jp"
ldap_pass="passl620"
ldap_people="ou=People,dc=company,dc=jp"
user_del_file="./DAT/user_del.ldif"
user_add_file="./DAT/user_add.ldif"
user_mod_file="./DAT/user_mod.ldif"
skipped_file="./DAT/skipped.txt"
DELIM=,
SUFFIX="dc=company,dc=jp"
OU_USERS="ou=People"
OU_GROUPS="ou=Group"
OUT_FILE=./OUT/del.out
SKIP_FILE=./SKIP/del.skip
TMP_FILE=./TMP/del.tmp
echo "" > ${OUT_FILE}
echo "" > ${TMP_FILE}

function start_stamp() {
  START=`date +%s`
}
function stamp() {
 END=`date +%s`
 SS=`expr ${END} - ${START}`
 HH=`expr ${SS} / 3600`
 SS=`expr ${SS} % 3600`
 MM=`expr ${SS} / 60`
 SS=`expr ${SS} % 60`
 echo "${HH}:${MM}:${SS}"
}

start_stamp
filename=$1
lineno=0
while read line
do
  lineno=`expr ${lineno} + 1`
  echo ${lineno}
  uid=`echo ${line} | cut -d ${DELIM} -f 1`
  cn=`echo ${line} | cut -d ${DELIM} -f 2`
  sn=`echo ${line} | cut -d ${DELIM} -f 3`
  des=`echo ${line} | cut -d ${DELIM} -f 4`
  pass=`echo ${line} | cut -d ${DELIM} -f 5`
  echo "uid=${uid},${OU_USERS},${SUFFIX}" >> ${TMP_FILE}
done < ${filename} stamp >> ${OUT_FILE}
echo "deleting ..."
${com_del} -x -D "${ldap_admin}" -w $ldap_pass -c -f ${TMP_FILE}
if test 0 -ne $? ; then
  echo ERROR OCCURED.
fi
stamp >> ${OUT_FILE}

カテゴリー: その他

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

カテゴリー