Skip to content
Snippets Groups Projects
Commit c3a356a9 authored by nimrod's avatar nimrod
Browse files

Major overhaul of the slapd (OpenLDAP) image.

- Use a single volume for the config and data LDAP directories, easier
to keep in sync in different cases (backups, migration).
- Add backup script, save to backup volume.
- Allow passing the location of the SSL key and cert to enable SSL,
otherwise a self-signed certificate and key are generated with the FQDN
of the container.
- Drop the dockerfile-lint linter, didn't give any useful advice.
- Change base image to Debian Buster.
- Set stopsignal for the container.
- Allow setting the log level.
- Unset the cleartext root password environment variable.
parent c65101a4
Branches
No related tags found
No related merge requests found
......@@ -5,13 +5,17 @@ services:
ldap:
build:
context: slapd/
volumes:
- _run_ldap:/run/slapd
- ldap:/var/lib/ldap
domainname: "${LDAP_HOSTNAME:-ldap}.${LDAP_DOMAIN:-nowhere.com}"
environment:
LDAP_ROOTPASS: "${LDAP_ROOTPASS:-foo}"
LDAP_DOMAIN: "${LDAP_DOMAIN:-nowhere.com}"
LDAP_ORGANIZATION: "${LDAP_ORGANIZATION:-none}"
hostname: "${LDAP_HOSTNAME:-ldap}"
restart: always
volumes:
- _run_slapd:/run/slapd
- ldap:/var/lib/ldap
- backup_ldap:/var/backups/ldap
nss-pam-ldapd:
build:
......@@ -20,23 +24,29 @@ services:
environment:
LDAP_BASE_DN: "${LDAP_BASE_DN:-dc=nowhere,dc=com}"
volumes:
- _run_ldap:/run/slapd
- _run_slapd:/run/slapd
ldap-account-manager:
build:
context: ldap-account-manager/
links:
- ldap
volumes:
- _run_ldap:/run/slapd
- ldap-account-manager:/var/lib/ldap-account-manager
ports:
- 80:80
restart: always
volumes:
- _run_slapd:/run/slapd
- ldap-account-manager:/var/lib/ldap-account-manager
volumes:
_run_ldap:
_run_slapd:
ldap:
ldap-account-manager:
labels:
snapshot: 'true'
backup_ldap:
labels:
snapshot: 'true'
networks:
default:
......
FROM debian:stretch-slim
RUN echo 'deb http://deb.debian.org/debian stretch-backports main' > /etc/apt/sources.list.d/backports.list && \
apt-get update && \
FROM debian:buster-slim
# hadolint ignore=DL3008
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
gnutls-bin=3.5.8-5+deb9u4 \
ldap-utils=2.4.44+dfsg-5+deb9u2 \
slapd=2.4.44+dfsg-5+deb9u2 \
gettext-base \
gnutls-bin \
ldap-utils \
slapd \
ssl-cert \
time \
&& \
mkdir -p /run/slapd && \
rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/* /var/cache/apt/archives/*
COPY --chown=root:root entrypoint /
usermod -aG ssl-cert openldap && \
rm -rf /tmp/* /var/tmp/* /var/cache/apt/archives/* /var/lib/apt/lists/* && \
rm -rf /etc/ssl/certs/ssl-cert-snakeoil.pem /etc/ssl/private/ssl-cert-snakeoil.key && \
rm -rf /var/lib/ldap/* /var/backups/ldap/* /run/slapd/* /etc/ldap/slapd.d
COPY --chown=root:root config.ldif /usr/share/slapd/
COPY --chown=root:root skel.ldif /usr/share/slapd/
COPY --chown=root:root entrypoint /usr/local/sbin/
COPY --chown=root:root backup /usr/local/sbin/
EXPOSE 389 636
VOLUME [ "/var/lib/ldap" ]
VOLUME [ "/run/ldap" ]
VOLUME [ "/run/slapd" ]
VOLUME [ "/var/backups/ldap" ]
ENV LDAP_URLS="ldap:/// ldapi:/// ldaps:///" \
SLAPD_DEBUG_LEVEL="NONE"
ENTRYPOINT [ "/entrypoint" ]
CMD [ "slapd", "-F", "/etc/ldap/slapd.d", "-u", "openldap", "-g", "openldap", "-h", "\"$LDAP_URLS\"", "-d", "$SLAPD_DEBUG_LEVEL" ]
HEALTHCHECK CMD ldapsearch -b cn=config -H ldapi:/// > /dev/null || exit 1
SLAPD_DEBUG_LEVEL="stats,stats2,none" \
SSL_CERT_FILE="/etc/ssl/certs/ssl-cert-snakeoil.pem" \
SSL_KEY_FILE="/etc/ssl/private/ssl-cert-snakeoil.key" \
SSL_CA_FILE="/etc/ssl/certs/ssl-cert-snakeoil.pem"
ENTRYPOINT [ "entrypoint" ]
CMD [ "slapd", "-F", "/var/lib/ldap/config", "-u", "openldap", "-g", "openldap", "-h", "\"$LDAP_URLS\"", "-d", "$SLAPD_DEBUG_LEVEL" ]
HEALTHCHECK CMD ldapsearch -b cn=config > /dev/null || exit 1
STOPSIGNAL INT
......@@ -15,10 +15,27 @@ Name | Description | Default value
`LDAP_ROOTPASS` | Root password.
`LDAP_DOMAIN` | Domain.
`LDAP_ORGANIZATION` | Organization.
`SLAPD_DEBUG_LEVEL` | The `slapd` debug/ log level.
`SSL_CERT_FILE` | Location of the SSL certificate file.
`SSL_KEY_FILE` | Location of the SSL key file.
`SSL_CA_FILE` | Location of the SSL certificate authority file.
## SSL
If the relevant environment variables aren't changed from their default values,
on startup the container will generate a key and self-signed certificate with
the FQDN of the container. If the location of the SSL key and certificate are
provided, those are used instead.
## Persistence
The database is at `/var/lib/ldap`.
The configuration (`cn=config`) and data LDAP directories reside in the
`config` and `data` diretories respectively in the `/var/lib/ldap` volume.
The LDAP directories are generated only if they're missing. Changes to
environment variables afterwards won't change the configuration, since that is
persisted to a volume. There's also the `/var/backups/ldap` volume where the
`backup` script saves snapshots of the LDAP directories (config directory
included).
## License
......
#!/bin/sh
set -eux
slapcat -n0 -v -l /var/backups/ldap/config.ldif
for dn in $(ldapsearch -Y EXTERNAL -LLL -s base -b '' o namingContexts | sed -n '/namingContexts/ s/namingContexts: //gp')
do
slapcat -b "$dn" -v -l "/var/backups/$dn.ldif"
done
# Global config:
dn: cn=config
objectClass: olcGlobal
cn: config
# Where the pid file is put. The init.d script
# will not stop the server if you change this.
olcPidFile: /var/run/slapd/slapd.pid
# List of arguments that were passed to the server
olcArgsFile: /var/run/slapd/slapd.args
# Read slapd-config(5) for possible values
olcLogLevel: none
# The tool-threads parameter sets the actual amount of cpu's that is used
# for indexing.
olcToolThreads: 1
# TLS options.
olcTLSCACertificateFile: ${SSL_CA_FILE}
olcTLSCertificateFile: ${SSL_CERT_FILE}
olcTLSCertificateKeyFile: ${SSL_KEY_FILE}
olcTLSCipherSuite: SECURE256:+SECURE128
olcTLSProtocolMin: 3.1
olcTLSDHParamFile: /usr/share/slapd/dh.pem
# Frontend settings
dn: olcDatabase={-1}frontend,cn=config
objectClass: olcDatabaseConfig
objectClass: olcFrontendConfig
olcDatabase: {-1}frontend
# The maximum number of entries that is returned for a search operation
olcSizeLimit: 500
# Allow unlimited access to local connection from the local root user
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break
# Allow unauthenticated read access for schema and base DN autodiscovery
olcAccess: {1}to dn.exact="" by * read
olcAccess: {2}to dn.base="cn=Subschema" by * read
# Config db settings
dn: olcDatabase=config,cn=config
objectClass: olcDatabaseConfig
olcDatabase: config
# Allow unlimited access to local connection from the local root user
olcAccess: to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break
olcRootDN: cn=admin,cn=config
# Load schemas
dn: cn=schema,cn=config
objectClass: olcSchemaConfig
cn: schema
include: file:///etc/ldap/schema/core.ldif
include: file:///etc/ldap/schema/cosine.ldif
include: file:///etc/ldap/schema/nis.ldif
include: file:///etc/ldap/schema/inetorgperson.ldif
# Load module
dn: cn=module{0},cn=config
objectClass: olcModuleList
cn: module{0}
# Where the dynamically loaded modules are stored
olcModulePath: /usr/lib/ldap
olcModuleLoad: back_mdb
# Set defaults for the backend
dn: olcBackend=mdb,cn=config
objectClass: olcBackendConfig
olcBackend: mdb
# The database definition.
dn: olcDatabase=mdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcMdbConfig
olcDatabase: mdb
# Checkpoint the database periodically in case of system
# failure and to speed slapd shutdown.
olcDbCheckpoint: 512 30
olcDbMaxSize: 1073741824
# Save the time that the entry gets modified, for database #1
olcLastMod: TRUE
# The base of your directory in database #1
olcSuffix: ${BASE_DN}
# Where the database file are physically stored for database #1
olcDbDirectory: /var/lib/ldap/data
# olcRootDN directive for specifying a superuser on the database. This
# is needed for syncrepl.
olcRootDN: cn=admin,${BASE_DN}
olcRootPW: ${PASSWORD_HASH}
# Indexing options for database #1
olcDbIndex: objectClass eq
olcDbIndex: cn,uid eq
olcDbIndex: uidNumber,gidNumber eq
olcDbIndex: member,memberUid eq
# The userPassword by default can be changed by the entry owning it if
# they are authenticated. Others should not be able to see it, except
# the admin entry above.
olcAccess: to attrs=userPassword
by self write
by anonymous auth
by * none
# Allow update of authenticated user's shadowLastChange attribute.
# Updating it on password change is implemented at least by libpam-ldap,
# libpam-ldapd, and the slapo-smbk5pwd overlay.
olcAccess: to attrs=shadowLastChange
by self write
by * read
# The admin dn (olcRootDN) bypasses ACLs and so has total access,
# everyone else can read everything.
olcAccess: to *
by * read
#!/bin/sh
set -eux
# Get the root password hash and unset the cleartext password.
PASSWORD_HASH="$(slappasswd -ns "$LDAP_ROOTPASS")"
unset LDAP_ROOTPASS
export PASSWORD_HASH
# See https://github.com/moby/moby/issues/8231
# shellcheck disable=SC2039
ulimit -n 1024 || true
# Create and set owner for runtime directories.
install -d -o openldap -g openldap /run/slapd
install -d -o openldap -g openldap /var/backups/ldap
install -d -o openldap -g openldap /var/lib/ldap
install -d -o openldap -g openldap /var/lib/ldap/config
install -d -o openldap -g openldap /var/lib/ldap/data
# Base DN.
BASE_DN="dc=$(echo "$LDAP_DOMAIN" | sed 's/^\.//; s/\.$//; s/\./,dc=/g')"
export BASE_DN
# DC.
DC="$(echo "$LDAP_DOMAIN" | sed 's/^\.//; s/\..*$//')"
export DC
# Generate self-signed certificates if none are provided.
if [ "${SSL_CERT_FILE:-}" = "/etc/ssl/certs/ssl-cert-snakeoil.pem" ] || \
[ "${SSL_KEY_FILE:-}" = "/etc/ssl/private/ssl-cert-snakeoil.key" ]
then
echo Generating self-signed key and certificate. >&2
DEBIAN_FRONTEND=noninteractive time make-ssl-cert generate-default-snakeoil --force-overwrite
fi
# Generate random DH parameters.
echo Generating DH parameters, this will take a while. >&2
time openssl dhparam -out /usr/share/slapd/dh.pem 2048
# Run slapadd with the correct user and location of the config directory.
alias slapadd='chroot --userspec openldap:openldap / slapadd -gv -F /var/lib/ldap/config'
# Create configuration is none is present.
if [ -z "$(find /var/lib/ldap/config -maxdepth 1 -mindepth 1)" ]
then
echo No configuration found, generating a new one. >&2
# shellcheck disable=SC2002
cat /usr/share/slapd/config.ldif | envsubst | slapadd -b 'cn=config'
fi
# Create directory if none is present.
if [ -z "$(find /var/lib/ldap/data -maxdepth 1 -mindepth 1)" ]
then
echo No directory found, generating a new one, >&2
# shellcheck disable=SC2002
cat /usr/share/slapd/skel.ldif | envsubst | slapadd -b "$BASE_DN"
fi
cat << EOF | debconf-set-selections -v
slapd slapd/internal/generated_adminpw password ${LDAP_ROOTPASS:-}
slapd slapd/internal/adminpw password ${LDAP_ROOTPASS:-}
slapd slapd/password2 password ${LDAP_ROOTPASS:-}
slapd slapd/password1 password ${LDAP_ROOTPASS:-}
slapd slapd/domain string ${LDAP_DOMAIN:-}
slapd shared/organization string ${LDAP_ORGANIZATION:-}
# Configure the client.
cat << EOF >> /etc/ldap/ldap.conf
URI ldapi:///
SASL_MECH EXTERNAL
BASE $BASE_DN
EOF
DEBIAN_FRONTEND=noninteractive dpkg-reconfigure -f noninteractive slapd
# Unset the root password hash.
unset PASSWORD_HASH
# Run CMD.
eval exec "$@"
dn: ${BASE_DN}
objectClass: top
objectClass: dcObject
objectClass: organization
o: ${LDAP_ORGANIZAION}
dc: ${DC}
dn: cn=admin,${BASE_DN}
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword: ${PASSWORD_HASH}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment