OpenLDAPのミラーモード[さくらのVPS/CentOS7]

OpenLDAPのミラーモードを2台のサーバで構築する手順。2台のOpenLDAPサーバに同時に更新を行うと問題が発生する場合がある為、keepalived で VIPを使用できるように設定する。セットアップは 1台目と2台目のサーバで全く同じコマンドを実行する。

・環境

Network InterfaceIPアドレス
1台目:eth1192.168.0.11/24
2台目:eth1192.168.0.12/24
VIP192.168.0.10/24

1. firewalld のセットアップ

#-- eth1 への IPアドレスは事前に設定してあること
#-- eth1 への通信を許可
firewall-cmd --add-interface=eth1 --permanent --zone=trusted 
firewall-cmd --reload

2. keepalived のセットアップ

#-- keepalived のインストール
yum install -y keepalived
systemctl enable keepalived

#-- VIPの設定
cat <<_EOF_> /etc/keepalived/keepalived.conf
vrrp_sync_group VG1 {
  group {
    SERVICE
  }
}

vrrp_instance SERVICE {
  state BACKUP
  interface eth1
  virtual_router_id 1
  priority 100
  advert_int 5
  virtual_ipaddress {
    192.168.0.10
  }
}
_EOF_

#-- keepalived の起動
systemctl start keepalived

#-- これで VIP がどちらかのサーバに設定される

3. openldap のセットアップ

#-- rsyslog に slapd のログ出力設定を追加
echo "local4.*  /var/log/openldaplog" > /etc/rsyslog.d/openldap.conf
sed -i '1s#^#/var/log/openldaplog\n#' /etc/logrotate.d/syslog
systemctl restart rsyslog

#-- パスワードを変数にセット
ROOT_PASSWORD="YourPassword"
ROOT_PW=$(slappasswd -s ${ROOT_PASSWORD})

#-- openldap のインストール (sendmail.schema が必要ない場合、sendmail-cf はインストールしない)
yum install -y openldap-servers openldap-clients sendmail-cf

#-- sendmail schema を保存
cp -p /usr/share/sendmail-cf/sendmail.schema /etc/openldap/schema/

#-- slapd.conf を作成 (schemaは、ミラーモードに 必要なもの + sendmail.schema のみ有効) 
cat <<_EOL_> /etc/openldap/slapd.conf
loglevel 256
sizelimit -1
#include  /etc/openldap/schema/corba.schema
#include  /etc/openldap/schema/duaconf.schema
#include  /etc/openldap/schema/java.schema
#include  /etc/openldap/schema/nis.schema
#include  /etc/openldap/schema/ppolicy.schema
#include  /etc/openldap/schema/collective.schema
include  /etc/openldap/schema/core.schema
include  /etc/openldap/schema/cosine.schema
include  /etc/openldap/schema/dyngroup.schema
include  /etc/openldap/schema/inetorgperson.schema
include  /etc/openldap/schema/misc.schema
include  /etc/openldap/schema/openldap.schema
include  /etc/openldap/schema/sendmail.schema
allow bind_v2
pidfile  /var/run/openldap/slapd.pid
argsfile /var/run/openldap/slapd.args
moduleload syncprov.la
moduleload back_hdb.la
backend hdb
#-- config 用データベースに対するアクセス制限
database config
rootdn  "cn=config"
rootpw  "${ROOT_PW}"
access to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
    by dn="cn=manager" manage
    by * none
overlay syncprov
#-- monitor データベースに対するアクセス制限
#   ROOT_DN のみ read 可能
#   確認コマンド ldapsearch -x -D "cn=config" -W +
database monitor
access to *
    by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read
    by * none
#-- user データベース
database hdb
suffix  ""
rootdn  "cn=manager"
rootpw  "${ROOT_PW}"
#--- userPassword に対するアクセス制限
#   自分自身は書き換え可能
#   ROOT_DN は書き換え可能
#   匿名接続ならば、認証したときにこの属性が使える
access to attrs=UserPassword
    by self write
    by anonymous auth
    by * none
