Initial import

This commit is contained in:
sebthom 2020-04-02 13:03:15 +02:00
parent b3fc7301be
commit 985bca6429
28 changed files with 1559 additions and 203 deletions

43
.gitattributes vendored Normal file
View file

@ -0,0 +1,43 @@
# from https://github.com/alexkaratarakis/gitattributes/blob/master/Java.gitattributes
# Handle line endings automatically for files detected as text
# and leave all files detected as binary untouched.
* text=auto
#
# The above will handle all files NOT found below
#
# These files are text and should be normalized (Convert crlf => lf)
*.css text
*.df text
*.htm text
*.html text
*.java text
*.js text
*.json text
*.jsp text
*.jspf text
*.jspx text
*.properties text
*.sh text
*.tld text
*.txt text
*.tag text
*.tagx text
*.xml text
*.yml text
# These files are binary and should be left untouched
# (binary is a macro for -text -diff)
*.class binary
*.dll binary
*.ear binary
*.gif binary
*.ico binary
*.jar binary
*.jpg binary
*.jpeg binary
*.png binary
*.so binary
*.war binary

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
/.project
/.settings
/.svn
**/.*.md.html

39
.travis.yml Normal file
View file

@ -0,0 +1,39 @@
# https://github.com/travis-ci/travis-yml/blob/master/schema.json
language: bash # using 'bash' instead of 'minimal' to prevent https://travis-ci.community/t/job-stuck-booting/4976
sudo: true
services:
- docker
cache:
directories:
- $HOME/.trivy/cache
env:
global:
DOCKER_REGISTRY=docker.io
DOCKER_REPO=vegardit/openldap
TRIVY_CACHE_DIR=$HOME/.trivy/cache
before_script:
# workaround for
# - https://stackoverflow.com/questions/34130613/how-to-make-travis-ci-work-with-a-local-git-branch-instead-of-a-specific-commit
# - https://unhashable.com/getting-the-current-branch-name-during-a-pull-request-in-travis-ci/
- if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then
export GIT_BRANCH="$TRAVIS_BRANCH";
else
export GIT_BRANCH="$TRAVIS_PULL_REQUEST_BRANCH";
fi
#- printenv | sort
- mkdir -p "$TRIVY_CACHE_DIR"
script:
- echo "$DOCKER_PASSWORD" | docker login -u="$DOCKER_USERNAME" "$DOCKER_REGISTRY" --password-stdin &&
if [[ "$TRAVIS_BRANCH" == "master" ]]; then
DOCKER_PUSH=1 bash ./build-image.sh;
else
bash ./build-image.sh;
fi
- ls -l $TRIVY_CACHE_DIR/trivy

7
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,7 @@
# Contributing to docker-openldap
Thanks for contributing to docker-openldap!
## License
By contributing your code, you agree to license your contribution under the [Apache License 2.0](LICENSE.txt).

201
LICENSE
View file

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

201
LICENSE.txt Normal file
View file

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

201
README.md
View file

