I'm attempting to rebuild nwaller's sssd puppet module to be entirely LDAP based and to be a little cleaner. In it we have a resource defined for each authentication domain of the form
define sssd::domain (
$domain = $name,
$domain_description = '',
$domain_type,
$ldap_uri = 'ldap://example.com',
$ldap_search_base = 'dc=example,dc=com',
$simple_allow_groups,
....
)
This definition is then passed as a concat::fragment
which fills out a template for building the final sssd.conf
.
This all works great if I define the LDAP server within each node, as in:
nodes.pp
node "node1.systems.private" {
include "puppet::client"
class {
'sssd':
domains => [ 'LDAP' ],
make_home_dir => true;
}
sssd::domain { 'LDAP':
domain_type => 'ldap',
ldap_uri => 'ldaps://ldap.site.com:636',
ldap_search_base => 'DC=site,DC=com',
ldap_user_search_base => 'OU=People,DC=site,DC=com',
ldap_group_search_base => 'OU=Groups,DC=site,DC=com',
ldap_default_bind_dn => 'CN=bindaccount,OU=Service Accounts,OU=People,DC=site,DC=com',
ldap_default_authtok => 'soopersekretbindpw',
simple_allow_groups => ['SysAdmins','AppAdmins'],
}
}
What I would rather do is a much more hierarchical setup. Keep the sssd::domain
definition as generic as possible, so I can maintain it as a module independent of our organization configurations. Define the LDAP server in a global config, and then within each node define which specific groups need access. So something more like:
modules/org/manifests/default.pp
class org::default {
include "puppet::client"
class {
'sssd':
domains => [ 'LDAP' ],
make_home_dir => true;
}
sssd::domain { 'LDAP':
domain_type => 'ldap',
ldap_uri => 'ldaps://ldap.site.com:636',
ldap_search_base => 'DC=site,DC=com',
ldap_user_search_base => 'OU=People,DC=site,DC=com',
ldap_group_search_base => 'OU=Groups,DC=site,DC=com',
ldap_default_bind_dn => 'CN=bindaccount,OU=Service Accounts,OU=People,DC=site,DC=com',
ldap_default_authtok => 'soopersekretbindpw',
}
}
nodes.pp
node "node1.systems.private" {
include "org::default"
sssd::domain { 'LDAP':
simple_allow_groups => ['SysAdmins','AppAdmins'],
}
}
As expected this results in a duplicate declaration error when attempting to apply the definition. Is there a way to do this, selectively override parameters, or am I stuck with defining the authentication domain within the original definition and then overriding the authorization parameters within each node?
I would use Hiera.
Hiera lets you decouple your variable data from your Puppet manifests.
Hiera, as the name implies, is hierarchical, allowing for some interesting ways to override, as well as combine, variable data.
First, modify your sssd:: domain declaration to perform Hiera lookups for the parameters:
In the code above, I've defined default values for each of the lookups. You could exclude those, if you like, by sticking the defaults in your most-generic Hiera data file (typically "common.yaml" or "common.json"):
common.yaml:
For the bits you want to personalize on a per-host basis, you'd create a YAML or JSON file named after the FQDN of the host in question, and put the necessary values in there.
node1.systems.private.yaml:
In this example, note that
ldap_simple_allow_groups
is using thehiera_array
lookup function. This will concatenate ALL the valid founds in the hierarchy. As such, node1 will get the values defined in common.yaml as well as the "SomeOtherGroup" defined in its own YAML file.Read the Hiera lookup types documentation for more details.
While Hiera is the best way and is duely accepted, I'd like to add for completeness' sake: There is a syntax to do just this override you had in mind:
Note that this syntax also serves to collect virtual resources, but may well be used to override resource parameters.
Obviously, this technique will lead to chaos if used consequently, so again - Hiera is superior in most cases.