[new-type] __openldap_server: first public version.

This already takes care of setting up the base DN and managing it as well as
allowing for settings for the listener URLS.

The type was also made a singleton as it doesn't make much sense to setup
multiple LDAP servers on the same machine.
This commit is contained in:
evilham 2019-12-10 12:49:07 +01:00
parent 42914d26c5
commit 22c5cd550b
9 changed files with 176 additions and 50 deletions

View File

@ -0,0 +1,44 @@
#!/bin/sh
manager_dn=$(cat "${__object}/parameter/manager-dn")
manager_password=$(cat "${__object}/parameter/manager-password")
description=$(cat "${__object}/parameter/description")
suffix=$(cat "${__object}/parameter/suffix")
suffix_dc=$(echo -n ${suffix} | awk -F',' '{print $1}' | awk -F'=' '{print $2}')
SLAPD_IPC=$(cat "${__object}/parameter/slapd-url" | tr '\n' ' ' | awk '{ print $1}')
cat <<DONE # | tee /dev/stderr
# Restart service
service slapd restart
# It can sometimes take a tiny bit to bind
sleep 1
# Create or update base object
if ldapsearch -xZ -D "${manager_dn}" -w "${manager_password}" -H '${SLAPD_IPC}' -b '${suffix}' -s base 2>&1 > /dev/null; then
# Already exists, use ldapmodify
ldapmodify -xZ -D "${manager_dn}" -w "${manager_password}" -H '${SLAPD_IPC}' <<EOF
dn: ${suffix}
changetype: modify
replace: objectClass
objectClass: top
objectClass: dcObject
objectClass: organization
-
replace: o
o: ${description}
-
replace: dc
dc: ${suffix_dc}
EOF
else
# Does not exist, use ldapadd
ldapadd -xZ -D "${manager_dn}" -w "${manager_password}" -H '${SLAPD_IPC}' <<EOF
dn: ${suffix}
objectClass: top
objectClass: dcObject
objectClass: organization
o: ${description}
dc: ${suffix_dc}
EOF
fi
DONE

View File

