GithubHelp home page GithubHelp logo

nohupped / adtoldap Goto Github PK

View Code? Open in Web Editor NEW
72.0 5.0 17.0 108 KB

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

License: MIT License

Go 74.58% C 16.15% Python 9.26%
sync tls ldap openldap active-directory daemon replication go golang python python3 c

adtoldap's Introduction

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

  • Get the pem file from the AD server

    From the windows server cmd, do

    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.

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.

adtoldap's People

Contributors

nohupped avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

adtoldap's Issues

If settings do not exist in the config file, the program bails

I am not using tls/ssl to talk to the source AD server. Aka, I am talking on port 389. As such, I have commented out UseTLS, etc. The program then says those values don't exist.

So, I then place UseTLS=false back into the config. I then get an error about CRTPath not being readable(I copied the example from the README). So I try to disable that option too, etc.

I can work around the CRTPath by setting it to /dev/null. But it'd be nice if the program was more forgiving on missing options(I don't need any of the certification/ssl stuff in my environment, all communication is sent over a secure tunnel).

Requires config file to be owned by root

12:19:53 -0500 adam@tooz:/srv/development/openldap$ sudo /srv/development/go/bin/ADtoLDAP -configfile test.ini
test.ini not owned by root. Make it owned by root, and make it non-readable to groups and others.

Please note, that test.ini exists in the current folder. I have to use sudo because of the previous requirement to access /var/log/ldapsync.log.

This program does not need to run as root, so shouldn't be forcing root ownership.

If /etc/ldapsync.ini does not exist, gives wrong permission to broad warning

12:10:40 -0500 adam@tooz:/srv/development/openldap$ sudo /srv/development/go/bin/ADtoLDAP
[sudo] password for adam:
/etc/ldapsync.ini file permission too broad, make it non-readable to groups and others.
12:14:14 -0500 adam@tooz:/srv/development/openldap$ ls /etc/ldapsync.ini
ls: cannot access /etc/ldapsync.ini: No such file or directory

Not able to `go get`

Hi There,

I am facing some trouble during installation. Could you please guide me what I might be doing wrong here?

❯ go get -f -u -v github.com/nohupped/ADtoLDAP

github.com/nohupped/ADtoLDAP (download)
github.com/nohupped/glog (download)
gopkg.in/ini.v1 (download)
gopkg.in/ldap.v2 (download)
gopkg.in/asn1-ber.v1 (download)
github.com/nohupped/ADtoLDAP/gosyncmodules
# github.com/nohupped/ADtoLDAP/gosyncmodules
src/github.com/nohupped/ADtoLDAP/gosyncmodules/logger.go:29:20: cannot use glog.DebugLevel (type uint) as type *uint in argument to logger.SetLogLevel
src/github.com/nohupped/ADtoLDAP/gosyncmodules/logger.go:36:21: cannot use glog.ErrorLevel (type uint) as type *uint in argument to logger.SetLogLevel
src/github.com/nohupped/ADtoLDAP/gosyncmodules/logger.go:39:21: cannot use glog.WarnLevel (type uint) as type *uint in argument to logger.SetLogLevel
src/github.com/nohupped/ADtoLDAP/gosyncmodules/logger.go:42:21: cannot use glog.InfoLevel (type uint) as type *uint in argument to logger.SetLogLevel
src/github.com/nohupped/ADtoLDAP/gosyncmodules/logger.go:45:21: cannot use glog.DebugLevel (type uint) as type *uint in argument to logger.SetLogLevel

Thanks

Remap basedn

Is it possible to remap the basedn for eg: if we're syncing from basedn = ou=someOu,dc=ad-example,dc=com and sync to basedn = ou=someOu,dc=ldap-example,dc=com ?

Error while running ./ADtoLDAP

Hi,

I am running into an issue when I trying to run ./ADtoLDAP. I made sure the base schema of my AD is the same as the base schema of my LDAP instance.

main.go:104: DEBUG: Add : &{cn=Users,dc=myorg,dc=local [{objectClass [top container]} {cn [Users]}]}
main.go:107: ERROR: LDAP Result Code 21 "Invalid Attribute Syntax": objectClass: value #1 invalid per syntax
main.go:104: DEBUG: Add : &{cn=Computers,dc=myorg,dc=local [{objectClass [top container]} {cn [Computers]}]}
main.go:107: ERROR: LDAP Result Code 21 "Invalid Attribute Syntax": objectClass: value #1 invalid per syntax
main.go:104: DEBUG: Add : &{cn=System,dc=myorg,dc=local [{objectClass [top container]} {cn [System]}]}
main.go:107: ERROR: LDAP Result Code 21 "Invalid Attribute Syntax": objectClass: value #1 invalid per syntax
main.go:104: DEBUG: Add : &{cn=LostAndFound,dc=myorg,dc=local [{objectClass [top lostAndFound]} {cn [LostAndFound]}]}
main.go:107: ERROR: LDAP Result Code 21 "Invalid Attribute Syntax": objectClass: value #1 invalid per syntax
main.go:123: DEBUG: Done from func FindDels
main.go:104: DEBUG: Add : &{cn=Infrastructure,dc=myorg,dc=local [{objectClass [top infrastructureUpdate]} {cn [Infrastructure]}]}
main.go:107: ERROR: LDAP Result Code 21 "Invalid Attribute Syntax": objectClass: value #1 invalid per syntax

Could you please help me what could be wrong?

Thanks

Requires root-level access to run

This is because the log file is hard-coded to /var/log/ldapsync.log. Further complicated because the logging is started before the command line is parsed, and before the config file is loaded.

Nothing about this program requires root level access. Just a config file to read, and 2 remote servers to talk to.

./main.go:56:3: undefined: gosyncmodules.CheckPerm

build failures

➜  ADtoLDAP git:(master) $ GOOS=linux GOARCH=amd64 go build .
./main.go:56:3: undefined: gosyncmodules.CheckPerm

go version:
go version go1.11.4 darwin/amd64

ADtoLDAP version is master

Module path should be "github.com/nohupped/ADtoLDAP", not "ADtoLDAP"

Background

Module path is inconsistent with go import path.
GO111MODULE=on, run go get github.com/nohupped/ADtoLDAP:

go: downloading github.com/nohupped/ADtoLDAP v0.0.0-20200426135055-207bf29e0c6b
go: github.com/nohupped/ADtoLDAP upgrade => v0.0.0-20200426135055-207bf29e0c6b
go get: github.com/nohupped/[email protected]: parsing go.mod:
        module declares its path as: ADtoLDAP
                but was required as: github.com/nohupped/ADtoLDAP 

Solution

Fix the module path:

  1. Rename the module path to "github.com/nohupped/ADtoLDAP": https://github.com/nohupped/ADtoLDAP/blob/master/go.mod#L1 :
module github.com/nohupped/ADtoLDAP
go 1.13
require (
	…
) 
  1. Warning the users not to use the module, get "github.com/nohupped/ADtoLDAP" in GOPATH mode.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.