天天看點

安全鏡像高可用的OpenLDAP叢集

安全鏡像高可用的OpenLDAP叢集

原文:http://www.grantcohoe.com/blog/2013/01/03/secure-mirroring-highly-available-openldap-cluster/

背景

我的組織在OpenLDAP目錄伺服器中存儲使用者資訊,這包括聯系資訊,性格喜好,iButton的辨別等。目錄伺服器不存儲使用者密碼,并依賴于一個Kerberos KDC通過SASL提供身份驗證。這是一個廣受支援和很受歡迎的配置,因為可以實作SSO(單點登入),并儲存密碼在你的目錄中。我們的客戶通過LDAP身份驗證通路機器,基本方法是基于PAM使用由使用者提供的憑據綁定到LDAP伺服器。如果綁定成功後,使用者成功登入;如果沒有,提示資訊給使用者。這個項目之前,我們有一台伺服器運作CentOS5.8/OpenLDAP2.3的目錄伺服器。如果這台伺服器壞掉,那麼所有的使用者資料都将丢失,沒有人可以登入到任何其他的伺服器(或網站,如果配置了斯坦福大學的WebAuth。檢視本作更多的指導)。顯然,這是一個需要糾正的一個問題。

技術

LDAP同步

OpenLDAP的2.4引入了被稱為“mirrormode”的複制方法,這使您可以使用自己已有的syncrepl協定同步多台伺服器之間的資料。以前(<=2.3的OpenLDAP)隻允許你做主從式的複制,其中slave是隻讀的,不能修改。顯然,這存在一些局限性,如果master(或OpenLDAP-ish中的“provider”)死了,那麼你的使用者無法做任何修改,直到master恢複。使用MirrorMode,您可以建立一個“N-way Multi-Master”的拓撲結構,允許所有伺服器進行讀/寫,并立即複制到其它機器。

即使其中一台伺服器死了,為了使使用者能夠持續通路LDAP,我們需要一種方法來保持資料包流動,并自動故障轉移到輔助伺服器。 Linux有一個叫做“Heartbeat”的包,具有這種功能。如果你熟悉Cisco的HSRP或開源的VRRP,它們的工作方式相同。伺服器A被配置設定一個IP位址(例如10.0.0.1 ),伺服器B被配置設定一個不同的位址(例如10.0.0.2 ) 。Heartbeat被配置以提供第三個IP位址( 10.0.0.3 ),将始終在兩者之間保持可用。在master伺服器上,以太網别名以虛拟IP位址建立。定期心跳( keep-alive包)被發送到其他伺服器,表示“我還活着! ” 。如果這些消息消失(當伺服器當機等) 時,輔助主機會注意到無法更新,并自動對自身建立一個類似的别名接口并配置設定虛拟IP位址。這種方法允許給你的用戶端提供一台連接配接的主機,但是它實際上可在多個機器之間無縫切換。

SASL認證

配置MirrorMode的簡單方法需要您存儲複制的DN的憑據以明文方式配置在檔案中。因為你是存儲密碼的明文,顯然這不是很安全。是以,我們可以使用主機的Kerberos主體(principal)綁定到LDAP伺服器作為複制DN并且執行所有我們需要做的任務,這比明文好多了!

SSL

如果要獲得安全,我們應該使用LDAPS(LDAP + SSL)來獲得我們的資料。我們将用我們的PKI來設定此功能,将此作為我們要確定的核心功能中的首要工作。

新伺服器

我準備了兩台新機,我們稱他們為“warlock.example.com”和“ldap2.example.com”。他們每個都跑我最喜歡的Scientific Linux企業版Linux6.2,但用的是OpenLDAP2.4。 在2.3和2.4之間你不能做MirrorMode。

配置

首先我們需要安裝所需的軟體包。

    openldap (LDAP libraries)

    openldap-servers (Server)

    openldap-clients (Client utilities)

    cyrus-sasl (SASL daemon)

    cyrus-sasl-ldap (LDAP authentication for SASL)

    cyrus-sasl-gssapi (Kerberos authentication for SASL)

    krb5-workstation (Kerberos client utilities)

    heartbeat (Failover)

如果你不想使用最小安裝,您可能同時需要安裝openssh用戶端和vim。有些套件可能不包含在你的基本釋出包中,可能需要其他庫(EPEL等)。

Kerberos Keytabs

每個主機都需要有自己的一套主機/和LDAP主體(principals),同時共享一個作為虛拟位址。最後,你需要具有下列主體(principals)的keytab :

    host/[email protected]

    ldap/[email protected]

    host/[email protected]

    ldap/[email protected]

警告:每次你寫一個randkey'd主體至keytab的時候,它的KVNO(密鑰版本号)會增加,進而使以前所有寫入的主體無效。您需要合并共享的主體到每個主機的keytab。請參考我的Kerberos的工具指南,用于執行這些操作。

把這個檔案存為etc/krb5.keytab,并在其上設定ACL,使LDAP使用者可以讀取它。

[[email protected] ~]# chmod 640 /etc/krb5.keytab

[[email protected] ~]# setfacl -m u:ldap:r /etc/krb5.keytab

[[email protected] ~]#

如果你看到這樣的“Kerberos error 13”或“get_sec_context:13”錯誤,這意味着無法讀取keytab,通常是LDAP伺服器,嘗試修複它。

NTP

Kerberos和OpenLDAP的同步需要同步時鐘。如果您尚未設定,在繼續之前按照我的指導在系統上設定NTP。

SASL

您需要在兩個LDAP伺服器上運作saslauthd。如果你還沒有這個設定,在繼續之前按照我的指南配置SASL認證。

日志

我們将使用Syslog和Logrotate為LDAP守護程序(slapd)管理日志檔案。預設情況下它會輸出local4。這個配置取決于你的系統,這裡我使用預設配置。為slapd添加一個條目到您的rsyslog配置檔案(通常是/etc/rsyslog.conf)。

local4.*                /var/log/slapd.log

現在,除非我們告訴logrotate滾動這個檔案,否則它會變得非常大,并導緻很多問題。我建立了一個配置檔案,系統會根據系統預設設定自動滾動此日志檔案。配置檔案為/etc/logrotate.d/slapd:

/var/log/slapd.log {

    missingok

}

然後重新啟動rsyslog。 Logrotate會運作cron任務,并且不需要重新啟動。

資料目錄

因為我從我的舊LDAP伺服器抓取資料,我不會設定新的資料目錄。在舊伺服器和新master上,資料目錄是/var/lib/ldap/。我隻是從舊的伺服器scp所有的内容到此目錄。如果你這樣做,我建議停止舊伺服器片刻,以確定在執行過程中沒有發生變化。在scp是以東西後,一定要改變這些東西的檔案屬性(chown)給LDAP使用者。我還建議運作slapindex,以確定所有資料被索引。

現在要配置用戶端庫,使其友善地測試新的配置,編輯你的/etc/openldap/ldap.conf中的URI,并添加證書設定。

BASE            dc=example,dc=com

URI             ldaps://ldap.example.com

TLS_CACERT      /etc/pki/tls/example-ca.crt

TLS_REQCERT     allow

當在伺服器上配置該檔案時,TLS_REQCERT必須設定為ALLOW,因為我們要通過LDAPS做Syncrepl。很明顯,因為我們使用的是共享的證書ldap.example.com,它不能比對的伺服器主機名就會失敗。在所有的用戶端上,都理所當然需要證書,否則在這種情況使我們無法通過LDAPS完成Syncrepl。

LDAPS證書

具有安全需求,OpenLDAP具有TLS通道内的會話的能力。這種工作方式和HTTPS一樣。要做到這一點,你需要有生成基于給定的CA SSL證書的能力。此過程依據組織機構不同而各異。不管怎樣,你所選擇的主機名是至關重要的,因為主機名将被驗證。在這種設定中,我們建立了一個“ldap.example.com”的主機名,所有LDAP用戶端将配置使用。在兩個主機上生成“ldap.example.com”主機名的相同SSL證書,并放置在每個伺服器上。