@ -10,6 +10,9 @@ DESCRIPTION
-----------
This type can be used to bootstrap an LDAP environment using openldap as slapd.
It bootstraps the LDAP server with sane defaults and creates and manages the
base DN defined by `suffix`.
REQUIRED PARAMETERS
-------------------
@ -17,14 +20,19 @@ manager-dn
The rootdn to set up in the directory.
E.g. `cn=manager,dc=ungleich,dc=ch`. See `slapd.conf(5)`.
manager-password
The password for `manager-dn` in the directory.
This will be used to connect to the LDAP server on the first `slapd-url`
with the given `manager-dn`.
manager-password-hash
The password for `manager-dn` in the directory.
This should be valid for `slapd.conf` like `{SSHA}qV+mCs3u8Q2sCmUXT4Ybw7MebHTASMyr`.
Generate e.g. with: `slappasswd -s weneedgoodsecurity`.
See `slappasswd(8C)`, `slapd.conf(5)`.
TODO: implement this: http://blog.adamsbros.org/2015/06/09/openldap-ssha-salted-hashes-by-hand/
to allow for a manager-password parameter and ensure idempotency (care with salts).
Such manager-password parameter should be mutually exclusive with this one.
to derive from the manager-password parameter and ensure idempotency (care with salts).
At that point, manager-password-hash should be deprecated and ignored.
serverid
The server for the directory.
@ -35,6 +43,17 @@ suffix
E.g. `dc=ungleich,dc=ch`. See `slapd.conf(5)`.
REQUIRED MULTIPLE PARAMETERS
----------------------------
slapd-url
A URL for slapd to listen on.
Pass once for each URL you want to support,
e.g.: `--slapd-url ldaps://my.fqdn/ --slapd-url ldap://my.fqdn/`.
The first instance that is passed will be used as the main URL to
connect to this LDAP server
See the `-h` flag in `slapd(8C)`.
OPTIONAL PARAMETERS
-------------------
syncrepl-credentials
@ -53,6 +72,11 @@ admin-email
Required if using `__letsencrypt_cert`.
Where to send Let's Encrypt emails like "certificate needs renewal".
tls-cipher-suite
Setting for TLSCipherSuite.
Defaults to `NORMAL` in a Debian-like OS and `HIGH:MEDIUM:+SSLv2` on FreeBSD.
See `slapd.conf(5)`.
tls-cert
If defined, `__letsencrypt_cert` is not used and this must be the path in
the remote hosts to the PEM-encoded TLS certificate.
@ -87,6 +111,11 @@ schema
The type user must ensure that the schema file is deployed.
This defaults to a sensible subset, for details see the type definition.
description
The description of the base DN passed in the `suffix` parameter.
Defaults to `Managed by cdist, do not edit manually.`
BOOLEAN PARAMETERS
------------------
staging
@ -97,48 +126,71 @@ replicate
Whether to setup replication or not.
If present `syncrepl-credentials` and `syncrepl-host` are also required.
EXAMPLES
--------
.. code-block:: sh
# Modify the ruleset on $__target_host:
__pf_ruleset --state present --source /my/pf/ruleset.conf
require="__pf_ruleset" \
__pf_apply
# Example of a simple server with manual certificate management.
pki_prefix="/usr/local/etc/pki/realms/ldap.camilion.cloud" \
__openldap_server \
--manager-dn 'cn=manager,dc=camilion,dc=cloud' \
--manager-password "foo" \
--manager-password-hash '{SSHA}foo' \
--serverid 0 \
--suffix 'dc=camilion,dc=cloud' \
--slapd-url 'ldaps://ldap.camilion.cloud' \
--tls-cert '${pki_prefix}/default.crt' \
--tls-privkey '${pki_prefix}/default.key' \
--tls-ca '${pki_prefix}/CA.crt'
# Remove the ruleset on $__target_host (implies disabling pf(4):
__pf_ruleset --state absent
require="__pf_ruleset" \
__pf_apply
root@ldap-for-guacamole:~# cat ldapbase.ldif
dn: dc=guaca-test,dc=ungleich,dc=ch
objectClass: top
objectClass: dcObject
objectClass: organization
o: Some description
dc: guaca-test
# Sample usage:
# The created basedn looks as follows:
#
# id=1
# for host in ldap-test1.ungleich.ch ldap-test2.ungleich.ch; do
# echo "__ungleich_ldap ${host} \
# --manager-dn 'cn=manager,dc=ungleich,dc=ch' \
# --manager-password '{SSHA}fooo' \
# --serverid '${id}' \
# --staging \
# --suffix 'dc=ungleich,dc=ch' \
# --searchbase 'dc=ungleich,dc=ch' \
# --syncrepl-credentials 'fooo' \
# --syncrepl-host 'ldap-test1.ungleich.ch' \
# --syncrepl-host 'ldap-test2.ungleich.ch' \
# --descriptiont 'Ungleich LDAP server'" \
# | cdist config -i - -v ${host}
# id=$((id + 1))
# done
# dn: dc=camilion,dc=cloud
# objectClass: top
# objectClass: dcObject
# objectClass: organization
# o: Managed by cdist, do not edit manually.
# dc: camilion
#
# Do not change it manually, the type will overwrite your changes.
#
# Changing to a replicated setup is a simple change to something like:
#
# Example for multiple servers with replication and automatic
# Let's Encrypt certificate management through certbot.
id=1
for host in ldap-test1.ungleich.ch ldap-test2.ungleich.ch; do
echo "__ungleich_ldap \
--manager-dn 'cn=manager,dc=ungleich,dc=ch' \
--manager-psasword 'foo' \
--manager-password-hash '{SSHA}fooo' \
--serverid '${id}' \
--suffix 'dc=ungleich,dc=ch' \
--slapd-url ldap://${host} \
--searchbase 'dc=ungleich,dc=ch' \
--syncrepl-credentials 'fooo' \
--syncrepl-host 'ldap-test1.ungleich.ch' \
--syncrepl-host 'ldap-test2.ungleich.ch' \
--description 'Ungleich LDAP server'" \
--staging \
| cdist config -i - -v ${host}
id=$((id + 1))
done
# The created basedn looks as follows:
#
# dn: dc=ungleich,dc=ch
# objectClass: top
# objectClass: dcObject
# objectClass: organization
# o: Ungleich LDAP server
# dc: ungleich
#
# Do not change it manually, the type will overwrite your changes.
SEE ALSO

View File

