When you enter the search term ‘LDAP’ on the forge you get a whole load of modules that so something with LDAP. Most of these modules alow you to install and LDAP client or LDAP server. Some of these modules even allow you to do some management of entries inside of the LDAP server, but none of these solutions provide the whole spectrum of operations needed to manage LDAP in a large organization.

What are the requirements

Before we introduce our Puppet types ldap_server and ldap_principal, Let’s first zoom in at the requirements of LDAP management in large organisations.

Manage attributes

The most obvious thing is: You need to manage attributes. the attributes property allows you to do this. Here is an example:

ldap_principal { 'docker:cn=gonzo,ou=muppetshow,dc=example,dc=org':
  ensure     => 'present',
  attributes => {
    'sn'           => 'gonzo',
    'objectclass'  => ['top', 'inetOrgPerson'],
    'givenName'    => 'Gonzo',
  },
}

Manage group memberships

Large organizations go beyond just adding and removing entries in a directory. Obviously the need the most basic feature of adding entries to a group (e.g. the MemberOf relation). And they need to do this in a way where you can add and remove certain memberships without touching other memberships. That is because the responsibility of the membership attributes of a user in most companies is distributed to different parts of the organization.

The head of the finance department, for example, decides who gets to have a membership to the group seeFinancialReports, while the IT department decides. who gets a membership to the group manageSystems.

Here is an example:

ldap_principal { 'docker:cn=muppets,ou=muppetshow,dc=example,dc=org':
  ensure     => 'present',
  attributes => {
    'objectclass'  => ['top', 'groupOfNames'],
  },
  present_in => {
    'member'       => [
      'cn=kermit,ou=muppetshow,dc=example,dc=org',
      'cn=piggy,ou=muppetshow,dc=example,dc=org',
      'cn=gonzo,ou=muppetshow,dc=example,dc=org',
    ],
  },
}

The ldap_principal type supports all these operations. Using the present_in property, you can specify which users must be present in a certain group. When you use this property, Puppet leaves all other group memberships as they are.

The reverse of this operation is the property absent_in. Like the word says, it makes sure the specified user is not available in a certain group.

ldap_principal { 'docker:cn=muppets,ou=muppetshow,dc=example,dc=org':
  ensure     => 'present',
  attributes => {
    'objectclass'  => ['top', 'groupOfNames'],
  },
  absent_in       => {
    'member'       => [
      'cn=kermit,ou=muppetshow,dc=example,dc=org',
      'cn=piggy,ou=muppetshow,dc=example,dc=org',
    ],
  },
  },
}

Manage only parts of the tree

Like I said, a responsibility of the LDAP principals is mostly shared across the organization. But you want to be sure your part of the LDAP tree contains only contains the ones you think are needed. Puppet has purge feature that allows you to remove resources that are not specfied in your manifest. But using this on LDAP, would also remove entries you don’t manage. So there needs to be a solution for purging just a container you manage.

ldap_principal has this feature. Setting the parameter purge to true on a certain LDAP container, means every entry not present in your manifest, will automatically be purged. This means your LDAP can remain clean and free of dangerous unwanted entries.

Here is an example:

ldap_principal { 'docker:ou=muppetshow,dc=example,dc=org':
  ensure     => 'absent',
  purge      => true,
}

But not only unknown entries can be dangerous, also unknown attributes can be a security hazard. To tackle this, ldap_principal has a feature called purge_attributes. When you set this to true, all attributes not specified in these LDAP entries, are removed. Thus making sure only attributes specified in your manifest are found in your part of the LDAP container.

Here is an example:

ldap_principal { 'docker:cn=fozzie,ou=muppetshow,dc=example,dc=org':
  ensure     => 'present',
  purge_attributes => true,
  attributes => {
    'objectclass'  => ['top', 'inetOrgPerson'],
    'userPassword' => "{SSHA512}2ZsyGTxVyEw14Cu9D/OXpTddfy/387D/rlR6R0VVdRIz+3Wn52fSYZpKAP1S\n9J/kRbkoBiPK/9eZMOZV6cgidzEyMzQ1Njc4",
    'givenName'    => 'Fozzie Bear',
    'cn'           => 'fozzie',
    'sn'           => 'Fozzie',
  },
}

Let the LDAP server encrypt

Some LDAP servers allow you to set the password value of an entry to a value that is encrypted before it is sent to the server. This is inherently unsafe. Therefore in most larger organization, the password encryption is done by the LDAP server. But because Puppet needs to manage encrypted attributes in an idempotent way, we need some way of control over the encrypted value.

The ldap_principal puppet type has support for transform property. Using this property, you can manage how puppet transforms specified user values before comparing it to the current state.

ldap_principal { 'docker:cn=gonzo,dc=example,dc=org':
  ensure            => 'present',
  attributes        => {
    'sn'            => 'gonzo',
    'objectclass'   => ["top", "inetorgperson"],
    'userPassword'  => 'mysecretpassword',
    'givenName'     => 'Gonzo',
  },
  transform => {'userPassword' => 'hashed'},
}

Do you need some or all of this?

If you need some or all of these requirements, check out the rest of the documentation for more details or go to the shop