我存放公有證書/etc/pki/tls/certs/slapd.pem, 私有證書/etc/pki/tls/private/slapd.pem, 以及CA憑證/etc/pki/tls/example-ca.crt. 在擷取這些檔案後,我檢查他們確定他們會實際工作:

[[email protected] ~]# openssl verify -CAfile /etc/pki/tls/example-ca.crt /etc/pki/tls/certs/slapd.pem

/etc/pki/tls/certs/slapd.pem: OK

[[email protected] ~]#

你需要允許LDAP帳戶讀取私有證書:

[[email protected] ~]# setfacl -m u:ldap:r /etc/pki/tls/private/slapd.pem

伺服器配置

如果您使用的是以前的伺服器配置,隻需使用scp複制整個的/etc/openldap代碼到新的伺服器。在複制之前,確定你移走可能要拷貝進來的任何檔案或目錄。如果你不這樣做,你可能需要做一些設定。OpenLDAP2.4使用配置的新方法被稱為“cn=config”,它是存儲在LDAP資料庫中的配置資料。然而,由于這不是完全支援大多數用戶端,我仍使用配置檔案。要建立一個全新的安裝,請參考我在此的其他文章之一。 (仍然在寫這篇文章的過程中)

下面的SSL證書指令需要放置在你的slapd.conf中:

TLSCertificateFile /etc/pki/tls/certs/slapd.pem

TLSCertificateKeyFile /etc/pki/tls/private/slapd.pem

TLSCACertificateFile /etc/pki/tls/example-ca.crt

根據您的系統,您可能需要配置運作在LDAPS://上的守護程序。在Red-Hat系統中,這些是在/etc/sysconfig/ldap中。

為了Syncrepl功能需要,您需要給你的配置添加兩件東西。首先在你的slapd.conf中:

# Syncrepl ServerID

serverID 001

# Syncrepl configuration for mirroring instant replication between another

# server. The binddn should be the host/ principal of this server

# stored in the Kerberos keytab

syncrepl rid=001

provider=ldaps://ldap2.example.com

type=refreshAndPersist

retry="5 5 300 +"

searchbase="dc=example,dc=com"

attrs="*,+"

bindmethod=sasl

binddn="cn=ldap1,ou=hosts,dc=example,dc=com"

mirrormode TRUE

該serverID值必須唯一地辨別該伺服器。請確定您在配置中加入輔助伺服器,同樣需要修改Syncrepl RID。

其次,你需要使複制的binddn具有完全讀取所有對象的權限。這應該在你的ACL檔案中控制(在slapd.conf中)。

access to *

        by dn.exact="cn=ldap1,ou=hosts,dc=example,dc=com" read

        by dn.exact="cn=ldap2,ou=hosts,dc=example,dc=com" read

警告:如果你沒有一個現有的ACL設定,這樣做隻是防止非授權的任何修改。這些指令的目的是要添加到現有的ACL中。

做好以上全部設定并準備啟動伺服器。        

[[email protected] ~]# service slapd start

Starting slapd:                                            [  OK  ]

[[email protected] ~]#

確定當你做SASL綁定時,伺服器正确地報告您的DN。通過下面指令驗證這一點:

ldap1 ~ # su ldap -s /bin/bash

bash-4.1$ kinit -k -t /etc/krb5.keytab host/ldap1.example.com

bash-4.1$ ldapwhoami -Q

dn:cn=ldap1,ou=hosts,dc=example,dc=com

bash-4.1$

該DN是一個應該在你的ACL中設定,并且有權限通路任何東西。

由于LDAP使用者總是需要這個主體(principal),我建議增加一個cronjob,以保持ticket活着。我寫了一個腳本,它會更新您的ticket以及修複一個SELinux的權限管理問題。你可以在這裡得到它,隻要把它放到/usr/local/sbin/目錄下。可能會有更好的方法,但是這個腳本也工作得挺好。

0 */2 * * * /usr/local/sbin/slaprenew

防火牆

不要忘記為LDAP和LDAPSSL開放389和636端口。

搜尋