@ -5,13 +5,17 @@ manager_dn=$(cat "${__object}/parameter/manager-dn")
manager_password_hash=$(cat "${__object}/parameter/manager-password-hash")
serverid=$(cat "${__object}/parameter/serverid")
suffix=$(cat "${__object}/parameter/suffix")
slapd_modules=$(cat "${__object}/parameter/module" || true)
slapd_modules=$(cat "${__object}/parameter/module" 2>/dev/null || true)
schemas=$(cat "${__object}/parameter/schema")
slapd_urls=$(cat "${__object}/parameter/slapd-url" | tr '\n' ' ')
tls_cipher_suite=$(cat "${__object}/parameter/tls-cipher-suite" 2>/dev/null || true)
os="$(cat "${__global}/explorer/os")"
# Setup OS-dependent vars
CONF_OWNER="root"
CONF_GROUP="root"
case "${os}" in
freebsd)
PKGS="openldap-server"
@ -24,6 +28,12 @@ case "${os}" in
# It looks like ppolicy and syncprov must be compiled
slapd_modules="back_mdb back_monitor"
fi
CONF_OWNER="ldap"
CONF_GROUP="ldap"
if [ -z "${tls_cipher_suite}" ]; then
# TODO: research default for FreeBSD. 'NORMAL' appears to not work
tls_cipher_suite="HIGH:MEDIUM:+SSLv2"
fi
;;
debian|ubuntu|devuan)
PKGS="slapd ldap-utils"
@ -35,6 +45,9 @@ case "${os}" in
if [ -z "${slapd_modules}" ]; then
slapd_modules="back_mdb ppolicy syncprov back_monitor"
fi
if [ -z "${tls_cipher_suite}" ]; then
tls_cipher_suite="NORMAL"
fi
;;
*)
echo "Don't know the openldap defaults for: $os" >&2
@ -42,6 +55,8 @@ case "${os}" in
;;
esac
PKG_MAIN=$(echo ${PKGS} | awk '{print $1;}')
# Determine if __letsencrypt_cert is to be used and setup vars accordingly
if [ -f "${__object}/parameter/tls-cert" ]; then
@ -106,17 +121,26 @@ for pkg in ${PKGS}; do
done
# TODO: Implement __start_on_boot for BSD
require="__package/slapd" __start_on_boot slapd
require="__package/${PKG_MAIN}" __start_on_boot slapd
# Setup -h flag for the listeners. See man slapd (-h flag).
case "${os}" in
freebsd)
require="__package/${PKG_MAIN}" __key_value \
--file "/etc/rc.conf" \
--key "slapd_flags" \
--value "\"-h '${slapd_urls}'\"" \
--delimiter "=" \
--comment "# LDAP Listener URLs" \
"${__target_host}__slapd_flags"
;;
debian|ubuntu|devuan)
require="__package/slapd" __line rm_slapd_conf \
require="__package/${PKG_MAIN}" __line rm_slapd_conf \
--file ${ETC}/default/slapd \
--regex 'SLAPD_CONF=.*' \
--state absent
require="__package/slapd" __line rm_slapd_services \
require="__package/${PKG_MAIN}" __line rm_slapd_services \
--file ${ETC}/default/slapd \
--regex 'SLAPD_SERVICES=.*' \
--state absent
@ -128,7 +152,7 @@ case "${os}" in
require="__line/rm_slapd_services" __line add_slapd_services \
--file ${ETC}/default/slapd \
--line "SLAPD_SERVICES=\"ldap://localhost/ ldap://${name}/\"" \
--line "SLAPD_SERVICES=\"${slapd_urls}\"" \
--state present
;;
*)
@ -149,15 +173,15 @@ if [ -z "${_skip_letsencrypt_cert}" ]; then
--automatic-renewal ${staging}
fi
require="__package/slapd" __directory ${SLAPD_DIR}/slapd.d --state absent
require="__package/${PKG_MAIN}" __directory ${SLAPD_DIR}/slapd.d --state absent
if [ -z "${_skip_letsencrypt_cert}" ]; then
require="__package/slapd __letsencrypt_cert/${name}" \
__file ${SLAPD_DIR}/slapd.conf --owner root --group root --mode 644 \
require="__package/${PKG_MAIN} __letsencrypt_cert/${name}" \
__file ${SLAPD_DIR}/slapd.conf --owner ${CONF_OWNER} --group ${CONF_GROUP} --mode 644 \
--source "${ldapconf}"
else
require="__package/slapd" \
__file ${SLAPD_DIR}/slapd.conf --owner root --group root --mode 644 \
require="__package/${PKG_MAIN}" \
__file ${SLAPD_DIR}/slapd.conf --owner ${CONF_OWNER} --group ${CONF_GROUP} --mode 644 \
--source "${ldapconf}"
fi
@ -166,7 +190,7 @@ cat << EOF > "${ldapconf}"
pidfile ${SLAPD_RUN_DIR}/slapd.pid
argsfile ${SLAPD_RUN_DIR}/slapd.args
TLSCipherSuite NORMAL
TLSCipherSuite ${tls_cipher_suite}
TLSCertificateFile ${tls_cert}
TLSCertificateKeyFile ${tls_privkey}
TLSCACertificateFile ${tls_ca}

View File

@ -0,0 +1 @@
Managed by cdist, do not edit manually.

View File

@ -1,6 +1,8 @@
description
syncrepl-credentials
syncrepl-searchbase
admin-email
tls-cipher-suite
tls-cert
tls-privkey
tls-ca
tls-ca

View File

@ -1,2 +1,3 @@
syncrepl-host
module
schema

View File

@ -1,4 +1,5 @@
manager-dn
manager-password
manager-password-hash
serverid
suffix

View File

@ -0,0 +1 @@
slapd-url