Initial commit

This commit is contained in:
paul 2017-09-09 17:54:45 +02:00 committed by Hive
commit 70ffd9b09c
8 changed files with 374 additions and 0 deletions

3
.dockerignore Normal file
View file

@ -0,0 +1,3 @@
docker-compose.yml
.git/
data/

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
data/

27
Dockerfile Normal file
View file

@ -0,0 +1,27 @@
FROM debian:stretch
EXPOSE 389
ENV DEBIAN_FRONTEND noninteractive \
CONFDIR /etc/ldap/slapd.d \
DATADIR /var/lib/ldap
# add our users and groups first to ensure their IDs get assigned consitently
RUN groupadd -r -g 500 openldap && useradd -r -u 500 -g openldap openldap
RUN \
apt-get update && \
apt-get install --yes --no-install-recommends \
slapd \
ldap-utils \
ca-certificates && \
# remove the default config, since the entrypoint
# will populate it by hand.
rm -rf /etc/ldap/slapd.d && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY entrypoint.sh /entrypoint.sh
COPY fixtures/ /usr/share/slapd/fixtures/
ENTRYPOINT ["/entrypoint.sh"]

30
README.md Normal file
View file

@ -0,0 +1,30 @@
## slapd
Slapd offers a LDAP server, which we mostly use for authentication of various
services.
Therefore, a lot of services have a direct (or indirect) dependency on this
image.
### Building slapd
```
docker build -t zombi/slapd .
```
### Running slapd
```
docker run -d --name ldap -v /data/ldap:/data -p 389:389 zombi/slapd
```
### Backing up data
Data in this container is considered essential, since it influences almost
all other services we run.
We recently discovered that **simply copying all the data from `data` DOES
NOT WORK**, therefore we included scripts for backing up the slapd database
into a compact .ldif format.
running `tools/create-ldap-backup.sh` will create two files:
* `conf.ldif` is a backup of the configuration.
* `data.ldif` contains all the saved datasets.

15
docker-compose.yml Normal file
View file

@ -0,0 +1,15 @@
version: '2'
services:
ldap:
build: .
ports:
- "3810:389"
environment:
- "ROOTPW=pass"
- "ORGANIZATION=zombi"
- "DATADIR=/data"
- "CONFDIR=/conf"
volumes:
- ./data/ldap/config:/conf
- ./data/ldap/data:/data

93
entrypoint.sh Executable file
View file

