We’re going to use Puppet to configure a pair of OpenLDAP servers with a master-slave replication.
This article is part of the Homelab Project with KVM, Katello and Puppet series.
Homelab
We have two CentOS 7 servers installed which we want to configure as follows:
ldap1.hl.local (10.11.1.11) – will be configured as an LDAP master
ldap2.hl.local (10.11.1.12) – will be configured as an LDAP slave
Both servers have SELinux set to enforcing mode.
See the image below to identify the homelab part this article applies to.
Configuration with Puppet
Puppet master runs on the Katello server. We use camptocamp-openldap Puppet module to configure OpenLDAP. Please see the module documentation for features supported and configuration options available.
See here (CentOS 7) and here (Debian) for blog posts on how to configure an OpenLDAP server manually.
Note that instructions below apply to both LDAP servers.
Firewall configuration to allow LDAPS access from homelab LAN:
firewall { '007 allow LDAPS': dport => [636], source => '10.11.1.0/24', proto => tcp, action => accept, }
Ensure that the private key (which we created previously) in the PKCS#8 format is available.
file {'/etc/pki/tls/private/hl.pem': ensure => file, source => 'puppet:///homelab_files/hl.pem', owner => '0', group => 'ldap', mode => '0640', }
Configure the LDAP server (note how we bind to the SSL port):
class { 'openldap::server': ldap_ifs => ['127.0.0.1:389/'], ldaps_ifs => ['0.0.0.0:636/'], ssl_cert => '/etc/pki/tls/certs/hl.crt', ssl_key => '/etc/pki/tls/private/hl.pem', }
Configure the database:
openldap::server::database { 'dc=top':
ensure => present,
directory => '/var/lib/ldap',
suffix => 'dc=top',
rootdn => 'cn=admin,dc=top',
rootpw => '{SSHA}cGfSAyREZC5XnJa77iP+EdR8BrvZfUuo',
}
Configure schemas:
openldap::server::schema { 'cosine': ensure => present, path => '/etc/openldap/schema/cosine.schema', } openldap::server::schema { 'inetorgperson': ensure => present, path => '/etc/openldap/schema/inetorgperson.schema', require => Openldap::Server::Schema["cosine"], } openldap::server::schema { 'nis': ensure => present, path => '/etc/openldap/schema/nis.ldif', require => Openldap::Server::Schema["inetorgperson"], }
Configure ACLs:
$homelab_acl = { '0 to attrs=userPassword,shadowLastChange' => [ 'by dn="cn=admin,dc=top" write', 'by dn="cn=reader,dc=top" read', 'by self write', 'by anonymous auth', 'by * none', ], '1 to dn.base=""' => [ 'by * read', ], '2 to *' => [ 'by dn="cn=admin,dc=top" write', 'by dn="cn=reader,dc=top" read', 'by self write', 'by users read', 'by anonymous auth', 'by * none', ], } openldap::server::access_wrapper { 'dc=top' : acl => $homelab_acl, }
Base configuration:
file { '/root/.ldap_config.ldif': ensure => file, source => 'puppet:///homelab_files/ldap_config.ldif', owner => '0', group => '0', mode => '0600', notify => Exec['configure_ldap'], } exec { 'configure_ldap': command => 'ldapadd -c -x -D cn=admin,dc=top -w PleaseChangeMe -f /root/.ldap_config.ldif && touch /root/.ldap_config.done', path => '/usr/bin:/usr/sbin:/bin:/sbin', provider => shell, onlyif => ['test -f /root/.ldap_config.ldif'], unless => ['test -f /root/.ldap_config.done'], }
Content of the file ldap_config.ldif
can be seen below.
We create a read-only account cn=reader,dc=top
for LDAP replication, we also create an LDAP user uid=tomas,ou=Users,dc=hl.local,dc=top
to log into homelab servers.
dn: cn=reader,dc=top objectClass: simpleSecurityObject objectclass: organizationalRole description: LDAP Read-only Access userPassword: {SSHA}NrBn6Kd4rW8jmf+KWmfbTMFOkcC43ctF dn: dc=hl.local,dc=top o: hl.local dc: hl.local objectClass: dcObject objectClass: organization dn: ou=Users,dc=hl.local,dc=top objectClass: organizationalUnit ou: Users dn: uid=tomas,ou=Users,dc=hl.local,dc=top uid: tomas uidNumber: 5001 gidNumber: 5001 objectClass: top objectClass: person objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount userPassword: {SSHA}aBLnLxAUZAqwwII6fNUzizyOY/YAowtt cn: Tomas gn: Tomas sn: Admin mail: [email protected] shadowLastChange: 16890 shadowMin: 0 shadowMax: 99999 shadowWarning: 14 shadowInactive: 3 loginShell: /bin/bash homeDirectory: /home/guests/tomas dn: ou=Groups,dc=hl.local,dc=top objectClass: organizationalUnit ou: Groups dn: cn=tomas,ou=Groups,dc=hl.local,dc=top gidNumber: 5001 objectClass: top objectClass: posixGroup cn: tomas
LDAP Master Server
Configure sync provider on the master node:
file { '/root/.ldap_syncprov.ldif': ensure => file, source => 'puppet:///homelab_files/ldap_syncprov.ldif', owner => '0', group => '0', mode => '0600', notify => Exec['configure_syncprov'], } exec { 'configure_syncprov': command => 'ldapadd -c -Y EXTERNAL -H ldapi:/// -f /root/.ldap_syncprov.ldif && touch /root/.ldap_syncprov.done && systemctl restart slapd', path => '/usr/bin:/usr/sbin:/bin:/sbin', provider => shell, onlyif => [ 'test -f /root/.ldap_syncprov.ldif', 'test -f /root/.ldap_config.done' ], unless => ['test -f /root/.ldap_syncprov.done'], }
Content of the file ldap_syncprov.ldif
for the master server can be seen below.
dn: cn=module,cn=config objectClass: olcModuleList cn: module olcModulePath: /usr/lib64/openldap olcModuleLoad: syncprov.la dn: olcOverlay=syncprov,olcDatabase={2}hdb,cn=config objectClass: olcOverlayConfig objectClass: olcSyncProvConfig olcOverlay: syncprov olcSpSessionLog: 100
LDAP Slave Server
Configure replication on the slave node:
file { '/root/.ldap_replication.ldif': ensure => file, source => 'puppet:///homelab_files/ldap_replication.ldif', owner => '0', group => '0', mode => '0600', notify => Exec['configure_replication'], } exec { 'configure_replication': command => 'ldapadd -c -Y EXTERNAL -H ldapi:/// -f /root/.ldap_replication.ldif && touch /root/.ldap_replication.done && systemctl restart slapd', path => '/usr/bin:/usr/sbin:/bin:/sbin', provider => shell, onlyif => ['test -f /root/.ldap_config.done'], unless => ['test -f /root/.ldap_replication.done'], }
Content of the file ldap_replication.ldif
for the slave server is below. Note how we bind to the SSL port.
dn: olcDatabase={2}hdb,cn=config changetype: modify add: olcSyncRepl olcSyncRepl: rid=001 provider=ldaps://ldap1.hl.local:636/ searchbase="dc=hl.local,dc=top" type=refreshAndPersist retry="60 10 300 +" schemachecking=on bindmethod=simple binddn="cn=reader,dc=top" credentials=PleaseChangeMe tls_reqcert=never tls_cert=/etc/pki/tls/certs/hl.crt tls_cacert=/etc/pki/tls/certs/hl.crt tls_key=/etc/pki/tls/private/hl.pem
The Result
We should end up with the following LDAP structure:
Anything that gets created on the LDAP master should be automatically synced to the slave.
Debugging LDAP Issues
If you hit problems, try running the following to start the LDAP server in debug mode with logging to the console:
# slapd -h ldapi:/// -u ldap -d 255
The logs can be a difficult to parse, but with Google search and a bit of luck you should to be able to work out what is going on.
Configure All Homelab Servers to use LDAP Authentication
We use Puppet module sgnl05-sssd to configure SSSD.
Add the following to the main homelab environment manifest file /etc/puppetlabs/code/environments/homelab/manifests/site.pp
so that it gets applied to all servers.
Note how SSSD is configured to use both LDAP servers for redundancy.
class {'::sssd': ensure => 'present', config => { 'sssd' => { 'domains' => 'default', 'config_file_version' => 2, 'services' => ['nss', 'pam'], }, 'domain/default' => { 'id_provider' => 'ldap', 'auth_provider' => 'ldap', 'cache_credentials' => true, 'default_shell' => '/bin/bash', 'mkhomedir' => true, 'ldap_search_base' => 'dc=hl.local,dc=top', 'ldap_uri' => 'ldaps://ldap1.hl.local,ldaps://ldap2.hl.local', 'ldap_id_use_start_tls' => false, 'ldap_tls_reqcert' => 'never', 'ldap_default_bind_dn' => 'cn=reader,dc=top', 'ldap_default_authtok' => 'PleaseChangeMe', } } }
After Puppet applies the configuration above, we should be able to log into all homelab servers with the LDAP user.
Can you please update this and add more clear explanations?
For example how to config ldap nodes.
The article explains how to configure LDAP servers with Puppet.
Puppet code snippets are provided with some brief explanation on what they do. If you’re not familiar with Puppet, or if these don’t make any sense to you, then there are also two weblinks listed for how to configure LDAP manually (on CentOS and Debian).
indeed I’m not familiar with puppet and if you could explain the snippets would help me to understand how it works and how to do it.
Thanks
I think that the Puppet website is probably the best place for you to start. It explains what Puppet is, and most importantly, how it works. They also offer the Learning VM (I used it myself when I started with Puppet) which is the perfect resource for trying out Puppet without having to deploy it in your own environment.
Error: ‘ldapadd -c -x -D cn=admin,dc=top -w pass -f /root/.ldap_config.ldif && touch /root/.ldap_config.done’ returned 49 instead of one of [0]
Error: /Stage[main]/Main/Node[ldap1.hl.local]/Exec[configure_ldap]/returns: change from notrun to 0 failed: ‘ldapadd -c -x -D cn=admin,dc=top -w rolecs123 -f /root/.ldap_config.ldif && touch /root/.ldap_config.done’ returned 49 instead of one of [0]
Do you have any idea?
Thanks
Try the command manually, see if it works. If it does, then the problem is Puppet. If it doesn’t, then it’s LDAP related. Start the LDAP server in a debug mode, identify and fix the problem.
I suspect it’s nothing to do with Puppet but rather a misconfigured LDAP server.
Thanks for this great guide. I am setting up something similar in my home lab and trying to use puppet (and Katello) to set up the ldap server/clients. In you guide above, I cannot figure out what files you are editing with the following :
Firewall
Private key
LDAP server (bind to SSL)
Database config
Schema config
ACL config
Base config
Are you appending the *.pp files which come with the camptocamp-openldap, or simply creating your own *.pp files with just the text you provide above?
I am still new to puppet and doing some online training to better understand the classes syntax, just now sure how your configuration ties in with the configuration already provided in the openldap module.
Thanks for any help you can give.
Damien.
You’re welcome!
When you install a Puppet module (e.g. camptocamp-openldap), that module does nothing by default. You need to create your own manifest (a .pp file under
manifests/
) that will be used to apply configuration to a client node. I use various Puppet modules from Puppet Forge in my home lab, but I write my own manifests, classes and sometimes modules that I use to apply configuration to servers. I hope this answers your question.Thanks again, I guess the issue is knowing if you should edit the pp files which are part of the openldap module, or create your own that work alongside the default pp files. From your response, I am guessing you dont touch the default files and simply create your own?
The default files in the openldap(camptocamp) module are a follows:
client client.pp params.pp server server.pp utils.pp
[root@katello manifests]# cd server
[root@katello server]# ls
access.pp config.pp dbindex.pp install.pp module.pp schema.pp slapdconf.pp
access_wrapper.pp database.pp globalconf.pp iterate_access.pp overlay.pp service.pp
If you edit the files that come with the module, then you will need to somehow merge changes every time you update that module with the new version. For that reason I don’t modify them but write a separate manifest instead that meets my needs. I find it easier this way.
Hello,
Your homelab series is really great in Covid 19 pandemic, I know it is too late in 2020 however it would be much appreciated if you can help me little bit.
I have installed a module camptocamp/openldap in homelab environment and under manifest directory I have create a file called ldap.pp
“/etc/puppetlabs/code/environments/homelab/modules/openldap/manifests/ldap.pp” but it is not getting applied to ldap hosts I have also edit host from “All host and Puppet classes”
If I move this file ldap.pp to “/etc/puppetlabs/code/environments/homelab/manifests/” directory so it is applied to all hosts like ldaps ad zabbix.
so my questions is “where to keep ldap.pp file and how to exactly applied it to only ldap hosts.
Thanks in advance
Hello,
I have sorted it out, thank you!!!
Hello Lisenet,
Please help me on the below issue.
Error:
==> default: Notice: /Stage[main]/Openldap::Server::Install/Package[openldap-servers]/ensure: created
==> default: Notice: /Stage[main]/Openldap::Server::Config/Shellvar[slapd]/value: value changed [‘ldapi:/// ldap:///’] to ‘ldap:/// ldapi:/// ‘
==> default: Notice: /Stage[main]/Openldap::Server::Service/Service[slapd]/ensure: ensure changed ‘stopped’ to ‘running’
==> default: Notice: /Stage[main]/Openldap::Utils/Package[openldap-clients]/ensure: created
==> default: Error: LDIF content:
==> default: dn: cn=nis,cn=schema,cn=config
==> default: objectClass: olcSchemaConfig
==> default: cn: nis
==> default: Error message: Execution of ‘/bin/ldapadd -cQY EXTERNAL -H ldapi:/// -f /tmp/openldap_schemas_ldif20210802-15796-7okrw0’ returned 80: ldap_add: Other (e.g., implementation specific) error (80)
==> default: additional info: olcObjectClasses: AttributeType not found: “manager”
==> default: adding new entry “cn=nis,cn=schema,cn=config”
I guess because of the above error, getting the following error too.
==> default: Notice: /Stage[main]/Iwd-openldap/Openldap::Server::Schema[ifast]/Openldap_schema[ifast]: Dependency Openldap_schema[nis] has failures: true
Details:
OS: CentOS 7
Virtual Box: Oracle Virtual Box 6.0
Puppet Version: 3.8.7
Puppet module:
puppet module install puppetlabs/postgresql –version 4.7.1
puppet module install herculesteam-augeasproviders_core –version 2.2.0
puppet module install camptocamp/openldap –version 1.14.0
puppet module install puppetlabs/firewall –version 1.8.0
This script was written when we had Centos 6.x version:
init.pp :
class iwd-openldap {
class { ‘openldap::server’: }
openldap::server::schema { ‘cosine’:
ensure => present,
path => ‘/etc/openldap/schema/cosine.schema’
}
openldap::server::schema { ‘nis’:
ensure => present,
path => ‘/etc/openldap/schema/nis.schema’
}
openldap::server::schema { ‘ifast’:
ensure => present,
path => ‘/vagrant/puppet/modules/iwd-openldap/files/ifast-schema.schema’,
require => [ Openldap::Server::Schema[“cosine”], Openldap::Server::Schema[“nis”] ]
} -> exec { ‘insert ldap data’:
command => ‘/bin/sh /vagrant/puppet/modules/iwd-openldap/files/import-ldap.sh’
}
}
base.ldif:
version: 1
dn: cn=Manager,dc=ifdsgroup,dc=com
objectClass: organizationalRole
cn: Manager
dn: ou=ifastbase,dc=ifdsgroup,dc=com
objectClass: organizationalUnit
objectClass: top
ou: ifastbase
dn: ou=ifast,ou=ifastbase,dc=ifdsgroup,dc=com
objectClass: top
objectClass: organizationalUnit
ou: ifast
— some more entries will be present
Please help me to resolve this issue. I am struggling on this last two weeks. Let me know if you need any other details.
Thanks & Regards,
Raja Rajagopal
Hi, which step of the article are you following?
Hello Lisenet,
Thanks for the reply. However, I did not follow up any particular article. I had vagrant script (vagrant up command). When we had Cent OS 6, I ran the script, the script or vagrant up command will install all the necessary software’s. Howeever, now we moved to Cent OS 7 and I am running the same vagrant up command and getting that error. That’s the reason I had given all those details.
Note: The Cent OS 7 also gets installed through vagrant and we are using puppet to install all the softwares in that VM.
Thanks,
Raja Rajagopal
It sounds like you have a work assignment to migrate your LDAP server from CentOS 6 to CentOS 7. If you are having issues with CentOS 7, then you will have to make sure that your Puppet/LDAP/Vagrant code is compatible with the new OS. Grab the error message, put it into a search engine and see what results you get. Also check LDAP migration/compatibility guides.
Hello Lisenet,
Once again thanks for the reply. How will I come to know that the issue is with Cent OS 7 and how I can make sure that Puppet/LDAP/Vagrant code is compatible with new OS. When I ran vagrant up command it is creating the VM, but after that when it is trying to install puppet module (which I mentioned in my earlier post) it is giving issue. I searched with the error message, however I did not get anything. Sure I will check the guide too.
Please let me know if you need any other details I will provide.
Thanks,
Raja Rajagopal
You will have to check the code to understand what it does, line by line, and possibly run it in blocks to see if everything works, then move on to the next one. This should make troubleshooting easier.
Hello Lisenet,
Once again thanks for the reply. Yes.. It not migrate LDAP server from Cent OS 6 to Cent OS 7. Earlier we used Cent OS 6 in the VM and Windows 7. Now Cent OS 6 is out of scope and Windows 7 support is going to end. So, we moved to Cent OS 7 and running the same vagrant script.(vagrant up). Now it is giving error. I am not sure what puppet modules should I use for Cent OS 7. I searched the error in google and all, but did not get correct answer. That’s why I posted in your site.
Please let me know if you need any details.
Note: We did not change anything in the vagrant file except the box.
Thanks & Regards,
Raja Rajagopal
Putting the reason aside, the fact is that your code was originally written for an older version of the OS/software, and may therefore be incompatible with CentOS 7 and/or software versions that come with it. You’ll have to check the code, line by line, to understand what it does and which part is failing. Once you isolate the issue, you should check for differences (changelogs, upgrade notes) between software versions that the problem might be caused by.