From 07d6e6885448cdb5fa5ec8b8e2f03bd234b10605 Mon Sep 17 00:00:00 2001 From: Dave Conroy Date: Sat, 18 Aug 2018 10:06:22 -0700 Subject: [PATCH] 6.0 - See Changelog --- CHANGELOG.md | 7 + Dockerfile | 23 ++- README.md | 12 ++ .../bootstrap/ldif/01-config-password.ldif | 8 +- .../config/bootstrap/ldif/02-security.ldif | 4 +- install/etc/cont-init.d/10-openldap | 187 ++++++++++++++---- install/etc/openldap/check_password.conf | 7 - install/etc/openldap/ppm.conf | 65 ------ 8 files changed, 198 insertions(+), 115 deletions(-) delete mode 100644 install/etc/openldap/check_password.conf delete mode 100644 install/etc/openldap/ppm.conf diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b1df14..f8cad0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 6.0 2018-08-18 + +* Stop relying on slapd.conf on first time initialization +* Properly apply ACLs for ppolicy +* Generate Wordlist for ppm.so +* Automatically generate check_password.conf and ppm.conf + ## 5.5 2018-08-16 * Fix for ACLs not applying on initial boot diff --git a/Dockerfile b/Dockerfile index 696d5ba..9b4017a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,9 +15,11 @@ ENV ADMIN_PASS=admin \ ENABLE_TLS=true \ LOG_LEVEL=256 \ OPENLDAP_VERSION=2.4.46 \ + ORGANIZATION="Example Organization" \ READONLY_USER_PASS=readonly \ READONLY_USER_USER=readonly \ REMOVE_CONFIG_AFTER_SETUP=false \ + SCHEMA2LDIF_VERSION=1.3 \ SCHEMA_TYPE=nis \ SSL_HELPER_PREFIX=ldap \ TLS_CA_CRT_FILENAME=ca.pem \ @@ -28,6 +30,7 @@ ENV ADMIN_PASS=admin \ TLS_VERIFY_CLIENT=try \ ZABBIX_HOSTNAME=openldap-app + COPY CHANGELOG.md /tiredofit/ RUN set -x && \ @@ -59,12 +62,12 @@ RUN set -x && \ cyrus-sasl \ coreutils \ cracklib \ - cracklib-words \ libressl \ libltdl \ libuuid \ libintl \ nginx \ + perl \ sed \ sudo \ unixodbc \ @@ -159,10 +162,24 @@ RUN set -x && \ curl -o /usr/sbin/cfssljson -SL https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 && \ chmod 700 /usr/sbin/cfssljson && \ \ +## Install Schema2LDIF + curl https://codeload.github.com/fusiondirectory/schema2ldif/tar.gz/${SCHEMA2LDIF_VERSION} | tar xvfz - --strip 1 -C /usr && \ + rm -rf /usr/Changelog && \ + rm -rf /usr/LICENSE && \ + \ +## Create Cracklib Dictionary + mkdir -p /usr/share/dict && \ + cd /usr/share/dict && \ + wget https://github.com/cracklib/cracklib/releases/download/cracklib-2.9.6/cracklib-words-2.9.6.gz && \ + create-cracklib-dict -o pw_dict cracklib-words-2.9.6.gz && \ + rm -rf cracklib-words-2.9.6.gz && \ + \ ### Cleanup + apk del \ + .openldap-build-deps \ + && \ rm -rf /tiredofit \ - /var/cache/apk/* && \ - apk del .openldap-build-deps + /var/cache/apk/* ### Add Assets ADD install / diff --git a/README.md b/README.md index 1f13a9f..f2016f5 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,7 @@ Required and used for new ldap server only: | `BASE_DN` | LDAP base DN. If empty automatically set from `DOMAIN` value. Default (empty) | | `ADMIN_PASS` | Ldap Admin password. Default `admin` | | `CONFIG_PASS` | Ldap Config password. Default `config` | +| `ORGANIZATION` | Organization Name Default: `Example Organization` | | `ENABLE_READONLY_USER` | Add a read only user. Default`false` | | `READONLY_USER_USER` | Read only user username. Default `readonly | | `READONLY_USER_PASS` | Read only user password. Default `readonly` | @@ -129,6 +130,17 @@ Backup Options: | `BACKUP_DATA_CRON_PERIOD` | Cron expression to schedule OpenLDAP data backup. Defaults `0 4 * * *` Every day at 4am. | | `BACKUP_TTL ` | Automatically cleanup backup after how many days. Default `15` | +Password Policy Options (only if using check_password.so): + +| Variable | Description | +|-----------|-------------| +| `PPOLICY_MAX_CONSEC`| Maximu Consective Character Pattern - Default `0` | +| `PPOLICY_MIN_DIGIT` | Minimum Digit Characters - Default `0` | +| `PPOLICY_MIN_LOWER` | Minimum Lowercase Characters - Default `0` | +| `PPOLICY_MIN_POINTS`| Minimum Points required to pass checker - Default `3` | +| `PPOLICY_MIN_PUNCT` | Minimum Punctuation Characters - Default `0` | +| `PPOLICY_MIN_UPPER` | Minimum Uppercase Characters - Default `0` | + TLS options: | Variable | Description | diff --git a/install/assets/slapd/config/bootstrap/ldif/01-config-password.ldif b/install/assets/slapd/config/bootstrap/ldif/01-config-password.ldif index ecfd342..f6ee346 100644 --- a/install/assets/slapd/config/bootstrap/ldif/01-config-password.ldif +++ b/install/assets/slapd/config/bootstrap/ldif/01-config-password.ldif @@ -1,7 +1,11 @@ -# Set config password +dn: olcDatabase={0}config,cn=config +changetype: modify +add: olcRootDN +olcRootDN: cn=admin,cn=config + dn: cn=config changeType: modify dn: olcDatabase={0}config,cn=config add: olcRootPW -olcRootPW: +olcRootPW: \ No newline at end of file diff --git a/install/assets/slapd/config/bootstrap/ldif/02-security.ldif b/install/assets/slapd/config/bootstrap/ldif/02-security.ldif index e13b5e3..72381bc 100644 --- a/install/assets/slapd/config/bootstrap/ldif/02-security.ldif +++ b/install/assets/slapd/config/bootstrap/ldif/02-security.ldif @@ -1,5 +1,5 @@ dn: olcDatabase={1},cn=config changeType: modify add: olcAccess -olcAccess: to attrs=userPassword,shadowLastChange by self write by dn="cn=admin," write by anonymous auth by * none -olcAccess: to * by self write by dn="cn=admin," write by * none +olcAccess: to attrs=userPassword,shadowLastChange by self =xw by dn="cn=admin," write by anonymous auth by * none +olcAccess: to * by self write by dn="cn=admin," write by * read diff --git a/install/etc/cont-init.d/10-openldap b/install/etc/cont-init.d/10-openldap index d149139..49b1e93 100755 --- a/install/etc/cont-init.d/10-openldap +++ b/install/etc/cont-init.d/10-openldap @@ -10,10 +10,35 @@ function get_ldap_base_dn() { BASE_DN=$BASE_DN$EXT done + IFS='.' read -a domain_elems <<< "${DOMAIN}" + SUFFIX="" + ROOT="" + + for elem in "${domain_elems[@]}" ; do + if [ "x${SUFFIX}" = x ] ; then + SUFFIX="dc=${elem}" + ROOT="${elem}" + fi + done + BASE_DN=${BASE_DN::-1} fi } + + IFS='.' read -a domain_elems <<< "${DOMAIN}" + SUFFIX="" + ROOT="" + + for elem in "${domain_elems[@]}" ; do + if [ "x${SUFFIX}" = x ] ; then + SUFFIX="dc=${elem}" + ROOT="${elem}" + else + BASE_DN="${SUFFIX},dc=${elem}" + fi + done + function is_new_schema() { local COUNT=$(ldapsearch -Q -Y EXTERNAL -H ldapi:/// -b cn=schema,cn=config cn | grep -c $1) if [ "$COUNT" -eq 0 ]; then @@ -42,12 +67,20 @@ function ldap_add_or_modify (){ function schema2ldif (){ SCHEMAS=$1 +# Dual Schema Support + if [ "$SCHEMA_TYPE" = "rfc2307bis" ] || [ "$SCHEMA_TYPE" = "RFC2307BIS" ]; then + cp -R /assets/slapd/config/bootstrap/schema/rfc2307bis/rfc2307bis.schema /etc/openldap/schema/ + SCHEMA_TYPE="rfc2307bis" + else + SCHEMA_TYPE="nis" + fi + tmpd=`mktemp -d` pushd ${tmpd} >>/dev/null echo "include /etc/openldap/schema/core.schema" >> convert.dat echo "include /etc/openldap/schema/cosine.schema" >> convert.dat - echo "include /etc/openldap/schema/nis.schema" >> convert.dat + echo "include /etc/openldap/schema/${SCHEMA_TYPE}.schema" >> convert.dat echo "include /etc/openldap/schema/inetorgperson.schema" >> convert.dat for schema in ${SCHEMAS} ; do @@ -153,7 +186,7 @@ if [ ! -e "$FIRST_START_DONE" ]; then # RFC2307bis schema if [ "$SCHEMA_TYPE" = "rfc2307bis" ] || [ "$SCHEMA_TYPE" = "RFC2307BIS" ]; then echo "** [openldap] Using RFC2307BIS schema type" - cp /assets/slapd/config/bootstrap/schema/rfc2307bis/rfc2307bis.* /etc/openldap/schema/ + cp -R /assets/slapd/config/bootstrap/schema/rfc2307bis/rfc2307bis.schema /etc/openldap/schema/ SCHEMA_TYPE="rfc2307bis" else echo "** [openldap] Using NIS schema type" @@ -163,45 +196,78 @@ if [ ! -e "$FIRST_START_DONE" ]; then get_ldap_base_dn ### Create Sample Configuration to Populate Schema - cat < /tmp/slapd.conf -include /etc/openldap/schema/core.schema -include /etc/openldap/schema/cosine.schema -include /etc/openldap/schema/inetorgperson.schema -include /etc/openldap/schema/${SCHEMA_TYPE}.schema -pidfile /run/openldap/slapd.pid -argsfile /run/openldap/slapd.args -modulepath /usr/lib/openldap -moduleload back_mdb.so - -disallow tls_2_anon - -database mdb -maxsize 1073741824 -suffix "${BASE_DN}" -rootdn "cn=admin,${BASE_DN}" -rootpw `slappasswd -s ${ADMIN_PASS}` -directory /var/lib/openldap - -#sortvals uid - -database config -rootdn "cn=admin,cn=config" -access to * + cat < /tmp/slapd.ldif +dn: cn=config +objectClass: olcGlobal +cn: config +olcPidFile: /run/openldap/slapd.pid +olcArgsFile: /run/openldap/slapd.args + +dn: cn=module,cn=config +objectClass: olcModuleList +cn: module +olcModulepath: /usr/lib/openldap +olcModuleload: back_mdb.so + +dn: cn=schema,cn=config +objectClass: olcSchemaConfig +cn: schema + +include: file:///etc/openldap/schema/core.ldif +include: file:///etc/openldap/schema/cosine.ldif +include: file:///etc/openldap/schema/inetorgperson.ldif +include: file:///etc/openldap/schema/${SCHEMA_TYPE}.ldif + +# Frontend settings +dn: olcDatabase=frontend,cn=config +objectClass: olcDatabaseConfig +objectClass: olcFrontendConfig +olcDatabase: frontend +olcAccess: to dn.base="" by * read +olcAccess: to dn.base="cn=Subschema" by * read +olcAccess: to * + by self write + by users read + by anonymous auth + +# Config Settings +dn: olcDatabase=config,cn=config +objectClass: olcDatabaseConfig +olcDatabase: config +olcRootPW: `slappasswd -s ${CONFIG_PASS}` +olcAccess: to * by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage by break by * break -database monitor -access to dn.subtree="cn=Monitor" - by dn.exact="cn=admin,$BASE_DN" write - by users read - by * none +dn: olcDatabase=mdb,cn=config +objectClass: olcDatabaseConfig +objectClass: olcMdbConfig +olcDatabase: mdb +olcSuffix: ${BASE_DN} +OlcDbMaxSize: 1073741824 +olcDbDirectory: /var/lib/openldap +olcRootDN: cn=admin,${BASE_DN} +olcRootPW: `slappasswd -s ${ADMIN_PASS}` +olcDbIndex: objectClass eq + +dn: olcDatabase=Monitor,cn=config +objectClass: olcDatabaseConfig +objectClass: olcMonitorConfig +olcDatabase: Monitor +olcAccess: to dn.subtree="cn=Monitor" by dn.exact="cn=admin,${BASE_DN}" write by users read by * none EOF set +e -silent slaptest -f /tmp/slapd.conf -F /etc/openldap/slapd.d -silent slaptest -f /tmp/slapd.conf -F /etc/openldap/slapd.d -u -rm -rf /tmp/slapd.conf + +/usr/bin/schema2ldif /etc/openldap/schema/core.schema > /etc/openldap/schema/core.ldif +/usr/bin/schema2ldif /etc/openldap/schema/cosine.schema > /etc/openldap/schema/cosine.ldif +/usr/bin/schema2ldif /etc/openldap/schema/inetorgperson.schema > /etc/openldap/schema/inetorgperson.ldif +/usr/bin/schema2ldif /etc/openldap/schema/${SCHEMA_TYPE}.schema > /etc/openldap/schema/${SCHEMA_TYPE}.ldif + +silent slapadd -n 0 -F /etc/openldap/slapd.d -l /tmp/slapd.ldif +rm -rf /tmp/slapd.ldif set -e + chown -R ldap:ldap /etc/openldap # Error: the database directory (/var/lib/openldap) is empty but not the config directory (/etc/openldap/slapd.d) @@ -338,11 +404,10 @@ chown -R ldap:ldap /etc/openldap echo "** [openldap] Processing file ${f}" ldap_add_or_modify "$f" done - # Add ppolicy schema echo "** [openldap] Adding ppolicy Schema" - schema2ldif /etc/openldap/schema/ppolicy.schema && \ + /usr/bin/schema2ldif /etc/openldap/schema/ppolicy.schema > /etc/openldap/schema/ppolicy.ldif && \ silent ldapadd -c -Y EXTERNAL -Q -H ldapi:/// -f /etc/openldap/schema/ppolicy.ldif # Read only user @@ -353,6 +418,7 @@ chown -R ldap:ldap /etc/openldap ldap_add_or_modify "/assets/slapd/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif" fi + # Custom LDIF injection if [ -d /assets/slapd/config/bootstrap/ldif/custom ]; then echo "** [openldap] Add custom bootstrap ldifs" for f in $(find /assets/slapd/config/bootstrap/ldif/custom -type f -name \*.ldif | sort); do @@ -466,6 +532,55 @@ chown -R ldap:ldap /etc/openldap done fi + + ## Configure PPolicy check_password.so + ppm.so module + PPOLICY_CHECK_RDN=${PPOLICY_CHECK_RDN:-0} + PPOLICY_MAX_CONSEC=${PPOLICY_MAX_CONSEC:-0} + PPOLICY_MAX_LENGTH=${PPOLICY_MAX_LENGTH:-0} + PPOLICY_MIN_DIGIT=${PPOLICY_MIN_DIGIT:-0} + PPOLICY_MIN_LOWER=${PPOLICY_MIN_LOWER:-0} + PPOLICY_MIN_POINTS=${PPOLICY_MIN_POINTS:-3} + PPOLICY_MIN_PUNCT=${PPOLICY_MIN_PUNCT:-0} + PPOLICY_MIN_UPPER=${PPOLICY_MIN_UPPER:-0} + PPOLICY_USE_CRACKLIB=${PPOLICY_USE_CRACKLIB:-1} + + ### check_password.so + if [ ! -f /etc/openldap/check_password.conf ]; then + cat < /etc/openldap/check_password.conf +## check_password.conf +## Auto Generated by Container, any changes will be reset on container restart! +min_points $PPOLICY_MIN_POINTS +min_upper $PPOLICY_MIN_UPPER +min_lower $PPOLICY_MIN_LOWER +min_digit $PPOLICY_MIN_DIGIT +min_punct $PPOLICY_MIN_PUNCT +max_consecutive_per_class $PPOLICY_MAX_CONSEC +EOF + + chown ldap. /etc/openldap/check_password.conf + fi + + ### ppm.so + if [ ! -f /etc/openldap/ppm.conf ]; then + cat < /etc/openldap/ppm.conf +## ppm.conf +## Auto Generated by Container, any changes will be reset on container restart! +minQuality $PPOLICY_MIN_POINTS +maxLength $PPOLICY_MAX_LENGTH +checkRDN $$POLICY_CHECK_RDN +forbiddenChars $PPOLICY_FORBIDDEN_CHARACTERS +maxConsecutivePerClass $PPOLICY_MAX_CONSEC +useCracklib $PPOLICY_USE_CRACKLIB +cracklibDict /usr/share/dict/pw_dict +class-upperCase ABCDEFGHIJKLMNOPQRSTUVWXYZ $PPOLICY_MIN_UPPER 1 +class-lowerCase abcdefghijklmnopqrstuvwxyz $PPOLICY_MIN_LOWER 1 +class-digit 0123456789 $PPOLICY_MIN_DIGIT 1 +class-special <>,?;.:/!§ù%*µ^¨$£²&é~"#'{([-|è`_\ç^à@)]°=}+ $PPOLICY_MIN_PUNCT 1 +EOF + + chown ldap. /etc/openldap/ppm.conf + fi + # Stop OpenLDAP echo "** [openldap] Finished OpenLDAP Initialization" diff --git a/install/etc/openldap/check_password.conf b/install/etc/openldap/check_password.conf deleted file mode 100644 index 42e113f..0000000 --- a/install/etc/openldap/check_password.conf +++ /dev/null @@ -1,7 +0,0 @@ -min_points 3 -min_upper 0 -min_lower 0 -min_digit 0 -min_punct 0 -max_consecutive_per_class 5 - diff --git a/install/etc/openldap/ppm.conf b/install/etc/openldap/ppm.conf deleted file mode 100644 index 80ff476..0000000 --- a/install/etc/openldap/ppm.conf +++ /dev/null @@ -1,65 +0,0 @@ -# minQuality parameter -# Format: -# minQuality [NUMBER] -# Description: -# One point is granted for each class for which MIN_FOR_POINT criteria is fulfilled. -# defines the minimum point numbers for the password to be accepted. -minQuality 3 - -# maxLength parameter -# Format: -# maxLength [NUMBER] -# Description: -# The password must not be more than [NUMBER] long. 0 means no limit is set. -maxLength 0 - -# checkRDN parameter -# Format: -# checkRDN [0 | 1] -# Description: -# If set to 1, password must not contain a token from the RDN. -# Tokens are separated by the following delimiters : space tabulation _ - , ; £ -checkRDN 0 - -# forbiddenChars parameter -# Format: -# forbiddenChars [CHARACTERS_FORBIDDEN] -# Description: -# Defines the forbidden characters list (no separator). -# If one of them is found in the password, then it is rejected. -forbiddenChars - -# maxConsecutivePerClass parameter -# Format: -# maxConsecutivePerClass [NUMBER] -# Description: -# Defines the maximum number of consecutive character allowed for any class -maxConsecutivePerClass 0 - -# useCracklib parameter -# Format: -# useCracklib [0 | 1] -# Description: -# If set to 1, the password must pass the cracklib check -useCracklib 0 - -# cracklibDict parameter -# Format: -# cracklibDict [path_to_cracklib_dictionnary] -# Description: -# directory+filename-prefix that your version of CrackLib will go hunting for -# For example, /var/pw_dict resolves as /var/pw_dict.pwd, -# /var/pw_dict.pwi and /var/pw_dict.hwm dictionnary files -cracklibDict /var/cache/cracklib/cracklib_dict - -# classes parameter -# Format: -# class-[CLASS_NAME] [CHARACTERS_DEFINING_CLASS] [MIN] [MIN_FOR_POINT] -# Description: -# [CHARACTERS_DEFINING_CLASS]: characters defining the class (no separator) -# [MIN]: If at least [MIN] characters of this class is not found in the password, then it is rejected -# [MIN_FOR_POINT]: one point is granted if password contains at least [MIN_FOR_POINT] character numbers of this class -class-upperCase ABCDEFGHIJKLMNOPQRSTUVWXYZ 0 1 -class-lowerCase abcdefghijklmnopqrstuvwxyz 0 1 -class-digit 0123456789 0 1 -class-special <>,?;.:/!§ù%*µ^¨$£²&é~"#'{([-|è`_\ç^à@)]°=}+ 0 1