#-- Termed は ROOT_DN のみ書き換え可能
access to dn.regex="uid=.*,ou=Termed,dc=.*"
    by * none
#-- その他の属性は ROOT_DN のみ書き換え可能
#   ROOT_DN 以外は read のみ可能
access to *
    by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
    by * read
checkpoint 1024 15
directory /var/lib/ldap
index entryCSN,entryUUID eq
index objectClass   eq,pres
index uid           eq,pres,sub
index mailHost,mailRoutingAddress,mailLocalAddress,sendmailMTAHost eq,pres
overlay syncprov
_EOL_

#-- slapd.conf から olc に設定を変換する為の前処理
rm -rf /etc/openldap/slapd.d/* /var/lib/ldap/*
mv /etc/openldap/slapd.d /etc/openldap/slapd.d.org

#-- DB_CONFIGの設定
# cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
cat <<'_EOL_'> /var/lib/ldap/DB_CONFIG
set_cachesize 0 10485760 1
set_flags DB_LOG_AUTOREMOVE
set_lg_regionmax 262144
set_lg_bsize 2097152
_EOL_

#-- DBの初期化など
systemctl start slapd
systemctl stop slapd
mv /etc/openldap/slapd.d.org /etc/openldap/slapd.d

#-- slapd.conf から olc に設定を変換
sudo -u ldap slaptest -f /etc/openldap/slapd.conf -F /etc/openldap/slapd.d

#-- slapd の起動
systemctl enable slapd
systemctl start slapd

#-- ミラーモードの ldif 作成
cat <<_EOL_> /tmp/ldap_mirror.ldif
dn: cn=config
changetype: modify
add: olcServerID
olcServerID: 001 ldap://192.168.0.11
-
add: olcServerID
olcServerID: 002 ldap://192.168.0.12

dn: olcDatabase={2}hdb,cn=config
changetype: modify
add: olcSyncRepl
olcSyncRepl: rid=001 provider=ldap://192.168.0.12/ binddn="cn=manager" bindmethod=simple credentials=${ROOT_PASSWORD} searchbase="" type=refreshAndPersist retry="5 10 60 +" timeout=1 scope=sub starttls=no schemachecking=ok
olcSyncRepl: rid=002 provider=ldap://192.168.0.11/ binddn="cn=manager" bindmethod=simple credentials=${ROOT_PASSWORD} searchbase="" type=refreshAndPersist retry="5 10 60 +" timeout=1 scope=sub starttls=no schemachecking=ok
-
add: olcMirrorMode
olcMirrorMode: TRUE

dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcSyncRepl
olcSyncRepl: rid=001 provider=ldap://192.168.0.12/ binddn="cn=config" bindmethod=simple credentials=${ROOT_PASSWORD} searchbase="cn=config" type=refreshAndPersist retry="5 10 300 +" timeout=1
olcSyncRepl: rid=002 provider=ldap://192.168.0.11/ binddn="cn=config" bindmethod=simple credentials=${ROOT_PASSWORD} searchbase="cn=config" type=refreshAndPersist retry="5 10 300 +" timeout=1
-
add: olcMirrorMode
olcMirrorMode: TRUE
_EOL_

#-- ミラーモードの設定投入
ldapadd -D "cn=config" -w ${ROOT_PASSWORD} -f /tmp/ldap_mirror.ldif

# これで VIP に対して更新処理を行えば、もう一方のサーバにも更新内容が反映される

04. LDAPサーバ構築 – openldap [さくらのVPS/CentOS7]

・LDAPサーバの用途

  1. メールアカウントの管理・認証
  2. Basic認証
  3. 各Webアプリケーションの認証

・LDAPサーバの構築

#-- 変数に必要な値を代入
ROOT_DN="cn=admin,dc=masdon,dc=life"
ROOT_PASSWORD="********"     #-- ROOT_DNのパスワードを入力
LDAP_MASTER=127.0.0.1
DOMAIN=masdon.life

#-- openldap と sendmail.schema をインストール
yum install -y openldap-servers openldap-clients sendmail-cf
ROOT_PW=$(slappasswd -s ${ROOT_PASSWORD})

#-- DB_CONFIG の作成
cat <<'_EOL_'> /var/lib/ldap/DB_CONFIG
set_cachesize 0 10485760 1
set_flags DB_LOG_AUTOREMOVE
set_lg_regionmax 262144
set_lg_bsize 2097152
_EOL_

#-- sendmail.schema を 指定のディレクトリへコピー
cp -p /usr/share/sendmail-cf/sendmail.schema /etc/openldap/schema/

#-- openldap の設定
cat <<_EOL_> /etc/openldap/slapd.conf
loglevel 0x4100
sizelimit -1
include  /etc/openldap/schema/corba.schema
include  /etc/openldap/schema/core.schema
include  /etc/openldap/schema/cosine.schema
include  /etc/openldap/schema/duaconf.schema
include  /etc/openldap/schema/dyngroup.schema
include  /etc/openldap/schema/inetorgperson.schema
include  /etc/openldap/schema/java.schema
include  /etc/openldap/schema/misc.schema
include  /etc/openldap/schema/nis.schema
include  /etc/openldap/schema/openldap.schema
include  /etc/openldap/schema/ppolicy.schema
include  /etc/openldap/schema/collective.schema
include  /etc/openldap/schema/sendmail.schema
allow bind_v2
pidfile  /var/run/openldap/slapd.pid
argsfile /var/run/openldap/slapd.args
moduleload syncprov.la
access to attrs=UserPassword
    by dn="${ROOT_DN}" write
    by self write
    by anonymous auth
    by * none
access to dn.regex="uid=.*,ou=Termed,dc=.*"
    by * none
access to *
    by * read
database config
access to *
    by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
    by * none
database monitor
access to *
    by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read
    by dn.exact="${ROOT_DN}" read
    by * none
database bdb
suffix  ""
checkpoint 1024 15
rootdn  "${ROOT_DN}"
rootpw  "${ROOT_PW}"
directory /var/lib/ldap
index objectClass   eq,pres
index uid           eq,pres,sub
index mailHost,mailRoutingAddress,mailLocalAddress,userPassword,sendmailMTAHost eq,pres
_EOL_

#-- slapd の起動オプションを変更
sed -i "s#^SLAPD_URLS=.*#SLAPD_URLS=\"ldap://${LDAP_MASTER}/\"#" /etc/sysconfig/slapd

#-- yum update で /etc/openlda/slapd.d が再作成されると slapd の起動が失敗するので定期的に確認して削除、同じく slapd.conf も slapd.conf.bakにリネームされるので元に戻す
mv /etc/openldap/slapd.d /etc/openldap/slapd.d.org
echo '* * * * * root rm -rf /etc/openldap/slapd.d >/dev/null 2>&1' > /etc/cron.d/${DOMAIN}-cron
echo '* * * * * root /usr/bin/mv -f /etc/openldap/slapd.conf.bak /etc/openldap/slapd.conf >/dev/null 2>&1' >>/etc/cron.d/${DOMAIN}-cron

#-- rsyslog の設定と logrotate の設定
echo "local4.*  /var/log/openldap" > /etc/rsyslog.d/openldap.conf
sed -i '1s#^#/var/log/openldap\n#' /etc/logrotate.d/syslog
systemctl restart rsyslog

#-- openldap を起動
systemctl enable slapd
systemctl start slapd

・ドメインと管理ユーザを登録

WORKDIR=~/work
mkdir -p ${WORKDIR}/ldap

#-- メールドメイン用の ldifファイルを作成
TMPDN=""
for x in $(for y in $(echo "${DOMAIN}" | sed 's/\./ /g')
do
    echo ${y}
done | tac)
do
    TMPDN="dc=${x}${TMPDN}"
cat <<_EOL_>>${WORKDIR}/ldap/init.ldif
dn: ${TMPDN}
objectClass: dcObject
objectClass: organization
dc: ${x}
o: ${DOMAIN}

_EOL_
    TMPDN=",${TMPDN}"
done

#-- 作成した ldif を LDAPサーバに登録
ldapadd -x -h ${LDAP_MASTER} -D "${ROOT_DN}" -w ${ROOT_PASSWORD} -f ${WORKDIR}/ldap/init.ldif

・管理者用メールアドレスの作成

#-- 管理者用メールアドレスを作成するスクリプトを作成
cat <<'_EOL_'> /usr/local/bin/create_admin_address.sh
#!/bin/bash
#
# usage)
# ./create_admin_address.sh domain

DOMAIN=$1
LDAP_MASTER=127.0.0.1
OUTBOUND_MTA_SERVER=127.0.0.1
STORE_SERVER=127.0.0.1
ROOT_DN="cn=admin,dc=masdon,dc=life"
ROOT_PASSWORD="********"  #-- ROOT_DNのパスワードを入力
WORKDIR=/root/work/ldap
ADMINS=" admin root postmaster abuse virus-report nobody "

ldapsearch -x -h ${LDAP_MASTER} -D "${ROOT_DN}" -w "${ROOT_PASSWORD}" > /dev/null 2>&1

if [ $? -ne 0 ]
then
  echo "invalid rootdn or rootpassword!!"
  exit 1
fi

mkdir -p ${WORKDIR}

ACCOUNT=$(echo ${ADMINS} | awk '{print $1}')
SSHAPW=$(slappasswd -s "${ROOT_PASSWORD}")
TMPDN=""
for x in $(for y in $(echo "${DOMAIN}" | sed 's/\./ /g')
do
  echo ${y}
done | tac)
do
  TMPDN="dc=${x}${TMPDN}"
  if [ $(ldapsearch -h ${LDAP_MASTER} -x -D "${ROOT_DN}" -w "${ROOT_PASSWORD}" -b "${TMPDN}" | grep -c ^dn:) -eq 0 ]
  then
    cat <<_EOF_>>${WORKDIR}/${DOMAIN}.ldif
dn: ${TMPDN}
objectClass: dcObject
objectClass: organization
dc: ${x}
o: ${DOMAIN}

_EOF_
  fi
  TMPDN=",${TMPDN}"
done

BASEDN=$(echo ${TMPDN} | sed 's/^,//')
BASEDN="ou=People,${BASEDN}"
TERMED=$(echo ${BASEDN} | sed 's/ou=People/ou=Termed/')

cat <<_EOF_>>${WORKDIR}/${DOMAIN}.ldif
dn: ${BASEDN}
ou: People
objectclass: organizationalUnit

dn: ${TERMED}
ou: Termed
objectclass: organizationalUnit

dn: uid=${ACCOUNT},${BASEDN}
objectclass: uidObject
objectClass: simpleSecurityObject
objectClass: inetLocalMailRecipient
objectClass: sendmailMTA
uid: ${ACCOUNT}
userPassword: ${SSHAPW}
mailHost: ${STORE_SERVER}
sendmailMTAHost: ${OUTBOUND_MTA_SERVER}
description: ${DOMAIN}
mailRoutingAddress: ${ACCOUNT}@${DOMAIN}
mailLocalAddress: ${ACCOUNT}@${DOMAIN}
_EOF_

for z in ${ADMINS}
do
  if [ "${z}" = "${ACCOUNT}" ]
  then
    continue
  fi
  echo "mailLocalAddress: ${z}@${DOMAIN}" >> ${WORKDIR}/${DOMAIN}.ldif
done
echo >> ${WORKDIR}/${DOMAIN}.ldif
ldapadd -x -h ${LDAP_MASTER} -D "${ROOT_DN}" -w "${ROOT_PASSWORD}" -f ${WORKDIR}/${DOMAIN}.ldif

_EOL_

#-- 管理者用メールアドレス作成
chmod 755 /usr/local/bin/create_admin_address.sh
/usr/local/bin/create_admin_address.sh ${DOMAIN}

・メールアドレスの作成

#-- メールアドレスを作成するスクリプトを作成
cat <<'_EOL_'> /usr/local/bin/create_mailaddress.sh
#!/bin/bash
# usage) ./create_mailaddress.sh <mailaddress>
ADDRESS=$1
LDAP_MASTER=127.0.0.1
STORE_SERVER=127.0.0.1
OUTBOUND_MTA_SERVER=127.0.0.1
ROOT_DN="cn=admin,dc=masdon,dc=life"
ROOT_PASSWORD="********"  #-- ROOT_DNのパスワードを入力
WORKDIR=/root/work/ldap

ldapsearch -x -h ${LDAP_MASTER} -D "${ROOT_DN}" -w ${ROOT_PASSWORD} > /dev/null 2>&1

if [ $? -ne 0 ]
then
	echo "invalid rootdn or rootpassword!!"
	exit 1
fi

if [ $(ldapsearch -x mailRoutingAddress=${ADDRESS} | grep -c "^mailRoutingAddress") -ne 0 ]
then
	echo "${ADDRESS} is already exist!!"
	exit 1
fi

mkdir -p ${WORKDIR}/ldap

ACCOUNT=$(echo ${ADDRESS} | awk -F@ '{print $1}')
if [ $(echo "${ADMINS}" | grep -c " ${ACCOUNT} ") -eq 1 ]
then
	echo "skip ${ADDRESS}"
	continue
fi
DOMAIN=$(echo ${ADDRESS} | awk -F@ '{print $2}')
mkdir -p ${WORKDIR}/${DOMAIN}
LDIFDIR=${WORKDIR}/${DOMAIN}
PASSWORD=$(mkpasswd -l 12 -d 3 -c 3 -C 3 -s 0)
SSHAPW=$(slappasswd -s ${PASSWORD})
BASEDN=""
for x in $(echo "${DOMAIN}" | sed 's/\./ /g')
do
	BASEDN="${BASEDN},dc=${x}"
done
BASEDN="ou=People${BASEDN}"

cat <<_EOF_>>${LDIFDIR}/${ACCOUNT}.ldif
dn: uid=${ACCOUNT},${BASEDN}
objectclass: uidObject
objectClass: simpleSecurityObject
objectclass: inetLocalMailRecipient
objectClass: sendmailMTA
uid: ${ACCOUNT}
userPassword: ${SSHAPW}
mailHost: ${STORE_SERVER}
sendmailMTAHost: ${OUTBOUND_MTA_SERVER}
mailRoutingAddress: ${ACCOUNT}@${DOMAIN}
mailLocalAddress: ${ACCOUNT}@${DOMAIN}

_EOF_

ldapadd -x -h ${LDAP_MASTER} -D "${ROOT_DN}" -w ${ROOT_PASSWORD} -f ${LDIFDIR}/${ACCOUNT}.ldif >/dev/null && echo ${PASSWORD}
_EOL_

chmod 755 /usr/local/bin/create_mailaddress.sh

・使用するアトリビュートの説明

アトリビュート説明
uidユーザ名admin
mailRoutingAddress配送先メールアドレス
認証に使用
admin@masdon.life
mailLocalAddressエイリアスメールアドレス
このアドレスに届いたメールは、
mailRoutingAddress の MBOX に配送される
admin@masdon.life
abuse@masdon.life
root@masdon.life
userPasswordパスワード{SSHA}ZiGSOKPJHbr9Jy2r2Q9hhJpdDv……
mailHostメール保存サーバ127.0.0.1
sendmailMTAHostメール送信サーバ127.0.0.1
description特にシステムで使用はしていない
ouPeople の場合は有効アカウント
Termed の場合は無効アカウント

これから構築するメールサーバはメールアドレスを LDAP に登録するだけですぐに使用できるようになる