Home

Awesome

ADtoLDAP

This is a badly written program that will gather results from Active Directory or another openldap server based on the attributes specified in /etc/ldapsync.ini, and sync it to the second ldap server.

This is tested against Windows Server 2012 as Primary and OpenLDAP server as Secondary, but should be able to work with any LDAP based Primary and Secondary servers as long as the required attributes are enabled on the Primary and the program is able to connect to both of them and be able to write to the Secondary.

Extended unix attributes needs to be enabled on the Active directory to enable the uid and gid fields on the master. The basedn which must be synced from, for eg:basedn = ou=someOu,dc=example,dc=com in the sample configuration below must be created on the destination server to acommodate the sync. For Active directory to LDAP syncing, we need to make sure that the schema of the openldap server is prepared to accomodate the additional attibutes AD incorporates, if we are syncing them. (an example would be the memberOf: attribute) Better - omit those unless required.

This can run over an encrypted connection if the UseTLS section in the configuration is set to true. To use TLS, make sure to add the domain name for which the AD certificate is generated. If that fails, the program panics throwing

panic: LDAP Result Code 200 "": x509: certificate is valid for example1.domain.com, example2.domain.com, EXAMPLE, not examples.domains.com

Using TLS will make it hard for decrypting the data transferred over wire. Without using TLS, the data can be viewed with a packet capturing program like tcpdump like

tcpdump -v -XX

Requirements to set up TLS connection

How to install

Since this program uses versioned modules, it requires a minimum of go-1.11 to compile.

go get github.com/nohupped/ADtoLDAP

A badly written Daemonizer is also included in the Daemonizer directory that daemonize itself, forks again and runs the program and capture any errors or panics that the program throws to the STDOUT/STDERR, and logs it to the syslog. Compile it as

gcc  -W -Wall ./main.c ./src/ForkSelf.c -o daemonizer

The program can be daemonized as

<path/to>/daemonizer <path/to>/ADtoLDAP

The Daemoniser was written as a part of learning. Use a Systemd Unit file instead.

Enable memberOf attribute in ldap (required only if we are syncing it) to accomodate the equivalent AD field, by using the 3 ldif files included here in this repo.

ldapadd -Q -Y EXTERNAL -H ldapi:/// -f memberof_load_configure.ldif
ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f 1refint.ldif
ldapadd -Q -Y EXTERNAL -H ldapi:/// -f 2refint.ldif

The permission of /etc/ldapsync.ini

The program checks if the file permissions for /etc/ldapsync.ini are too broad. If it is not 600, the program will report that, and will not start. This can be over-ridden by running the program with the flag --safe=false. This is to make sure that the password in the ldapsync.ini are not exposed to world readable.

Sample ldapsync.ini file to sync from a Windows AD server to an OpenLDAP server

A sample config file can be printed to stdout by running

./ADtoLDAP -showSampleConfig

Output:

### Sample config generated by the program. Edit accordingly ###
[ADServer]
Host = <host ip>
#ADPort = 389 for non ssl and 636 for ssl
Port = 389
UseTLS = false
# set InsecureSkipVerify to true for testing, to accept the certificate without any verification.
InsecureSkipVerify = true
#CRTValidFor will not be honored if InsecureSkipVerify is set to true.
CRTValidFor = example1.domain.com
#Path to the pem file, which is used to create the custom CA pool. Will not be honored if InsecureSkipVerify is set to true.
#CRTPath = /etc/ldap.crt
#Page the result size to prevent possible OOM error and crash
Page = 500
#AD Connection Timeout in seconds (Defaults to 10)
ConnTimeOut = 10
username = cn=neo,cn=Users,dc=example,dc=com
password = somepassword
basedn = ou=someou,dc=example,dc=com
#Attributes required to be pulled
attr = givenName, unixHomeDirectory, sn, loginShell, memberOf, dn, o, uid, objectclass, cn, displayName, cn, uidNumber, gidNumber, member
#ldap filter
filter = (cn=*)

[LDAPServer]
Host = <ldap server ip>
Port = 389
UseTLS = false
InsecureSkipVerify = true
CRTValidFor = ldapserver.example.com
#CRTPath = /etc/ldap/sasl2/server.crt
#Page LDAP result
Page = 500
#LDAP Connection Timeout in seconds (Defaults to 10)
ConnTimeOut = 10
username = cn=admin,dc=ldap,dc=example,dc=com
password = somepassword
basedn = ou=someOu,dc=example,dc=com
attr = givenName, homeDirectory, sn, loginShell, memberOf, dn, o, uid, objectclass, cn, displayName, cn, uidNumber, gidNumber, memberUid
filter = (cn=*)


