[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. 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 REQUIRED PARAMETERS
------------------- -------------------
@ -17,14 +20,19 @@ manager-dn
The rootdn to set up in the directory. The rootdn to set up in the directory.
E.g. `cn=manager,dc=ungleich,dc=ch`. See `slapd.conf(5)`. 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 manager-password-hash
The password for `manager-dn` in the directory. The password for `manager-dn` in the directory.
This should be valid for `slapd.conf` like `{SSHA}qV+mCs3u8Q2sCmUXT4Ybw7MebHTASMyr`. This should be valid for `slapd.conf` like `{SSHA}qV+mCs3u8Q2sCmUXT4Ybw7MebHTASMyr`.
Generate e.g. with: `slappasswd -s weneedgoodsecurity`. Generate e.g. with: `slappasswd -s weneedgoodsecurity`.
See `slappasswd(8C)`, `slapd.conf(5)`. See `slappasswd(8C)`, `slapd.conf(5)`.
TODO: implement this: http://blog.adamsbros.org/2015/06/09/openldap-ssha-salted-hashes-by-hand/ 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). to derive from the manager-password parameter and ensure idempotency (care with salts).
Such manager-password parameter should be mutually exclusive with this one. At that point, manager-password-hash should be deprecated and ignored.
serverid serverid
The server for the directory. The server for the directory.
@ -35,6 +43,17 @@ suffix
E.g. `dc=ungleich,dc=ch`. See `slapd.conf(5)`. 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 OPTIONAL PARAMETERS
------------------- -------------------
syncrepl-credentials syncrepl-credentials
@ -53,6 +72,11 @@ admin-email
Required if using `__letsencrypt_cert`. Required if using `__letsencrypt_cert`.
Where to send Let's Encrypt emails like "certificate needs renewal". 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 tls-cert
If defined, `__letsencrypt_cert` is not used and this must be the path in If defined, `__letsencrypt_cert` is not used and this must be the path in
the remote hosts to the PEM-encoded TLS certificate. 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. The type user must ensure that the schema file is deployed.
This defaults to a sensible subset, for details see the type definition. 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 BOOLEAN PARAMETERS
------------------ ------------------
staging staging
@ -97,48 +126,71 @@ replicate
Whether to setup replication or not. Whether to setup replication or not.
If present `syncrepl-credentials` and `syncrepl-host` are also required. If present `syncrepl-credentials` and `syncrepl-host` are also required.
EXAMPLES EXAMPLES
-------- --------
.. code-block:: sh .. code-block:: sh
# Modify the ruleset on $__target_host: # Example of a simple server with manual certificate management.
__pf_ruleset --state present --source /my/pf/ruleset.conf pki_prefix="/usr/local/etc/pki/realms/ldap.camilion.cloud" \
require="__pf_ruleset" \ __openldap_server \
__pf_apply --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): # The created basedn looks as follows:
__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:
# #
# id=1 # dn: dc=camilion,dc=cloud
# for host in ldap-test1.ungleich.ch ldap-test2.ungleich.ch; do # objectClass: top
# echo "__ungleich_ldap ${host} \ # objectClass: dcObject
# --manager-dn 'cn=manager,dc=ungleich,dc=ch' \ # objectClass: organization
# --manager-password '{SSHA}fooo' \ # o: Managed by cdist, do not edit manually.
# --serverid '${id}' \ # dc: camilion
# --staging \ #
# --suffix 'dc=ungleich,dc=ch' \ # Do not change it manually, the type will overwrite your changes.
# --searchbase 'dc=ungleich,dc=ch' \
# --syncrepl-credentials 'fooo' \
# --syncrepl-host 'ldap-test1.ungleich.ch' \ #
# --syncrepl-host 'ldap-test2.ungleich.ch' \ # Changing to a replicated setup is a simple change to something like:
# --descriptiont 'Ungleich LDAP server'" \ #
# | cdist config -i - -v ${host} # Example for multiple servers with replication and automatic
# id=$((id + 1)) # Let's Encrypt certificate management through certbot.
# done 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 SEE ALSO

View file

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

View file

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

View file

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

View file

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