@ -1,2 +1,199 @@
# docker-openldap
Opinionated docker image based on minideb (Debian 10 "buster") to run an OpenLDAP 2.4 server.
# vegardit/openldap <a href="https://github.com/vegardit/docker-openldap/" title="GitHub Repo"><img height="30" src="https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/github.svg?sanitize=true"></a>
[![Build Status](https://travis-ci.com/vegardit/docker-openldap.svg?branch=master "Tavis CI")](https://travis-ci.com/vegardit/docker-openldap)
[![License](https://img.shields.io/github/license/vegardit/docker-openldap.svg?label=license)](#license)
[![Docker Pulls](https://img.shields.io/docker/pulls/vegardit/openldap.svg)](https://hub.docker.com/r/vegardit/openldap)
[![Docker Stars](https://img.shields.io/docker/stars/vegardit/openldap.svg)](https://hub.docker.com/r/vegardit/openldap)
[![Docker Image Size](https://images.microbadger.com/badges/image/vegardit/openldap.svg)](https://hub.docker.com/r/vegardit/openldap)
1. [What is it?](#what-is-it)
1. [Configuration](#config)
1. [Initial configuration](#initial-config)
1. [Customizing the Password Policy](#ppolicy)
1. [Changing UID/GID of OpenLDAP service user](#uidgid)
1. [Periodic LDAP Backup](#backup)
1. [Synchronizing timezone/time with docker host](#timesync)
1. [Performance tuning](#performance-tuning)
1. [Troubleshooting](#troubleshooting)
1. [References](#references)
1. [License](#license)
## <a name="what-is-it"></a>What is it?
Opinionated docker image based on [minideb](https://github.com/bitnami/minideb) (Debian 10 "buster") to run an [OpenLDAP 2.4](https://www.openldap.org/doc/admin24/) server.
To keep the image light and simple, it does not configure TLS. Instead we recommend configuring a [Traefik 2.x](https://traefik.io) [TCP service](https://docs.traefik.io/routing/services/#configuring-tcp-services) with e.g. an auto-renewing [Let's Encrypt configuration](https://docs.traefik.io/https/acme/) in front of the OpenLDAP service.
## <a name="config"></a>Configuration
### <a name="initial-config"></a>Initial configuration
Various parts of the LDAP server can be configured via environment variables. All environment variables starting with `LDAP_INIT_`
are only evaluated on the **first** container launch. Changing their values later has no effect when restarting or updating the container.
To customize the initial configuration you can set the following environment variables:
```sh
LDAP_INIT_ORG_DN='dc=example,dc=com'
LDAP_INIT_ORG_NAME='Example Corporation'
LDAP_INIT_ADMIN_GROUP_DN='cn=ldapadmins,ou=Groups,${LDAP_INIT_ORG_DN}'
LDAP_INIT_ROOT_USER_DN='uid=admin,${LDAP_INIT_ORG_DN}'
LDAP_INIT_ROOT_USER_PW='changeit'
LDAP_INIT_RFC2307BIS_SCHEMA=0 # 0=use NIS (RFC2307) schema, 1=use RFC2307bis schema
```
Environment variables can for example be set using `docker run` with `-e`, e.g.
```sh
docker run -itd \
-e LDAP_INIT_ORG_DN='o=yourorg' \
-e LDAP_INIT_ROOT_USER_PW='newpassword' \
-e LDAP_INIT_ORG_NAME='Company Inc' \
-e LDAP_INIT_PPOLICY_PW_MIN_LENGTH='12' \
vegardit/openldap
```
Alternatively you can use an [env-file](https://docs.docker.com/compose/env-file/) to store all changed variables and use the option `--env-file` with `docker run`, e.g.:
```sh
docker run -itd --env-file environment vegardit/openldap
```
In environment file values must not be enclosed using quotes (`'` or `"`), please remove them. See this example file: [example/docker/example.env].
The initial LDAP tree structure is imported from [/opt/ldifs/init_org_tree.ldif](ldifs/init_org_tree.ldif).
You can mount a custom file at `/opt/ldifs/init_org_tree.ldif` if you require changes.
LDAP entries (users, groups) are imported from [/opt/ldifs/init_org_entries.ldif](ldifs/init_org_entries.ldif).
You can mount a custom file at `/opt/ldifs/init_org_entries.ldif` if you require changes.
### <a name="ppolicy"></a>Customizing the Password Policy
On **initial** container launch, the [password policy](https://www.openldap.org/doc/admin24/overlays.html#Password%20Policies) is imported from [/opt/ldifs/init_org_ppolicy.ldif](ldifs/init_org_ppolicy.ldif)
The following parameters can be modified via environment variables **before** initial container launch:
```sh
LDAP_INIT_PPOLICY_DEFAULT_DN='cn=DefaultPasswordPolicy,ou=Policies,${LDAP_INIT_ORG_DN}'
LDAP_INIT_PPOLICY_PW_MIN_LENGTH=8
LDAP_INIT_PPOLICY_MAX_FAILURES=3
LDAP_INIT_PPOLICY_LOCKOUT_DURATION=300
```
If more customizations are required, simply mount a custom policy file at `/opt/ldifs/init_org_ppolicy.ldif` **before** initial container launch.
**Password Quality Checker:**
[pqChecker](https://www.meddeb.net/pqchecker/) is configured as default password quality checker using the rule `0|01010101` with
the following meaning:
|Pos. |Value |Effective Rule
|----:|:-----:|:----------
|0-1 | `0\|`|Don't broadcast passwords.
|2-4 | `01` |Minimum 1 uppercase character.
|5-6 | `01` |Minimum 1 lowercase character.
|7-8 | `01` |Minimum 1 digit.
|9-10 | `01` |Minimum 1 special character.
|11-..| empty | No characters are disallowed in passwords.
The pqChecker rule syntax is explained here in more detail: https://www.meddeb.net/pqchecker/?Idx=2
A custom rule can be provided via an environment variable, e.g.:
```sh
LDAP_PPOLICY_PQCHECKER_RULE='0|01020101@!+-#'
```
### <a name="uidgid"></a>Changing UID/GID of OpenLDAP service user
The UID/GID of the user running the OpenLDAP service can be aligned with the docker host, using the environment variables
`LDAP_OPENLDAP_UID` and `LDAP_OPENLDAP_GID`.
During each container start it is verified that the given UID/GID matches the currently effective UID/GID. If not, the UID/GID
of the `openldap` user are changed accordingly and `chown` on `/etc/ldap` and `/var/lib/slapd` is executed before the OpenLDAP service is started.
### <a name="backup"></a>Periodic LDAP Backup
This image automatically generates a daily LDIF export at `2 a.m.` to `/var/lib/ldap/data.ldif`.
The following environment variables can be used to configure the automatic LDAP backup:
```bash
LDAP_BACKUP_TIME='02:00' # Format is "HH:MM", i.e. 24-hour format with minute precision
LDAP_BACKUP_FILE='/var/lib/ldap/data.ldif'
```
To disable automatic backup set an empty value for the environment variable `LDAP_BACKUP_TIME`.
### <a name="timesync"></a>Synchronizing timezone/time with docker host
To use the same timezone and/or time of the docker host you can run the docker image with `--volume /etc/localtime:/etc/localtime:ro --volume /etc/timezone:/etc/timezone:ro`
Docker compose file example:
```yaml
version: '3.7'
services:
openldap:
image: vegardit/openldap:latest
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
```
### <a name="performance-tuning"></a>Performance tuning
#### DB Indexes
The database indexes that are configured during initial container launch are imported from [/opt/ldifs/init_backend_indexes.ldif](ldifs/init_mdb_indexes.ldif)
To use other indexes, simply mount a custom file at `/opt/ldifs/init_backend_indexes.ldif` **before** initial container launch.
#### Memory usage
The maximum number of open files is set to `1024` by default to prevent excessive RAM consumption as reported [here](https://github.com/docker/docker/issues/8231).
The following environment variable can be used to increase this limit:
```sh
LDAP_NOFILE_LIMIT=2048
```
### <a name="troubleshooting"></a>Troubleshooting
The slapd service logs to stdout. You can change the active log levels by setting this environment variable:
```sh
LDAP_LOG_LEVELS='Config Stats'
```
The following [log levels](https://www.openldap.org/doc/admin24/slapdconfig.html#loglevel%20%3Clevel%3E) are available:
```
Any (-1) enable all debugging
Trace (1) trace function calls
Packets (2) debug packet handling
Args (4) heavy trace debugging
Conns (8) connection management
BER (16) print out packets sent and received
Filter (32) search filter processing
Config (64) configuration processing
ACL (128) access control list processing
Stats (256) stats log connections/operations/results
Stats2 (512) stats log entries sent
Shell (1024) print communication with shell backends
Parse (2048) print entry parsing debugging
Sync (16384) syncrepl consumer processing
None (32768) only messages that get logged whatever log level is set
```
## <a name="references"></a>References
- OpenLDAP Software 2.4 Administrator's Guide https://www.openldap.org/doc/admin24/guide.html
- OpenLDAP Online Configuration Reference https://tylersguides.com/guides/openldap-online-configuration-reference/
- slapd-config(5) - Linux man page https://linux.die.net/man/5/slapd-config
## <a name="license"></a>License
All files in this repository are released under the [Apache License 2.0](LICENSE.txt).

11
build-debug-image.sh Normal file
View file

@ -0,0 +1,11 @@
#!/usr/bin/env bash
#
# Copyright 2019-2020 by Vegard IT GmbH, Germany, https://vegardit.com
# SPDX-License-Identifier: Apache-2.0
#
# @author Sebastian Thomschke, Vegard IT GmbH
#
# https://github.com/vegardit/docker-openldap
#
bash "$(dirname "$0")/build-image.sh" --build-arg DEBUG_BUILD=1

77
build-image.sh Normal file
View file

@ -0,0 +1,77 @@
#!/usr/bin/env bash
#
# Copyright 2019-2020 by Vegard IT GmbH, Germany, https://vegardit.com
# SPDX-License-Identifier: Apache-2.0
#
# @author Sebastian Thomschke, Vegard IT GmbH
#
# https://github.com/vegardit/docker-openldap
#
set -e -x
if [ ! -n "$BASH" ]; then /usr/bin/env bash "$0" "$@"; exit; fi
DOCKER_REGISTRY=${DOCKER_REGISTRY:-docker.io}
DOCKER_REPO=${DOCKER_REPO:-vegardit/openldap}
last_commit_date=$(date -d @$(git log -1 --format="%at") --utc +"%Y%m%d_%H%M%S")
docker build $(dirname $0)/image \
--compress \
--build-arg GIT_BRANCH="${GIT_BRANCH:-$(git rev-parse --abbrev-ref HEAD)}" \
--build-arg GIT_COMMIT_DATE="$(date -d @$(git log -1 --format='%at') --utc +'%Y-%m-%d %H:%M:%S UTC')" \
--build-arg GIT_COMMIT_HASH="$(git rev-parse --short HEAD)" \
--build-arg GIT_REPO_URL="$(git config --get remote.origin.url)" \
`# using the current date as value for BASE_LAYER_CACHE_KEY, i.e. the base layer cache (that holds system packages with security updates) will be invalidate once per day` \
--build-arg BASE_LAYER_CACHE_KEY=$(date +%Y%m%d) \
-t $DOCKER_REPO:latest \
-t $DOCKER_REPO:latest-buster \
-t $DOCKER_REPO:${last_commit_date} \
-t $DOCKER_REPO:${last_commit_date}-buster \
"$@"
#
# perform security audit using https://github.com/aquasecurity/trivy
#
mkdir -p ${TRIVY_CACHE_DIR:-$HOME/.trivy/cache}
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ${TRIVY_CACHE_DIR:-$HOME/.trivy/cache}:/root/.cache/ \
aquasec/trivy --no-progress --exit-code 0 --severity HIGH,CRITICAL $DOCKER_REPO:${last_commit_date}
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ${TRIVY_CACHE_DIR:-$HOME/.trivy/cache}:/root/.cache/ \
aquasec/trivy --no-progress --ignore-unfixed --exit-code 1 --severity HIGH,CRITICAL $DOCKER_REPO:${last_commit_date}
sudo chown -R $USER:$(id -gn) $TRIVY_CACHE_DIR || true
#
# determine effective LDAP version and apply tags
#
ldap_version=$(docker run $DOCKER_REPO:${last_commit_date} "dpkg -s slapd | grep 'Version:' | grep -oP 'Version: \K\d+\.\d+\.\d+'")
docker image tag $DOCKER_REPO:${last_commit_date} $DOCKER_REPO:${ldap_version%.*}.x #2.4.x
docker image tag $DOCKER_REPO:${last_commit_date} $DOCKER_REPO:${ldap_version%.*}.x-buster #2.4.x
docker image tag $DOCKER_REPO:${last_commit_date} $DOCKER_REPO:${ldap_version%%.*}.x #2.x
docker image tag $DOCKER_REPO:${last_commit_date} $DOCKER_REPO:${ldap_version%%.*}.x-buster #2.x
#
# push image with tags to remote docker registry
#
if [[ "${DOCKER_PUSH:-0}" == "1" ]]; then
docker image tag $DOCKER_REPO:${last_commit_date} $DOCKER_REGISTRY/$DOCKER_REPO:latest
docker image tag $DOCKER_REPO:${last_commit_date} $DOCKER_REGISTRY/$DOCKER_REPO:latest-buster
docker image tag $DOCKER_REPO:${last_commit_date} $DOCKER_REGISTRY/$DOCKER_REPO:${ldap_version} #2.4.47
docker image tag $DOCKER_REPO:${last_commit_date} $DOCKER_REGISTRY/$DOCKER_REPO:${ldap_version}-buster #2.4.47
docker image tag $DOCKER_REPO:${last_commit_date} $DOCKER_REGISTRY/$DOCKER_REPO:${ldap_version%.*}.x #2.4.x
docker image tag $DOCKER_REPO:${last_commit_date} $DOCKER_REGISTRY/$DOCKER_REPO:${ldap_version%.*}.x-buster #2.4.x
docker image tag $DOCKER_REPO:${last_commit_date} $DOCKER_REGISTRY/$DOCKER_REPO:${ldap_version%%.*}.x #2.x
docker image tag $DOCKER_REPO:${last_commit_date} $DOCKER_REGISTRY/$DOCKER_REPO:${ldap_version%%.*}.x-buster #2.x
docker push $DOCKER_REGISTRY/$DOCKER_REPO:latest
docker push $DOCKER_REGISTRY/$DOCKER_REPO:latest-buster
docker push $DOCKER_REGISTRY/$DOCKER_REPO:${ldap_version} #2.4.47
docker push $DOCKER_REGISTRY/$DOCKER_REPO:${ldap_version}-buster #2.4.47
docker push $DOCKER_REGISTRY/$DOCKER_REPO:${ldap_version%.*}.x #2.4.x
docker push $DOCKER_REGISTRY/$DOCKER_REPO:${ldap_version%.*}.x-buster #2.4.x
docker push $DOCKER_REGISTRY/$DOCKER_REPO:${ldap_version%%.*}.x #2.x
docker push $DOCKER_REGISTRY/$DOCKER_REPO:${ldap_version%%.*}.x-buster #2.x
fi

View file

@ -0,0 +1,66 @@
#############################
# @author Sebastian Thomschke, Vegard IT GmbH
#############################
version: '3.7'
# https://docs.docker.com/compose/compose-file/
services:
ldap_service:
# https://github.com/vegardit/docker-openldap
image: vegardit/openldap:latest # https://hub.docker.com/r/vegardit/openldap
environment:
#DEBUG_RUN_SH: 1
LDAP_INIT_ORG_DN: o=example.com
LDAP_INIT_ORG_NAME: Example Inc.
LDAP_INIT_ROOT_USER_DN: uid=admin,o=example.com
LDAP_INIT_ROOT_USER_PW: CHANGE@it
LDAP_BACKUP_TIME: # disable backup by setting to empty string
ports:
- 389:389
volumes:
- ./ldifs/init_org_entries.ldif:/opt/ldifs/init_org_entries.ldif:ro
- ./ldifs/init_org_tree.ldif:/opt/ldifs/init_org_tree.ldif:ro
ldap_ui:
# https://github.com/alekseydemidov/pla-ssp
image: netflyer/openldap-ui:latest # https://hub.docker.com/r/netflyer/openldap-ui
ports:
- 8080:8080
- 8081:8081
environment:
###############################
# PHP LDAP Admin (Port 8080)
###############################
PHPLDAPADMIN_LDAP_BASE: o=example.com
PHPLDAPADMIN_LDAP_CLIENT_TLS: 'false'
PHPLDAPADMIN_LDAP_HOSTS: ldap_service
###############################
# SelfService Password (Port 8081) https://github.com/ltb-project/self-service-password
###############################
DEBUG_MODE: 'false'
#LDAP connection https://ltb-project.org/documentation/self-service-password/1.3/config_ldap
LDAP_URL: ldap://ldap_service
LDAP_BASE_DN: ou=Users,o=example.com
LDAP_USER_DN: uid=ldapbind,ou=TechnicalAccounts,ou=Users,o=example.com
LDAP_USER_PASSWORD: CHANGE@it
LDAP_FILTER: '(\&(objectClass=inetOrgPerson)(uid={login}))' # backslash is mandatory!
LDAP_LOGIN_ATTRIBUTE: 'uid'
LDAP_FULLNAME_ATTRIBUTE: 'cn'
CHANGE_SSHKEY: 'true'
MAIL_ADDRESS_USE_LDAP: 'true'
USE_TOKENS: 'false' # don't use "forgot my password" links
USE_QUESTIONS: 'false' # https://ltb-project.org/documentation/self-service-password/latest/config_questions
# Password policy https://ltb-project.org/documentation/self-service-password/1.3/config_ppolicy
PWD_MIN_LENGTH: 8
PWD_MAX_LENGTH: 32
PWD_MIN_LOWER: 1
PWD_MIN_UPPER: 1
PWD_MIN_DIGIT: 1
PWD_MIN_SPECIAL: 1
PWD_NO_REUSE: 'false'
PWD_SHOW_POLICY: 'always'
PWD_SHOW_POLICY_POS: 'below'
USE_PWNEDPASSWORD: 'false'

View file

@ -0,0 +1,68 @@
version: 1
##############################
# Employees
# slappasswd -h {SHA} -s changeit
##############################
dn: uid=alice,ou=Employees,ou=Users,${LDAP_INIT_ORG_DN}
ou: Employees
ou: Users
description: Alice Young
objectClass: top
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: ldapPublicKey
uid: alice
cn: Alice Young
sn: Young
givenName: Alice
mail: alice@example.com
userPassword: CHANGE@it
sshPublicKey:
dn: uid=bob,ou=Employees,ou=Users,${LDAP_INIT_ORG_DN}
ou: Employees
ou: Users
description: Bob Old
objectClass: top
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: ldapPublicKey
uid: bob
cn: Bob Old
sn: Old
givenName: Bob
mail: bob@example.com
userPassword: CHANGE@it
sshPublicKey:
##############################
# Technical Accounts
##############################
dn: uid=ldapbind,ou=TechnicalAccounts,ou=Users,${LDAP_INIT_ORG_DN}
ou: TechnicalAccounts
ou: Users
description: ldapbind user
objectClass: top
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
uid: ldapbind
cn: ldapbind
sn: ldapbind
userPassword: CHANGE@it
##############################
# Groups
##############################
dn: cn=ldapadmins,ou=Groups,${LDAP_INIT_ORG_DN}
ou: Groups
description: LDAP Administrators Group
objectClass: top
objectClass: groupOfUniqueNames
cn: ldapadmins
uniqueMember: uid=alice,ou=Employees,ou=Users,${LDAP_INIT_ORG_DN}
uniqueMember: uid=bob,ou=Employees,ou=Users,${LDAP_INIT_ORG_DN}

View file

@ -0,0 +1,43 @@
version: 1
##############################
# LDAP tree definition
##############################
dn: ${LDAP_INIT_ORG_DN}
description: ${LDAP_INIT_ORG_NAME}
objectClass: top
objectClass: organization
${LDAP_INIT_ORG_DN_ATTR}
dn: ou=Groups,${LDAP_INIT_ORG_DN}
ou: Groups
description: Groups
objectClass: top
objectClass: organizationalUnit
dn: ou=Users,${LDAP_INIT_ORG_DN}
ou: Users
description: Users Accounts
objectClass: top
objectClass: organizationalUnit
dn: ou=Employees,ou=Users,${LDAP_INIT_ORG_DN}
ou: Employees
ou: Users
description: Internal Users (Employees)
objectClass: top
objectClass: organizationalUnit
dn: ou=External,ou=Users,${LDAP_INIT_ORG_DN}
ou: External
ou: Users
description: External Users (Contractors, Customers)
objectClass: top
objectClass: organizationalUnit
dn: ou=TechnicalAccounts,ou=Users,${LDAP_INIT_ORG_DN}
ou: TechnicalAccounts
ou: Users
description: Technical Accounts
objectClass: top
objectClass: organizationalUnit

View file

@ -0,0 +1,24 @@
#See https://docs.docker.com/compose/env-file/
#DEBUG_RUN_SH=0
#INIT_SH_FILE=
LDAP_INIT_ORG_DN=o=yourorg
LDAP_INIT_ORG_NAME=Example Inc
#LDAP_INIT_ADMIN_GROUP_DN=cn=ldapadmins,ou=Groups,o=yourorg
#LDAP_INIT_ROOT_USER_DN=uid=admin,o=yourorg
LDAP_INIT_ROOT_USER_PW=password
#LDAP_INIT_PPOLICY_DEFAULT_DN=cn=DefaultPasswordPolicy,ou=Policies,o=yourorg
LDAP_INIT_PPOLICY_PW_MIN_LENGTH=8
#LDAP_INIT_PPOLICY_MAX_FAILURES=3
#LDAP_INIT_PPOLICY_LOCKOUT_DURATION=300
#LDAP_INIT_RFC2307BIS_SCHEMA=0
#LDAP_PPOLICY_PQCHECKER_RULE=0|01010101
#LDAP_NOFILE_LIMIT=1024
#LDAP_LOG_LEVELS=Config Stats
# Format is "HH:MM", i.e. 24-hour format with minute precision
#LDAP_BACKUP_TIME=02:00
#LDAP_BACKUP_FILE=/var/lib/ldap/data.ldif

131
image/Dockerfile Normal file
View file

@ -0,0 +1,131 @@
# Copyright 2019-2020 by Vegard IT GmbH, Germany, https://vegardit.com
# SPDX-License-Identifier: Apache-2.0
#
# @author Sebastian Thomschke, Vegard IT GmbH
#
# https://github.com/vegardit/docker-openldap
#
# built daily:
# https://hub.docker.com/r/bitnami/minideb/tags?page=1&name=buster
FROM bitnami/minideb:buster
# built monthly:
# https://hub.docker.com/_/debian?tab=tags&page=1&name=buster-slim
# FROM debian:buster-slim
LABEL maintainer="Vegard IT GmbH (vegardit.com)"
# if set to 1 debug tools are added to the image (htop,less,mc,vim)
ARG DEBUG_BUILD=0
ARG PQCHECKER_URL=https://www.meddeb.net/pub/pqchecker/deb/8/pqchecker_2.0.0_amd64.deb
ARG PQCHECKER_MD5=c005ce596e97d13e39485e711dcbc7e1
ARG DEBIAN_FRONTEND=noninteractive
ARG LC_ALL=C
ARG BASE_LAYER_CACHE_KEY
SHELL ["/bin/bash", "-c"]
RUN \
apt-get update -y && \
# https://github.com/phusion/baseimage-docker/issues/319
apt-get install -y apt-utils 2> >( grep -v 'debconf: delaying package configuration, since apt-utils is not installed' >&2 ) && \
############################################################
if [ "${DEBUG_BUILD}" = "1" ]; then \
echo "Installing debugging tools..." && \
apt-get update -y && \
apt-get install --no-install-recommends -y libcomerr2 mc && \
apt-get install --no-install-recommends -y htop less procps vim && \
echo 'set ignorecase\n\
set showmatch\n\
set novisualbell\n\
set noerrorbells\n\
syntax enable\n\
set mouse-=a' > ~/.vimrc; \
fi && \
############################################################
echo "Installing slapd..." && \
echo 'slapd slapd/root_password password whatever' | debconf-set-selections && \
echo 'slapd slapd/root_password_again password whatever' | debconf-set-selections && \
apt-get install --no-install-recommends -y slapd ldap-utils && \
echo "OpenLDAP $(apt-cache show slapd | grep Version)" >> /opt/build_info && \
# workaround for 'service slapd stop' not working, see https://stackoverflow.com/a/58792698/5116073
sed -i 's/--exec $SLAPD 2/--name slapd 2/' /etc/init.d/slapd && \
############################################################
echo "Installing pqChecker password quality checker module..." && \
# https://www.meddeb.net/pqchecker/
apt-get install --no-install-recommends -y curl && \
curl -k -o /tmp/pqchecker.deb -SL "${PQCHECKER_URL}" && \
echo "${PQCHECKER_MD5} /tmp/pqchecker.deb" | md5sum -c - && \
dpkg -i /tmp/pqchecker.deb && \
rm /tmp/pqchecker.deb && \
apt-get remove --auto-remove -y curl && \
############################################################
echo "Moving config and data directories..." && \
mv /etc/ldap/slapd.d /etc/ldap/slapd.d_orig && \
mkdir /etc/ldap/slapd.d && \
mv /var/lib/ldap /var/lib/ldap_orig && \
mkdir /var/lib/ldap && \
############################################################
echo "apt-get clean up..." && \
apt-get clean autoclean && \
apt-get autoremove --purge -y && \
############################################################
echo "Removing logs, caches and temp files..." && \
rm -rf /var/cache/{apt,debconf} \
/var/lib/apt/lists/* \
/var/log/{apt,alternatives.log,bootstrap.log,dpkg.log} \
/tmp/* /var/tmp/*
VOLUME ["/etc/ldap/slapd.d", "/var/lib/ldap"]
ARG GIT_REPO_URL
ARG GIT_BRANCH
ARG GIT_COMMIT_HASH
ARG GIT_COMMIT_DATE
LABEL \
org.label-schema.vcs-ref=$GIT_COMMIT_HASH \
org.label-schema.vcs-url="https://github.com/vegardit/docker-openldap"
RUN \
echo "GIT_REPO: $GIT_REPO_URL" > /opt/build_info && \
echo "GIT_BRANCH: $GIT_BRANCH" >> /opt/build_info && \
echo "GIT_COMMIT: $GIT_COMMIT_HASH @ $GIT_COMMIT_DATE" >> /opt/build_info && \
cat /opt/build_info
COPY ldifs /opt/ldifs
COPY run.sh /opt/run.sh
# Default configuration: can be overridden at the docker command line
ENV \
DEBUG_RUN_SH=0 \
INIT_SH_FILE='' \
LDAP_INIT_ORG_DN='o=example.com' \
LDAP_INIT_ORG_NAME='Example Corporation' \
LDAP_INIT_ADMIN_GROUP_DN='cn=ldapadmins,ou=Groups,${LDAP_INIT_ORG_DN}' \
LDAP_INIT_ROOT_USER_DN='uid=admin,${LDAP_INIT_ORG_DN}' \
LDAP_INIT_ROOT_USER_PW='changeit' \
LDAP_INIT_PPOLICY_DEFAULT_DN='cn=DefaultPasswordPolicy,ou=Policies,${LDAP_INIT_ORG_DN}' \
LDAP_INIT_PPOLICY_PW_MIN_LENGTH=8 \
LDAP_INIT_PPOLICY_MAX_FAILURES=3 \
LDAP_INIT_PPOLICY_LOCKOUT_DURATION=300 \
LDAP_INIT_RFC2307BIS_SCHEMA=0 \
LDAP_PPOLICY_PQCHECKER_RULE='0|01010101' \
LDAP_NOFILE_LIMIT=1024 \
LDAP_LOG_LEVELS='Config Stats' \
# Format is "HH:MM", i.e. 24-hour format with minute precision
LDAP_BACKUP_TIME='02:00' \
LDAP_BACKUP_FILE='/var/lib/ldap/data.ldif' \
LDAP_OPENLDAP_UID='' \
LDAP_OPENLDAP_GID=''
EXPOSE 389
ENTRYPOINT ["/bin/sh", "-c"]
# exec is required for propagating SIGTERM from docker to child process
CMD ["exec /bin/bash /opt/run.sh"]

View file

@ -0,0 +1,12 @@
version: 1
# Global Database Options @ https://linux.die.net/man/5/slapd-config
dn: olcDatabase={-1}frontend,cn=config
changetype: modify
replace: olcPasswordHash
olcPasswordHash: {SSHA}
-
# maximum number of seconds (in real time) slapd will spend answering a search request
replace: olcTimeLimit
olcTimeLimit: 60

20
image/ldifs/init_mdb.ldif Normal file
View file

@ -0,0 +1,20 @@
version: 1
# General Database Options @ https://linux.die.net/man/5/slapd-config
dn: olcDatabase={1}mdb,cn=config
changetype: modify
########################
# configure Base DN
########################
replace: olcSuffix
olcSuffix: ${LDAP_INIT_ORG_DN}
-
########################
# configure root user
########################
replace: olcRootDN
olcRootDN: ${LDAP_INIT_ROOT_USER_DN}
-
replace: olcRootPW
olcRootPW: ${LDAP_INIT_ROOT_USER_PW_HASHED}

View file

@ -0,0 +1,37 @@
version: 1
# General Database Options @ https://linux.die.net/man/5/slapd-config
dn: olcDatabase={1}mdb,cn=config
changetype: modify
########################
# configure ACLs
########################
replace: olcAccess
olcAccess: {0}to attrs=userPassword
by dn="${LDAP_INIT_ROOT_USER_DN}" write
by group/groupOfUniqueNames/uniqueMember="${LDAP_INIT_ADMIN_GROUP_DN}" write
by self write
by anonymous auth
by * none
olcAccess: {1}to attrs=shadowLastChange
by self write
by users read
by * none
olcAccess: {2}to attrs=sshPublicKey
by dn="${LDAP_INIT_ROOT_USER_DN}" write
by group/groupOfUniqueNames/uniqueMember="${LDAP_INIT_ADMIN_GROUP_DN}" write
by self write
by users read
by * none
# This ACL gives incoming connections the ability to read the rootDSE.
# It is important to allow this, as clients may need to obtain information from the base level (such as your supported SASL Mechanisms).
# The ".base" portion of the ACL restricts clients to querying only the top level
olcAccess: {3}to dn.base=""
by * read
olcAccess: {4}to *
by dn="${LDAP_INIT_ROOT_USER_DN}" write
by group/groupOfUniqueNames/uniqueMember="${LDAP_INIT_ADMIN_GROUP_DN}" write
by users read
by anonymous auth
by * none

View file

@ -0,0 +1,15 @@
version: 1
# General Database Options @ https://linux.die.net/man/5/slapd-config
dn: olcDatabase={1}mdb,cn=config
changetype: modify
########################
# configure DB indexes
########################
replace: olcDbIndex
olcDbIndex: objectClass pres,eq
olcDbIndex: uid,mail pres,eq
olcDbIndex: uidNumber,gidNumber eq
olcDbIndex: cn,givenName,sn,ou pres,eq,approx,sub
olcDbIndex: member,memberUid,memberOf,uniqueMember pres,eq

View file

@ -0,0 +1,31 @@
version: 1
dn: cn=module{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad: memberof
olcModuleLoad: refint
dn: olcOverlay=memberof,olcDatabase={1}mdb,cn=config
objectClass: top
objectClass: olcConfig
objectClass: olcOverlayConfig
objectClass: olcMemberOf
olcOverlay: memberof
olcMemberOfDangling: ignore
olcMemberOfRefInt: TRUE
olcMemberOfGroupOC: groupOfUniqueNames
olcMemberOfMemberAD: uniqueMember
olcMemberOfMemberOfAD: memberOf
dn: olcOverlay=refint,olcDatabase={1}mdb,cn=config
objectClass: top
objectClass: olcConfig
objectClass: olcOverlayConfig
objectClass: olcRefintConfig
olcOverlay: refint
olcRefintAttribute: owner
olcRefintAttribute: manager
olcRefintAttribute: member
olcRefintAttribute: memberOf
olcRefintAttribute: uniqueMember

View file

@ -0,0 +1,18 @@
version: 1
dn: cn=module{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad: ppolicy
dn: olcOverlay=ppolicy,olcDatabase={1}mdb,cn=config
objectClass: top
objectClass: olcConfig
objectClass: olcOverlayConfig
objectClass: olcPPolicyConfig
olcOverlay: ppolicy
olcPPolicyDefault: ${LDAP_INIT_PPOLICY_DEFAULT_DN}
olcPPolicyHashCleartext: TRUE
# return AccountLocked instead of InvalidCredentials error:
olcPPolicyUseLockout: TRUE
olcPPolicyForwardUpdates: FALSE

View file

@ -0,0 +1,18 @@
version: 1
dn: cn=module{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad: unique
dn: olcOverlay=unique,olcDatabase={1}mdb,cn=config
objectClass: top
objectClass: olcConfig
objectClass: olcOverlayConfig
objectClass: olcUniqueConfig
olcOverlay: unique
olcUniqueURI: ldap:///${LDAP_INIT_ORG_DN}?cn?sub
olcUniqueURI: ldap:///${LDAP_INIT_ORG_DN}?uid?sub
olcUniqueURI: ldap:///ou=Users,${LDAP_INIT_ORG_DN}?mail?sub
olcUniqueURI: ldap:///ou=Users,${LDAP_INIT_ORG_DN}?gidNumber?sub
olcUniqueURI: ldap:///ou=Users,${LDAP_INIT_ORG_DN}?uidNumber?sub

View file

@ -0,0 +1,95 @@
version: 1
##############################
# Internal Users
##############################
dn: uid=employee1,ou=Internal,ou=Users,${LDAP_INIT_ORG_DN}
ou: Internal
ou: Users
description: Employee 1
objectClass: top
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: ldapPublicKey
uid: employee1
cn: Employee1
sn: Employee1
givenName: Employee1
mail: employee1@example.com
userPassword: changeit
##############################
# External Users
##############################
dn: uid=guest1,ou=External,ou=Users,${LDAP_INIT_ORG_DN}
ou: External
ou: Users
description: Guest 1
objectClass: top
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
uid: guest1
cn: Guest1
sn: Guest1
givenName: Guest1
mail: guest1@example.com
userPassword: changeit
##############################
# Technical Users
##############################
dn: uid=machine1,ou=TechnicalAccounts,ou=Users,${LDAP_INIT_ORG_DN}
ou: External
ou: Users
description: Machine 1
objectClass: top
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: ldapPublicKey
uid: machine1
cn: Machine1
sn: Machine1
givenName: Machine1
mail: machine1@example.com
userPassword: changeit
##############################
# Groups
##############################
dn: cn=ldapadmins,ou=Groups,${LDAP_INIT_ORG_DN}
ou: Groups
objectClass: top
objectClass: groupOfUniqueNames
cn: ldapadmins
description: Ldap Admin Group
uniqueMember: uid=employee1,ou=External,ou=Users,${LDAP_INIT_ORG_DN}
dn: cn=employees,ou=Groups,${LDAP_INIT_ORG_DN}
ou: Groups
objectClass: top
objectClass: groupOfUniqueNames
cn: employees
description: Employees Group
uniqueMember: uid=employee1,ou=External,ou=Users,${LDAP_INIT_ORG_DN}
dn: cn=guests,ou=Groups,${LDAP_INIT_ORG_DN}
ou: Groups
objectClass: top
objectClass: groupOfUniqueNames
cn: guests
description: Guests Group
uniqueMember: uid=guest1,ou=External,ou=Users,${LDAP_INIT_ORG_DN}
dn: cn=machines,ou=Groups,${LDAP_INIT_ORG_DN}
ou: Groups
objectClass: top
objectClass: groupOfUniqueNames
cn: machines
description: Machines Group
uniqueMember: uid=machine1,ou=TechnicalAccounts,ou=Users,${LDAP_INIT_ORG_DN}

View file

@ -0,0 +1,40 @@
version: 1
##############################
# Password Policy
##############################
dn: ou=Policies,${LDAP_INIT_ORG_DN}
ou: Policies
objectClass: top
objectClass: organizationalUnit
dn: cn=DefaultPasswordPolicy,ou=Policies,${LDAP_INIT_ORG_DN}
objectClass: top
objectClass: device
objectClass: pwdPolicy
objectClass: pwdPolicyChecker
cn: DefaultPasswordPolicy
pwdAttribute: userPassword
# 0=reset count of consecutive password failures only on successful authentication
pwdFailureCountInterval: 0
# maximum number of consecutive password failures locking the account
pwdMaxFailure: ${LDAP_INIT_PPOLICY_MAX_FAILURES:-3}
pwdMinAge: 0
pwdMustChange: TRUE
# if TRUE user must send current password during password modification operation
pwdSafeModify: FALSE
# number of passwords maintained in a list of previously used passwords
pwdInHistory: 0
# number of further bind operations after a password has expired
pwdGraceAuthNLimit: 0
# account lock duration in seconds (300=5min)
pwdLockoutDuration: ${LDAP_INIT_PPOLICY_LOCKOUT_DURATION:-300}
pwdAllowUserChange: TRUE
#0=do not show expiration warning on bind
pwdExpireWarning: 0
pwdLockout: TRUE
pwdMaxAge: 0
# Password Quality
pwdMinLength: ${LDAP_INIT_PPOLICY_PW_MIN_LENGTH:-8}
pwdCheckQuality: 2
pwdCheckModule: /usr/lib/ldap/pqchecker.so

View file

@ -0,0 +1,43 @@
version: 1
##############################
# LDAP tree definition
##############################
dn: ${LDAP_INIT_ORG_DN}
description: ${LDAP_INIT_ORG_NAME}
objectClass: top
objectClass: organization
${LDAP_INIT_ORG_DN_ATTR}
dn: ou=Groups,${LDAP_INIT_ORG_DN}
ou: Groups
description: Groups
objectClass: top
objectClass: organizationalUnit
dn: ou=Users,${LDAP_INIT_ORG_DN}
ou: Users
description: Users Accounts
objectClass: top
objectClass: organizationalUnit
dn: ou=Internal,ou=Users,${LDAP_INIT_ORG_DN}
ou: Internal
ou: Users
description: Internal Users (Employees)
objectClass: top
objectClass: organizationalUnit
dn: ou=External,ou=Users,${LDAP_INIT_ORG_DN}
ou: External
ou: Users
description: External Users (Contractors, Customers)
objectClass: top
objectClass: organizationalUnit
dn: ou=TechnicalAccounts,ou=Users,${LDAP_INIT_ORG_DN}
ou: TechnicalAccounts
ou: Users
description: Technical Accounts
objectClass: top
objectClass: organizationalUnit

View file

@ -0,0 +1,15 @@
dn: cn=openssh-lpk,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: openssh-lpk
olcAttributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13
NAME 'sshPublicKey'
DESC 'MANDATORY: OpenSSH Public key'
EQUALITY octetStringMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
)
olcObjectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0
NAME 'ldapPublicKey'
DESC 'MANDATORY: OpenSSH LPK objectclass'
SUP top
AUXILIARY MAY ( sshPublicKey $ uid )
)

View file

@ -0,0 +1,53 @@
# https://tools.ietf.org/html/draft-howard-rfc2307bis-02
dn: cn=rfc2307bis,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: rfc2307bis
olcAttributeTypes: ( 1.3.6.1.1.1.1.2 NAME 'gecos' DESC 'The GECOS field; the common name' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.3 NAME 'homeDirectory' DESC 'The absolute path to the home directory' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.4 NAME 'loginShell' DESC 'The path to the login shell' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.5 NAME 'shadowLastChange' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.6 NAME 'shadowMin' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.7 NAME 'shadowMax' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.8 NAME 'shadowWarning' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.9 NAME 'shadowInactive' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.10 NAME 'shadowExpire' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.11 NAME 'shadowFlag' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.12 NAME 'memberUid' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcAttributeTypes: ( 1.3.6.1.1.1.1.13 NAME 'memberNisNetgroup' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcAttributeTypes: ( 1.3.6.1.1.1.1.14 NAME 'nisNetgroupTriple' DESC 'Netgroup triple' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcAttributeTypes: ( 1.3.6.1.1.1.1.15 NAME 'ipServicePort' DESC 'Service port number' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.16 NAME 'ipServiceProtocol' DESC 'Service protocol name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcAttributeTypes: ( 1.3.6.1.1.1.1.17 NAME 'ipProtocolNumber' DESC 'IP protocol number' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.18 NAME 'oncRpcNumber' DESC 'ONC RPC number' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.19 NAME 'ipHostNumber' DESC 'IPv4 addresses as a dotted decimal omitting leading zeros or IPv6 addresses as defined in RFC2373' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.1.1.1.20 NAME 'ipNetworkNumber' DESC 'IP network omitting leading zeros, eg. 192.168' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.21 NAME 'ipNetmaskNumber' DESC 'IP netmask omitting leading zeros, eg. 255.255.255.0' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.22 NAME 'macAddress' DESC 'MAC address in maximal, colon separated hex notation, eg. 00:00:92:90:ee:e2' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.1.1.1.23 NAME 'bootParameter' DESC 'rpc.bootparamd parameter' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.1.1.1.24 NAME 'bootFile' DESC 'Boot image name' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.1.1.1.26 NAME 'nisMapName' DESC 'Name of a generic NIS map' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{64} )
olcAttributeTypes: ( 1.3.6.1.1.1.1.27 NAME 'nisMapEntry' DESC 'A generic NIS entry' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.28 NAME 'nisPublicKey' DESC 'NIS public key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.29 NAME 'nisSecretKey' DESC 'NIS secret key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.30 NAME 'nisDomain' DESC 'NIS domain' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
olcAttributeTypes: ( 1.3.6.1.1.1.1.31 NAME 'automountMapName' DESC 'Automount Map Name' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.32 NAME 'automountKey' DESC 'Automount Key value' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
olcAttributeTypes: ( 1.3.6.1.1.1.1.33 NAME 'automountInformation' DESC 'Automount information' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
olcObjectClasses: ( 1.3.6.1.1.1.2.0 NAME 'posixAccount' DESC 'Abstraction of an account with POSIX attributes' SUP top AUXILIARY MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory ) MAY ( userPassword $ loginShell $ gecos $ description ) )
olcObjectClasses: ( 1.3.6.1.1.1.2.1 NAME 'shadowAccount' DESC 'Additional attributes for shadow passwords' SUP top AUXILIARY MUST uid MAY ( userPassword $ description $ shadowLastChange $ shadowMin $ shadowMax $ shadowWarning $ shadowInactive $ shadowExpire $ shadowFlag ) )
olcObjectClasses: ( 1.3.6.1.1.1.2.2 NAME 'posixGroup' DESC 'Abstraction of a group of accounts' SUP top AUXILIARY MUST gidNumber MAY ( userPassword $ memberUid $ description ) )
olcObjectClasses: ( 1.3.6.1.1.1.2.3 NAME 'ipService' DESC 'Abstraction an Internet Protocol service. Maps an IP port and protocol (such as tcp or udp) to one or more names; the distinguished value of the cn attribute denotes the services canonical name' SUP top STRUCTURAL MUST ( cn $ ipServicePort $ ipServiceProtocol ) MAY description )
olcObjectClasses: ( 1.3.6.1.1.1.2.4 NAME 'ipProtocol' DESC 'Abstraction of an IP protocol. Maps a protocol number to one or more names. The distinguished value of the cn attribute denotes the protocol canonical name' SUP top STRUCTURAL MUST ( cn $ ipProtocolNumber ) MAY description )
olcObjectClasses: ( 1.3.6.1.1.1.2.5 NAME 'oncRpc' DESC 'Abstraction of an Open Network Computing (ONC) [RFC1057] Remote Procedure Call (RPC) binding. This class maps an ONC RPC number to a name. The distinguished value of the cn attribute denotes the RPC service canonical name' SUP top STRUCTURAL MUST ( cn $ oncRpcNumber ) MAY description )
olcObjectClasses: ( 1.3.6.1.1.1.2.6 NAME 'ipHost' DESC 'Abstraction of a host, an IP device. The distinguished value of the cn attribute denotes the hosts canonical name. Device SHOULD be used as a structural class' SUP top AUXILIARY MUST ( cn $ ipHostNumber ) MAY ( userPassword $ l $ description $ manager ) )
olcObjectClasses: ( 1.3.6.1.1.1.2.7 NAME 'ipNetwork' DESC 'Abstraction of a network. The distinguished value of the cn attribute denotes the network canonical name' SUP top STRUCTURAL MUST ipNetworkNumber MAY ( cn $ ipNetmaskNumber $ l $ description $ manager ) )
olcObjectClasses: ( 1.3.6.1.1.1.2.8 NAME 'nisNetgroup' DESC 'Abstraction of a netgroup. May refer to other netgroups' SUP top STRUCTURAL MUST cn MAY ( nisNetgroupTriple $ memberNisNetgroup $ description ) )
olcObjectClasses: ( 1.3.6.1.1.1.2.9 NAME 'nisMap' DESC 'A generic abstraction of a NIS map' SUP top STRUCTURAL MUST nisMapName MAY description )
olcObjectClasses: ( 1.3.6.1.1.1.2.10 NAME 'nisObject' DESC 'An entry in a NIS map' SUP top STRUCTURAL MUST ( cn $ nisMapEntry $ nisMapName ) )
olcObjectClasses: ( 1.3.6.1.1.1.2.11 NAME 'ieee802Device' DESC 'A device with a MAC address; device SHOULD be used as a structural class' SUP top AUXILIARY MAY macAddress )
olcObjectClasses: ( 1.3.6.1.1.1.2.12 NAME 'bootableDevice' DESC 'A device with boot parameters; device SHOULD be used as a structural class' SUP top AUXILIARY MAY ( bootFile $ bootParameter ) )
olcObjectClasses: ( 1.3.6.1.1.1.2.14 NAME 'nisKeyObject' DESC 'An object with a public and secret key' SUP top AUXILIARY MUST ( cn $ nisPublicKey $ nisSecretKey ) MAY ( uidNumber $ description ) )
olcObjectClasses: ( 1.3.6.1.1.1.2.15 NAME 'nisDomainObject' DESC 'Associates a NIS domain with a naming context' SUP top AUXILIARY MUST nisDomain )
olcObjectClasses: ( 1.3.6.1.1.1.2.16 NAME 'automountMap' SUP top STRUCTURAL MUST automountMapName MAY description )
olcObjectClasses: ( 1.3.6.1.1.1.2.17 NAME 'automount' DESC 'Automount information' SUP top STRUCTURAL MUST ( automountKey $ automountInformation ) MAY description )
olcObjectClasses: ( 1.3.6.1.1.1.2.18 NAME 'groupOfMembers' DESC 'A group with members (DNs)' SUP top STRUCTURAL MUST cn MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description $ member ) )

View file

@ -0,0 +1,11 @@
dn: cn=sudo,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: sudo
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.1 NAME 'sudoUser' DESC 'User(s) who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.2 NAME 'sudoHost' DESC 'Host(s) who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.3 NAME 'sudoCommand' DESC 'Command(s) to be executed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.4 NAME 'sudoRunAs' DESC 'User(s) impersonated by sudo (deprecated)' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.5 NAME 'sudoOption' DESC 'Options(s) followed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.6 NAME 'sudoRunAsUser' DESC 'User(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.7 NAME 'sudoRunAsGroup' DESC 'Group(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcObjectClasses: ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' DESC 'Sudoer Entries' SUP top STRUCTURAL MUST cn MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ description ) )

238
image/run.sh Normal file
View file

@ -0,0 +1,238 @@
#!/usr/bin/env bash
#
# Copyright 2019-2020 by Vegard IT GmbH, Germany, https://vegardit.com
# SPDX-License-Identifier: Apache-2.0
#
# @author Sebastian Thomschke, Vegard IT GmbH
#
# https://github.com/vegardit/docker-openldap
#
set -e -u
if [ -z "${BASH_VERSINFO:-}" ]; then /usr/bin/env bash "$0" "$@"; exit; fi
set -o pipefail
trap 'echo >&2 "$(date +%H:%M:%S) Error - exited with status $? at line $LINENO:"; pr -tn $0 | tail -n+$((LINENO - 3)) | head -n7' ERR
if [ "${DEBUG_RUN_SH:-}" == "1" ]; then
set -x
fi
cat <<'EOF'
_ __ __ __________
| | / /__ ____ _____ __________/ / / _/_ __/
| | / / _ \/ __ `/ __ `/ ___/ __ / / / / /
| |/ / __/ /_/ / /_/ / / / /_/ / _/ / / /
|___/\___/\__, /\__,_/_/ \__,_/ /___/ /_/
/____/
EOF
cat /opt/build_info
echo
if [ -f "$INIT_SH_FILE" ]; then
source "$INIT_SH_FILE"
fi
function log() {
if [ -p /dev/stdin ]; then
while read line; do
echo "[$(date "+%Y-%m-%d %H:%M:%S") ${BASH_SOURCE}:${BASH_LINENO}] $line"
done
else
echo "[$(date "+%Y-%m-%d %H:%M:%S") ${BASH_SOURCE}:${BASH_LINENO}] ${@}"
fi
}
# display slapd build info
slapd -VVV 2>&1 | log || true
# Limit maximum number of open file descriptors otherwise slapd consumes two
# orders of magnitude more of RAM, see https://github.com/docker/docker/issues/8231
ulimit -n $LDAP_NOFILE_LIMIT
#################################################################
# Adjust UID/GID and file permissions based on env var config
#################################################################
if [ -n "${LDAP_OPENLDAP_UID:-}" ]; then
effective_uid=$(id -u openldap)
if [ "$LDAP_OPENLDAP_UID" != "$effective_uid" ]; then
log "Changing UID of openldap user from $effective_uid to $LDAP_OPENLDAP_UID..."
usermod -o -u "$LDAP_OPENLDAP_UID" openldap
fi
fi
if [ -n "${LDAP_OPENLDAP_GID:-}" ]; then
effective_gid=$(id -g openldap)
if [ "$LDAP_OPENLDAP_GID" != "$effective_gid" ]; then
log "Changing GID of openldap user from $effective_gid to $LDAP_OPENLDAP_GID..."
usermod -o -u "$LDAP_OPENLDAP_GID" openldap
fi
fi
chown -R openldap:openldap /etc/ldap
chown -R openldap:openldap /var/lib/ldap
chown -R openldap:openldap /var/lib/ldap_orig
chown -R openldap:openldap /var/run/slapd
#################################################################
# Configure LDAP server on initial container launch
#################################################################
if [ ! -e /etc/ldap/slapd.d/initialized ]; then
function interpolate_vars() {
# https://stackoverflow.com/a/40167919
local line lineEscaped
while IFS= read -r line || [ -n "$line" ]; do # the `||` clause ensures that the last line is read even if it doesn't end with \n
# escape all chars that could trigger an expansion
IFS= read -r lineEscaped < <(echo "$line" | tr '`([$' '\1\2\3\4')
# selectively re-enable ${ references
lineEscaped=${lineEscaped//$'\4'{/\${}
# escape embedded double quotes to preserve them
lineEscaped=${lineEscaped//\"/\\\"}
eval "printf '%s\n' \"$lineEscaped\"" | tr '\1\2\3\4' '`([$'
done
}
function substr_before() {
echo "${1%%$2*}"
}
function str_replace() {
IFS= read -r -d $'\0' str
echo "${str/$1/$2}"
}
function ldif() {
log "--------------------------------------------"
local action=$1 && shift
local file=${!#}
log "Loading [$file]..."
interpolate_vars < $file > /tmp/$(basename $file)
ldap$action -H ldapi:/// "${@:1:${#}-1}" -f /tmp/$(basename $file)
}
# interpolate variable placeholders in env vars starting with "LDAP_INIT_"
for name in ${!LDAP_INIT_*}; do
declare "${name}=$(echo "${!name}" | interpolate_vars)"
done
# pre-populate folders in case they are empty
for folder in "/var/lib/ldap" "/etc/ldap/slapd.d"; do
if [ "$folder" -ef "${folder}_orig" ]; then
continue
fi
if [ -z "$(ls $folder)" ]; then
log "Initializing [$folder]..."
cp -r --preserve=all ${folder}_orig/. $folder
fi
done
LDAP_INIT_ROOT_USER_PW_HASHED=$(slappasswd -s "${LDAP_INIT_ROOT_USER_PW}")
/etc/init.d/slapd start
sleep 3
if [ "${LDAP_INIT_RFC2307BIS_SCHEMA:-}" == "1" ]; then
log "Replacing NIS (RFC2307) schema with RFC2307bis schema..."
ldapdelete -Y EXTERNAL cn={2}nis,cn=schema,cn=config
ldif add -Y EXTERNAL /opt/ldifs/schema_rfc2307bis02.ldif
fi
ldif add -Y EXTERNAL /etc/ldap/schema/ppolicy.ldif
ldif add -Y EXTERNAL /opt/ldifs/schema_sudo.ldif
ldif add -Y EXTERNAL /opt/ldifs/schema_ldapPublicKey.ldif
ldif modify -Y EXTERNAL /opt/ldifs/init_frontend.ldif
ldif add -Y EXTERNAL /opt/ldifs/init_module_memberof.ldif
ldif modify -Y EXTERNAL /opt/ldifs/init_mdb.ldif
ldif modify -Y EXTERNAL /opt/ldifs/init_mdb_acls.ldif
ldif modify -Y EXTERNAL /opt/ldifs/init_mdb_indexes.ldif
ldif add -Y EXTERNAL /opt/ldifs/init_module_unique.ldif
ldif add -Y EXTERNAL /opt/ldifs/init_module_ppolicy.ldif
LDAP_INIT_ORG_DN_ATTR=$(substr_before $LDAP_INIT_ORG_DN "," | str_replace "=" ": ") # referenced by init_org_tree.ldif
ldif add -x -D "$LDAP_INIT_ROOT_USER_DN" -w "$LDAP_INIT_ROOT_USER_PW" /opt/ldifs/init_org_tree.ldif
ldif add -x -D "$LDAP_INIT_ROOT_USER_DN" -w "$LDAP_INIT_ROOT_USER_PW" /opt/ldifs/init_org_ppolicy.ldif
ldif add -x -D "$LDAP_INIT_ROOT_USER_DN" -w "$LDAP_INIT_ROOT_USER_PW" /opt/ldifs/init_org_entries.ldif
log "--------------------------------------------"
echo "1" > /etc/ldap/slapd.d/initialized
rm -f /tmp/*.ldif
log "Creating periodic LDAP backup at [$LDAP_BACKUP_FILE]..."
slapcat -n 1 -l $LDAP_BACKUP_FILE || true
/etc/init.d/slapd stop
sleep 3
fi
echo "$LDAP_PPOLICY_PQCHECKER_RULE" > /etc/ldap/pqchecker/pqparams.dat
#################################################################
# Configure LDAP backup task
#################################################################
if [ -n "${LDAP_BACKUP_TIME:-}" ]; then
log "--------------------------------------------"
log "Configuring LDAP backup task to run daily: time=[${LDAP_BACKUP_TIME}] file=[$LDAP_BACKUP_FILE]..."
function backup_ldap() {
while true; do
while [ "$(date +%H:%M)" != "${LDAP_BACKUP_TIME}" ]; do
sleep 10s
done
log "Creating periodic LDAP backup at [$LDAP_BACKUP_FILE]..."
slapcat -n 1 -l $LDAP_BACKUP_FILE || true
sleep 23h
done
}
backup_ldap &
fi
#################################################################
# Start LDAP service
#################################################################
log "--------------------------------------------"
log "Starting OpenLDAP: slapd..."
#required for propagating SIGTERM from docker to service process
#https://unix.stackexchange.com/questions/146756/forward-sigterm-to-child-in-bash/444676#444676
function trap_handler() {
local signal=$1
if [ -n "${service_process_pid:-}" ]; then
log "Sending [$signal] to PID [$service_process_pid] ..."
kill -s $signal $service_process_pid 2>/dev/null
else
log "Received [$signal] before service started."
sig_received_before_service_started=$signal
fi
}
trap 'trap_handler TERM' SIGTERM SIGINT SIGHUP # https://github.com/openldap/openldap/search?q=SIGTERM
trap 'trap_handler QUIT' SIGQUIT
trap 'trap_handler USR1' SIGUSR1 # https://github.com/openldap/openldap/search?q=SIGUSR1
trap 'trap_handler USR2' SIGUSR2 # https://github.com/openldap/openldap/search?q=SIGUSR2
/usr/sbin/slapd \
$(for logLevel in ${LDAP_LOG_LEVELS:-}; do echo -n "-d $logLevel "; done) \
-h "ldap:/// ldapi:///" \
-u openldap -g openldap \
-F /etc/ldap/slapd.d 2>&1 | log &
service_process_pid=$(jobs -p | tail -1)
log "OpenLDAP PID: $service_process_pid"
if [ -n "${sig_received_before_service_started:-}" ]; then
kill -s $sig_received_before_service_started $service_process_pid 2>/dev/null
fi
wait $service_process_pid
trap - TERM INT
wait $service_process_pid
exit_status=$?
exit $exit_status