@ -0,0 +1,93 @@
#!/bin/bash -e
set -eo pipefail
# set default values for undefined vars
CONFDIR=${CONFDIR:-'/etc/ldap/slapd.d'}
DATADIR=${DATADIR:-'/var/lib/ldap'}
if [[ -z "$ORGANIZATION" && -z "$SUFFIX" ]] ; then
fail 'neither ORGANIZATION nor SUFFIX supplied as environment var'
fi
if [[ -n "$ORGANIZATION" ]] ; then
# if an organization was set, we can generate the RootDN from that
SUFFIX=${SUFFIX:-"o=${ORGANIZATION}"}
fi
function fail {
# write to stderr
echo "ERROR: $@" >&2
exit 1
}
function configure {
sed \
-e "s|@SUFFIX@|${SUFFIX}|g" \
-e "s|@PASSWORD@|${ROOTPW}|g" \
-e "s|@DATADIR@|${DATADIR}|g" \
/usr/share/slapd/fixtures/config.ldif \
| slapadd -F "$CONFDIR" -b "cn=config"
return $?
}
function init_fixtures {
mkdir -p /docker-entrypoint-initdb.d
# if no files exist in this directory then copy example structure
if ! ls /docker-entrypoint-initdb.d/* 1> /dev/null 2>&1 ; then
cp /usr/share/slapd/fixtures/example_structure.ldif /docker-entrypoint-initdb.d/structure.ldif
fi
for f in /docker-entrypoint-initdb.d/*; do
case "$f" in
*.sh)
echo "$0: running $f"; . "$f"
;;
*.ldif)
sed \
-e "s|@SUFFIX@|${SUFFIX}|g" \
-e "s|@PASSWORD@|${ROOTPW}|g" \
-e "s|@DATADIR@|${DATADIR}|g" \
-e "s|@ORGANIZATION@|${ORGANIZATION}|g" \
"$f" \
| slapadd -F "$CONFDIR" -b "$SUFFIX"
;;
*) echo "$0: ignoring $f" ;;
esac
echo
done
}
# Reduce maximum number of open file descriptors to 1024
# otherwise slapd consumes two orders of magnitude more of RAM
# see https://github.com/docker/docker/issues/8231
ulimit -n 1024 || fail "could not set ulimits"
# create dirs if they not already exists
[ -d $CONFDIR ] || mkdir -p $CONFDIR
[ -d $DATADIR ] || mkdir -p $DATADIR
if [[ ! -d "$CONFDIR/cn=config" ]] ; then
echo "configuration not found, creating one for $SUFFIX .."
[[ -z "$ROOTPW" ]] && fail "ROOTPW not set."
[[ -z "$SUFFIX" ]] && fail "SUFFIX not set."
# if rootpw is not already in hashed format, hash it first
[[ "${ROOTPW:0:1}" == '{' ]] \
||ROOTPW=`slappasswd -s "$ROOTPW"`
configure || fail "could not create slapd config"
fi
if [[ ! -f "$DATADIR/data.mdb" ]] ; then
init_fixtures
fi
# fix file permissions
chown -R openldap:openldap $CONFDIR $DATADIR \
|| fail "could not change permissions"
echo "Starting slapd."
exec /usr/sbin/slapd -F $CONFDIR -u openldap -g openldap -h 'ldapi:// ldap://' -d stats

156
fixtures/config.ldif Normal file
View file

@ -0,0 +1,156 @@
# this file was adapted from the default /usr/share/slapd/slapd.init.ldif
# Global config:
dn: cn=config
objectClass: olcGlobal
cn: config
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
# 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
olcRootPW: @PASSWORD@
# Load schemas
dn: cn=schema,cn=config
objectClass: olcSchemaConfig
cn: schema
# base schemas
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
# additional schemas
# include: file:///etc/ldap/schema/ppolicy.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
# Load memberof module
dn: cn=module{1},cn=config
objectClass: olcModuleList
objectClass: top
cn: module{1}
olcModulePath: /usr/lib/ldap
olcModuleLoad: memberof.la
# Load refint module
dn: cn=module{2},cn=config
objectClass: olcModuleList
objectClass: top
cn: module{2}
olcModulePath: /usr/lib/ldap
olcModuleLoad: refint.la
# 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: @SUFFIX@
# Where the database file are physically stored for database #1
olcDbDirectory: @DATADIR@
# olcRootDN directive for specifying a superuser on the database. This
# is needed for syncrepl.
olcRootDN: cn=admin,@SUFFIX@
olcRootPW: @PASSWORD@
# Indexing options for database #1
olcDbIndex: objectClass eq
olcDbIndex: cn,uid eq
olcDbIndex: uidNumber,gidNumber eq
olcDbIndex: member,memberUid eq
# additional attributes
olcDbIndex: mail,associatedDomain eq
olcDbIndex: memberOf 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
# ou=People users can see ou=People node
olcAccess: to dn.exact="ou=People,@SUFFIX@"
by dn.subtree="ou=People,@SUFFIX@" read
by * break
# User can only access their own profile
# Services can read all User nodes
olcAccess: to dn.subtree="ou=People,@SUFFIX@"
by self read
by dn.subtree="ou=Services,ou=People,@SUFFIX@" read
by * none
# allow to read domain attributes for service accounts
olcAccess: to dn.subtree="ou=Domains,@SUFFIX@"
by dn.subtree="ou=Services,ou=People,@SUFFIX@" read
# The admin dn (olcRootDN) bypasses ACLs and so has total access,
# everyone logged in can read everything.
olcAccess: to *
by anonymous none
by * read
# memberof overlay manages the memberOf attribute based on referential
# groups
dn: olcOverlay={0}memberof,olcDatabase={1}mdb,cn=config
objectClass: olcConfig
objectClass: olcMemberOf
objectClass: olcOverlayConfig
objectClass: top
olcOverlay: memberof
# refint overlay preserves referential integrety, by watching for renames of
# referenced fields
dn: olcOverlay={1}refint,olcDatabase={1}mdb,cn=config
objectClass: olcConfig
objectClass: olcOverlayConfig
objectClass: olcRefintConfig
objectClass: top
olcOverlay: {1}refint
olcRefintAttribute: memberof member manager owner

View file

@ -0,0 +1,49 @@
# Create RootDN first:
dn: @SUFFIX@
objectClass: organization
objectClass: top
o: @ORGANIZATION@
dn: ou=People,@SUFFIX@
ou: people
objectClass: organizationalUnit
objectClass: top
description: People associated with @ORGANIZATION@
dn: ou=Services,ou=People,@SUFFIX@
ou: services
objectClass: organizationalUnit
objectClass: top
description: Accounts for services of @ORGANIZATION@
dn: ou=Groups,@SUFFIX@
ou: groups
objectClass: organizationalUnit
objectClass: top
description: User groups within @ORGANIZATION@
dn: ou=System,ou=Groups,@SUFFIX@
ou: system
objectClass: organizationalUnit
objectClass: top
description: Posix groups within @ORGANIZATION@
dn: cn=user,ou=System,ou=Groups,@SUFFIX@
cn: user
objectClass: posixGroup
objectClass: top
gidNumber: 30000
description: Default system user group
dn: ou=Domains,@SUFFIX@
ou: domains
objectClass: organizationalUnit
objectClass: top
description: Domains controlled by @ORGANIZATION@
dn: ou=Policies,@SUFFIX@
ou: policies
objectClass: organizationalUnit
objectClass: top
description: Password policies for @ORGANIZATION@