配置兩台主伺服器和輔助伺服器後,我們現在需要使輔助伺服器接收複制的初始資料。假設你不喜歡這樣做,從舊伺服器複制資料目錄,你的master是唯一一個有真實資料的機器。啟動這台機器上的服務,如果一切按計劃順利進行,你應該能夠搜尋到對象,以驗證它工作正常。

[[email protected] ~]# kinit user

Password for [email protected]:

[[email protected] ~]# ldapsearch -h localhost uid=user uidNumber -Q -LLL

dn: uid=user,ou=users,dc=example,dc=com

uidNumber: 10046

[[email protected] ~]#

如果出現錯誤,提高調試級别(-d 1),并輸出詳細錯誤。

複制

依照如上所述在做kinit LDAP使用者(host/ldap2.example.com)後,啟動輔助LDAP伺服器。如果你用tail跟蹤slapd的日志檔案,你應該可以看到發生的非常快的複制事件。這是伺服器從在slapd.conf中指定的提供者處裝載它的資料。一旦完成,請以上面類似的方式嘗試搜尋伺服器。

[[email protected] ~]# tail /var/log/slapd.log

slapd[15759]: syncrepl_entry: rid=001 be_search (0)

slapd[15759]: syncrepl_entry: rid=001 uid=user,ou=Users,dc=example,dc=com

slapd[15759]: syncrepl_entry: rid=001 be_add uid=user,ou=Users,dc=example,dc=com (0)

slapd[15759]: syncrepl_entry: rid=001 LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_ADD)

slapd[15759]: syncrepl_entry: rid=001 inserted UUID 84ba3544-5be8-102b-9a32-4dfcdb785320

slapd[15759]: syncrepl_entry: rid=001 be_search (0)

slapd[15759]: syncrepl_entry: rid=001 uid=user,ou=Users,dc=example,dc=com

slapd[15759]: syncrepl_entry: rid=001 be_add uid=user,ou=Users,dc=example,dc=com (0)

slapd[15759]: syncrepl_entry: rid=001 LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_ADD)

slapd[15759]: syncrepl_entry: rid=001 inserted UUID 84c04164-5be8-102b-9a33-4dfcdb785320

slapd[15759]: syncrepl_entry: rid=001 be_search (0)

心跳(Heartbeat)

心跳為在多個Linux系統之間的配置資源提供故障轉移(failover)。在這種情況下,我們将提供高可用性的一個别名IP位址(10.0.0.3),将此IP提供給用戶端作為LDAP伺服器(ldap.example.com)。 Heartbeat配置非常簡單,隻需要三個檔案:

在/etc/ha.d/haresources中包含我們将故障轉移的資源,這個配置在兩台伺服器上應該是相同的。

ldap1.example.com IPaddr::10.0.0.3/24/eth0:1/10.0.0.255

上面主機的名稱不是“ldap.example.com”,究其原因是因為該條目必須是在配置檔案(下面)中列出的一個節點。

在/etc/ha.d/authkeys中包含用于保護心跳封包的共享密碼,這是為了防止有人未授權而連接配接一台伺服器,并聲稱自己是群集的一部分。

auth 1

1 md5 mysupersecretpassword

請務必執行指令chmod,確定不是所有人都可讀(推薦600)。

最後,/etc/ha.d/ha.cf是Heartbeat的配置檔案,它應該包含每一個叢集中的伺服器、計時器和日志檔案條目。

mcast           eth0 225.0.0.1 694 1 0

auto_failback   on

keepalive 1

deadtime 5

debugfile       /var/log/ha-debug.log

logfile         /var/log/ha.log

logfacility     local0

udp             eth0

node            ldap1.example.com

node            ldap2.example.com

在這些所有設定好之後,啟動heartbeat服務。過一會,你應該看到另一個以太網接口顯示為您的master。要測試故障轉移,拔掉一台機子,看看會發生什麼!

DNS Hack

使LDAP伺服器響應共享IP位址的副作用是,它無法知道真正主機名。是以你需要編輯你的/etc/hosts檔案,列出ldap.example.com名稱對應的每個實際的主機IP位址。在這個例子中,ldap1是10.0.0.1、ldap2是10.0.0.2。你應該修改hosts檔案,包括:

10.0.0.1 ldap.example.com ldap

10.0.0.2 ldap.example.com ldap

第一個條目應該是本地系統的位址(在ldap2案例中10.0.0.2應該在第一個)。

您的DNS伺服器應該能夠做到正向和反向查找ldap.example.com對應10.0.0.3(高度可用的位址)。

如果您有伺服器之間綁定或者來自用戶端綁定的問題,它通常是由于DNS的問題。

測試

如果一切按計劃順利進行,你應該可以在slapd的日志檔案中看到同步(Sync)消息。

slapd[11059]: slapd starting

slapd[11059]: do_syncrep2: rid=002 LDAP_RES_INTERMEDIATE - REFRESH_DELETE

同樣,如果您登入到客戶機(在我的案例中,我做了這個KDC),你應該隻能夠在ldap.example.com主機上搜尋,其他的将傳回錯誤。

[[email protected] ~]# ldapsearch -Q -LLL uid=user displayName -h ldap.example.com

dn: uid=user,ou=users,dc=example,dc=com

displayName: Firstname Lastname (user)

[[email protected] ~]# ldapsearch -Q -LLL uid=user displayName -h ldap1.example.com

ldap_sasl_interactive_bind_s: Invalid credentials (49)

        additional info: SASL(-13): authentication failure: GSSAPI Failure: gss_accept_sec_context

[[email protected] ~]# ldapsearch -Q -LLL uid=user displayName -h ldap2.example.com

ldap_sasl_interactive_bind_s: Invalid credentials (49)

        additional info: SASL(-13): authentication failure: GSSAPI Failure: gss_accept_sec_context

[[email protected] ~]#

該原因是,用戶端從不同的視角識别伺服器的主機名是什麼。這種差異導緻SASL

崩潰,而不讓你綁定。

錯誤

[[email protected] ~]# ldapsearch -h ldap.example.com uid=user

SASL/GSSAPI authentication started

ldap_sasl_interactive_bind_s: Invalid credentials (49)

        additional info: SASL(-13): authentication failure: GSSAPI Failure: gss_accept_sec_context

[[email protected] ~]#

在伺服器上顯示的錯誤:

slapd[9888]: GSSAPI Error: Unspecified GSS failure.  Minor code may provide more information (Wrong principal in request)

slapd[9888]: text=SASL(-13): authentication failure: GSSAPI Failure: gss_accept_sec_context

這意味着你的DNS沒有配置或失去功能,按照說明修複它。

LDAP日志顯示:

slapd[1901]: do_syncrepl: rid=005 rc -2 retrying

slapd[1901]: slap_client_connect: URI=ldap://ldap2.example.com ldap_sasl_interactive_bind_s failed (-2)

并且 /var/log/messages 包含:

GSSAPI Error: Unspecified GSS failure.  Minor code may provide more information (Credentials cache permissions incorrect)

你需要改變你的KRB5CC檔案的SELinux上下文(預設是Scientific Linux上的/tmp/krb5cc_$UIDOFLDAPUSER),以便slapd程序可以讀取。由于每次重新初始化票據,可能造成權限的違約風險,我推薦使用上面cronjob中的腳本。如果有人發現一個更好的方式能做到這一點,請讓我知道!

如果您的用戶端上啟用SSL後,您會收到(使用-d 1):

TLS: can't connect: TLS error -5938:Encountered end of file.

檢查伺服器證書檔案,可能是你設定的路徑不正确。

總結

現在你有兩個獨立運作OpenLDAP2.4的LDAP伺服器,并且它們之間可以進行資料同步。通過監聽一個心跳服務IP位址,他們的目的是即使其中一台伺服器死掉,也将始終保持可用。你也可以綁定SASL到每個伺服器,以避免在您的配置檔案中存儲密碼。

如果看完本文後你覺得有什麼可以改善的或不清晰的地方,請随時與我聯系!您也可以下載下傳在http://archive.grantcohoe.com/projects/ldap上的示例配置檔案。

繼續閱讀