[Replace]
userObjectClass = posixAccount,top,inetOrgPerson
groupObjectClass = top,posixGroup
[Map]
#ADAttribute = ldapattribute, that is mapping AD attribute to the relevant ldap attribute
unixHomeDirectory = homeDirectory
#specify member mapping if you are selecting member attribute from *attr above
member = memberUid

[Sync]
#Add sleep time after each successful sync, in seconds.
sleepTime = 5
# loglevel can be set to either of
#   ErrorLevel = iota // 0
#   WarnLevel // 1
#   InfoLevel // 2
#   DebugLevel // 3
# Uncomment the below line and set to desired value. Defaults to DebugLevel.
# loglevel = DebugLevel

Eg:

./ADtoLDAP --safe=false --configfile=/etc/ldapsync.ini --logfile=/tmp/ldapsync.log

--safe=false will omit the config file permission checking.

--logfile=<path> will write to that log file. Defaults to /var/log/ldapsync.log.

--config-file=<path> if not specified, takes the default path /etc/ldapsync.ini.

Sample /etc/ldapsync.ini for syncing from one OpenLDAP server to another OpenLDAP server

[ADServer]
Host = <LDAP server1 IP>
Port = 636
UseTLS = true
# set InsecureSkipVerify to true for testing, to accept the certificate without any verification.
InsecureSkipVerify = false
#CRTValidFor will not be honored if InsecureSkipVerify is set to true.
CRTValidFor = example1.domain.com
#Path to the pem file, which is used to create the custom CA pool. Will not be honored if InsecureSkipVerify is set to true.
CRTPath = /etc/ldap.crt
#Page the result size to prevent possible OOM error and crash
Page = 500
#AD Connection Timeout in seconds (Defaults to 10)
ConnTimeOut = 10
username = cn=someuser,dc=example,dc=com
password = somepassword1
basedn = ou=SomeOU,dc=example,dc=com
#Attributes required to be pulled
#attr = comment, givenName, unixHomeDirectory, sn, loginShell, memberOf, dn, o, uid, objectclass, cn, displayName, cn, uidNumber, gidNumber, member
attr = givenName, homeDirectory, sn, loginShell, memberOf, dn, o, uid, objectclass, cn, displayName, cn, uidNumber, gidNumber, memberUid
#ldap filter
filter = (cn=*)

[LDAPServer]
Host = 127.0.0.1
Port = 636
UseTLS = true
InsecureSkipVerify = false
CRTValidFor = ldapserver.example.com
CRTPath = /etc/ldap/sasl2/server.crt
#Page LDAP result
Page = 500
#LDAP Connection Timeout in seconds (Defaults to 10)
ConnTimeOut = 10
username = cn=SomeUser1,dc=example,dc=com
password = somepassword2
basedn = ou=SomeOU,dc=example,dc=com
attr = givenName, homeDirectory, sn, loginShell, memberOf, dn, o, uid, objectclass, cn, displayName, cn, uidNumber, gidNumber, memberUid
filter = (cn=*)


[Replace]
userObjectClass = posixAccount,top,inetOrgPerson
groupObjectClass = top,posixGroup
[Map]


[Sync]
#Add sleep time after each successful sync, in seconds.
sleepTime = 60
# loglevel can be set to either of
#   ErrorLevel = iota // 0
#   WarnLevel // 1
#   InfoLevel // 2
#   DebugLevel // 3
# Uncomment the below line and set to desired value. Defaults to DebugLevel.
# loglevel = DebugLevel

We'd probably need to create index for the frequently accessed attributes in ldap. A sample ldif file with a few of the attributes can be found in the ldif directory. Run the query

ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f addindex.ldif

Monitoring

A sample python3 monitoring module and script can be found here. The approach was to seek to the end of the log file, reads backwards until it finds another newline character(doing this because of the huge log files this an generate), and from the captured line, takes the timestamp and evaluates it with the current system time, do the math with the warning and critical thresholds that the class Monitor accepts, and exits with relevent exit code suitable for nagios. An example of using the module can be found here.