Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/nohupped/ADtoLDAP

A light weight Active Directory to OpenLDAP, or OpenLDAP to OpenLDAP Synchronization Connector written in Golang.
https://github.com/nohupped/ADtoLDAP

active-directory c daemon go golang ldap openldap python python3 replication sync tls

Last synced: 2 months ago
JSON representation

A light weight Active Directory to OpenLDAP, or OpenLDAP to OpenLDAP Synchronization Connector written in Golang.

Awesome Lists containing this project

README

        

# 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

```txt
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

```bash
tcpdump -v -XX
```

## Requirements to set up TLS connection

* Get the pem file from the AD server

From the windows server cmd, do

```cmd
certutil -ca.cert ca_name.cer > ca.crt
```

This will generate the pem file, and will be saved in the working directory by the name ca.crt.
This pem file must be copied over from the master/AD server to the slave/openldap server, and the path to this file must be mentioned in the ldapsync.ini file to create a custom cert pool and use it as the Root CAs, so the DialTLS wouldn't panic with a `certificate signed by unknown authority` error.

## How to install

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

```bash
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

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

The program can be daemonized as

```bash
/daemonizer /ADtoLDAP
```

The Daemoniser was written as a part of learning. Use a [Systemd Unit file](http://man7.org/linux/man-pages/man5/systemd.unit.5.html) 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](ldifs/) in this repo.

```bash
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

```bash
./ADtoLDAP -showSampleConfig
```

Output:

```ini
### Sample config generated by the program. Edit accordingly ###
[ADServer]
Host =
#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 =
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:

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

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

`--logfile=` will write to that log file. Defaults to `/var/log/ldapsync.log`.

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

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

```ini
[ADServer]
Host =
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](ldifs/). Run the query

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

## Monitoring

A sample python3 monitoring module and script can be found [here](LdapSyncMonitor/SyncMonitor). 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](LdapSyncMonitor/monitorDaemon.py).