Compare commits

...

6 Commits

19 changed files with 423 additions and 99 deletions

View File

@ -65,7 +65,7 @@ on_calendar_backup_remote_to_local: "*-*-* 21:30:00"
## Schedule for Maintenance Tasks
on_calendar_heal_docker: "*-*-* {{ hours_server_awake }}:30:00" # Heal unhealthy docker instances once per hour
on_calendar_renew_lets_encrypt_certificates: "*-*-* 12,00:30:00" # Renew Mailu certificates twice per day
on_calendar_deploy_mailu_certificates: "*-*-* 13,01:30:00" # Deploy Mailu certificates twice per day
on_calendar_deploy_certificates: "*-*-* 13,01:30:00" # Deploy letsencrypt certificates twice per day to docker containers
on_calendar_msi_keyboard_color: "*-*-* *:*:00" # Change the keyboard color every minute
on_calendar_cleanup_failed_docker: "*-*-* 12:00:00" # Clean up failed docker backups every noon
on_calendar_btrfs_auto_balancer: "Sat *-*-01..07 00:00:00" # Execute btrfs auto balancer every first Saturday of a month
@ -157,6 +157,7 @@ domain_gitea: "git.{{primary_domain}}"
domain_gitlab: "gitlab.{{primary_domain}}"
domain_portfolio: "{{primary_domain}}"
domain_keycloak: "auth.{{primary_domain}}"
domain_ldap: "ldap.{{primary_domain}}"
domain_listmonk: "newsletter.{{primary_domain}}"
domain_mailu: "{{system_email_host}}"
domain_mastodon: "microblog.{{primary_domain}}"
@ -245,9 +246,9 @@ keycloak_administrator_username: "{{administrator_username}}"
#### LDAP
ldap_version: "latest"
ldap_admin_version: "2.0.0-dev" # @todo Attention: Change this as fast as released to latest
ldap_administrator_username: "{{administrator_username}}"
ldap_administrator_password: "{{user_administrator_initial_password}}" #CHANGE for security reasons
# ldap_database_password: # Needs to be defined in inventory
#### Listmonk
listmonk_admin_username: "{{administrator_username}}"

View File

@ -306,6 +306,15 @@
domain: "{{domain_keycloak}}"
http_port: 8032
- name: setup ldap
hosts: ldap
become: true
roles:
- role: docker-ldap
vars:
domain: "{{domain_ldap}}"
http_port: 8033
# Native Webserver Roles
- name: setup nginx-static-repositorys
hosts: nginx-static-repositorys

View File

@ -1,7 +1,137 @@
# Draft Docker LDAP and SSO
Draft role for an LDAP implementation with sso.
## See
- [ChatGPT Conversation](https://chat.openai.com/share/77919994-5d44-4a64-877d-b572d67483d4)
- [Discouse Documentation](https://forum.veen.world/t/cymais-ldap-implementierung-documentation/49)
- [Setup Guide](https://goneuland.de/ldap-nextcloud-und-mailserver-in-docker/)
- https://hub.docker.com/r/bitnami/openldap
# Docker LDAP Role
This Ansible role provides a streamlined implementation of an LDAP server with TLS support. It leverages Docker Compose to deploy a pre-configured OpenLDAP server and phpLDAPadmin for easy management.
---
## 🚀 **Features**
- **Secure LDAP with TLS**:
- Automatically configures TLS certificates for secure communication.
- Provides configurable support for LDAPS on port 636.
- **phpLDAPadmin Integration**:
- Includes a Dockerized phpLDAPadmin setup for easy user and group management.
- **Healthcheck Support**:
- Ensures that the LDAP service is healthy and accessible using `ldapsearch`.
---
## 📋 **Requirements**
### Prerequisites
- A valid domain name.
- SSL/TLS certificates (e.g., from Lets Encrypt).
- Ansible installed on the deployment host.
- Docker and Docker Compose installed on the target host.
---
## 🔧 **Role Variables**
### Key Variables
| Variable | Description | Default Value |
|-------------------------------|----------------------------------------------------------|--------------------------------------|
| `docker_compose_project_name` | Name of the Docker Compose project. | `ldap` |
| `ldap_root` | Base DN for the LDAP directory. | `dc={{primary_domain_sld}},dc={{primary_domain_tld}}` |
| `ldap_admin_dn` | Distinguished Name (DN) for the LDAP administrator. | `cn={{ldap_administrator_username}},{{ldap_root}}` |
| `cert_mount_directory` | Directory to mount SSL/TLS certificates. | `{{docker_compose_instance_directory}}/certs/` |
| `ldap_administrator_username` | Username for the LDAP admin. | `admin` |
| `ldap_administrator_password` | Password for the LDAP admin. | _Required_ |
| `ldap_admin_version` | Version of phpLDAPadmin Docker image. | `latest` |
| `ldap_version` | Version of OpenLDAP Docker image. | `latest` |
---
## 📂 **Role Structure**
```
roles/
docker-ldap/
README.md
vars/
main.yml
tasks/
main.yml
templates/
docker-compose.yml.j2
```
---
## 📖 **Usage**
Heres an example playbook to use this role:
```yaml
- name: Deploy LDAP with SSO
hosts: ldap_servers
roles:
- role: docker-ldap
vars:
docker_compose_instance_directory: "/home/administrator/docker-compose/ldap/"
primary_domain_sld: "veen"
primary_domain_tld: "world"
ldap_administrator_username: "administrator"
ldap_administrator_password: "secure_password_here"
ldap_admin_version: "latest"
ldap_version: "latest"
```
### **Steps to Deploy:**
1. Clone your playbook repository to the target server.
2. Run the playbook:
```bash
ansible-playbook -i inventory playbook.yml
```
3. Access phpLDAPadmin:
- URL: `http://localhost:8080` (or your configured port)
- Login: Use the admin DN and password.
---
## 🛠️ **Technical Details**
### **Services Configured**
1. **OpenLDAP**
- TLS enabled on port 636.
- Configuration driven by environment variables.
2. **phpLDAPadmin**
- Accessible on port 8080.
- Simplifies LDAP management via a web interface.
3. **Healthchecks**
- Uses `ldapsearch` to validate LDAP functionality.
### **Directory Structure**
The following directories are mounted in the container:
- **Certificates:** `{{cert_mount_directory}}` for TLS certificates.
- **LDAP Data:** `data:/bitnami/openldap` for persistent data storage.
---
## 🔒 **Security Recommendations**
- Always use strong passwords for `ldap_administrator_password`.
- Ensure proper file permissions for mounted certificate files.
- Restrict access to phpLDAPadmin by binding it to `127.0.0.1` or using a reverse proxy.
---
## 📜 **References**
- [Bitnami OpenLDAP](https://hub.docker.com/r/bitnami/openldap)
- [phpLDAPadmin Documentation](https://github.com/leenooks/phpLDAPadmin/wiki/Docker-Container)
- [LDAP Account Manager](https://github.com/LDAPAccountManager/docker)
---
## 👨‍💻 **Author**
Kevin Veen-Birkenbach - [veen.world](https://www.veen.world)
Feel free to report issues, suggest features, or contribute to the repository! 😊

View File

@ -0,0 +1,22 @@
---
- name: "include docker/compose/common.yml"
include_tasks: docker/compose/common.yml
- name: "include tasks nginx-docker-proxy-domain.yml"
include_tasks: nginx-docker-proxy-domain.yml
- name: "create {{docker_compose_instance_directory}}"
file:
path: "{{docker_compose_instance_directory}}"
state: directory
mode: 0755
- name: "include the nginx-docker-cert-deploy role"
include_role:
name: nginx-docker-cert-deploy
- name: add docker-compose.yml
template:
src: "docker-compose.yml.j2"
dest: "{{docker_compose_instance_directory}}docker-compose.yml"
notify: docker compose project setup

View File

@ -1,15 +1,26 @@
services:
{% include 'templates/docker/services/' + database_type + '.yml.j2' %}
phpldapadmin:
image: leenooks/phpldapadmin:{{ldap_admin_version}}
logging:
driver: journald
restart: {{docker_restart_policy}}
ports:
- 127.0.0.1:{{http_port}}:8080
environment:
# @See https://github.com/leenooks/phpLDAPadmin/wiki/Docker-Container
APP_URL: https://{{domain}}
LDAP_HOST: openldap
openldap:
image: bitnami/openldap:{{ldap_version}}
logging:
driver: journald
restart: {{docker_restart_policy}}
ports:
- '127.0.0.1:389:1389' # Expose just on local host for security reasons
- '127.0.0.1:389:389' # Expose just on local host for security reasons, phpLDAPadmin requires this
- '636:636' # Expose to internet
environment:
# @See https://hub.docker.com/r/bitnami/openldap
# GENERAL
LDAP_ADMIN_USERNAME: {{ldap_administrator_username}} # LDAP database admin user.
LDAP_ADMIN_PASSWORD: {{ldap_administrator_password}} # LDAP database admin password.
@ -17,24 +28,26 @@ services:
#LDAP_PASSWORDS: password1,password2 # Comma separated list of passwords to use for LDAP users. Default: bitnami1,bitnami
LDAP_ROOT: {{ldap_root}} # LDAP baseDN (or suffix) of the LDAP tree. Default: dc=example,dc=org
LDAP_ADMIN_DN: {{ldap_admin_dn}}
LDAP_PORT_NUMBER: 389 # Route to default port
# TLS
LDAP_ENABLE_TLS: yes # Whether to enable TLS for traffic or not. Defaults to no
LDAP_REQUIRE_TLS: yes # Whether connections must use TLS. Will only be applied with LDAP_ENABLE_TLS active. Defaults to no
LDAP_REQUIRE_TLS: no # Deactivated so that it can be accessed on the server itself via phpldapadmin
LDAP_LDAPS_PORT_NUMBER: 636 # Port used for TLS secure traffic. Priviledged port is supported (e.g. 636). Default: 1636 (non privileged port).
LDAP_TLS_CERT_FILE: File containing the certificate file for the TLS traffic. No defaults.
LDAP_TLS_KEY_FILE: File containing the key for certificate. No defaults.
LDAP_TLS_CA_FILE: File containing the CA of the certificate. No defaults.
LDAP_TLS_DH_PARAMS_FILE: File containing the DH parameters. No defaults.
# Database Configuration
MARIADB_ROOT_PASSWORD=root-password
MARIADB_USER=customuser
MARIADB_DATABASE=customdatabase
MARIADB_ENABLE_LDAP=yes
LDAP_TLS_CERT_FILE: /certs/cert.pem # File containing the certificate file for the TLS traffic. No defaults.
LDAP_TLS_KEY_FILE: /certs/key.pem # File containing the key for certificate. No defaults.
LDAP_TLS_CA_FILE: /certs/chain.pem # File containing the CA of the certificate. No defaults.
#LDAP_TLS_DH_PARAMS_FILE: # File containing the DH parameters. No defaults.
volumes:
- {{cert_mount_directory}}:/certs:ro
- 'data:/bitnami/openldap'
{% include 'templates/docker/container/depends-on-just-database.yml.j2' %}
healthcheck:
test: >
ldapsearch -x -H ldap://localhost:389 -b "{{ldap_root}}" -D "{{ldap_admin_dn}}" -w "{{ldap_administrator_password}}"
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
{% include 'templates/docker/container/networks.yml.j2' %}
{% include 'templates/docker/compose/volumes.yml.j2' %}
data:

View File

@ -1,5 +1,4 @@
docker_compose_project_name: "ldap"
database_type: "postgres"
database_password: "{{ldap_database_password}}"
ldap_root: "dc={{primary_domain_sld}},dc={{primary_domain_tld}}"
ldap_admin_dm: "cn={{ldap_administrator_username}},{{ldap_root}}"
ldap_admin_dn: "cn={{ldap_administrator_username}},{{ldap_root}}"
cert_mount_directory: "{{docker_compose_instance_directory}}/certs/"

View File

@ -1,7 +0,0 @@
---
- name: "restart deploy-letsencrypt-mailu.cymais.service"
systemd:
name: deploy-letsencrypt-mailu.cymais.service
state: restarted
enabled: yes
daemon_reload: yes

View File

@ -7,15 +7,9 @@
vars:
nginx_docker_reverse_proxy_extra_configuration: "client_max_body_size 31M;"
- name: "create {{path_docker_compose_instances}}mailu"
- name: "create {{docker_compose_instance_directory}}"
file:
path: "{{path_docker_compose_instances}}mailu"
state: directory
mode: 0755
- name: "create {{path_administrator_scripts}}mailu"
file:
path: "{{path_administrator_scripts}}mailu"
path: "{{docker_compose_instance_directory}}"
state: directory
mode: 0755
@ -25,11 +19,9 @@
state: directory
mode: 0755
- name: "create /etc/mailu/certs"
file:
path: "/etc/mailu/certs"
state: directory
mode: 0755
- name: "Include the nginx-docker-cert-deploy role"
include_role:
name: nginx-docker-cert-deploy
- name: add docker-compose.yml
template:
@ -43,25 +35,6 @@
dest: "{{docker_compose_instance_directory}}mailu.env"
notify: docker compose project setup
- name: add deploy-letsencrypt-mailu.sh
template:
src: "deploy-letsencrypt-mailu.sh.j2"
dest: "{{path_administrator_scripts}}mailu/deploy-letsencrypt-mailu.sh"
- name: configure deploy-letsencrypt-mailu.cymais.service
template:
src: "deploy-letsencrypt-mailu.service.j2"
dest: "/etc/systemd/system/deploy-letsencrypt-mailu.cymais.service"
notify: restart deploy-letsencrypt-mailu.cymais.service
- name: "include role for systemd-timer for {{service_name}}"
include_role:
name: systemd-timer
vars:
on_calendar: "{{on_calendar_deploy_mailu_certificates}}"
service_name: "deploy-letsencrypt-mailu"
persistent: "true"
- name: flush docker service
meta: flush_handlers
when: mode_setup |bool

View File

@ -1,7 +0,0 @@
[Unit]
Description=Let's Encrypt Mailu Deploy
OnFailure=systemd-notifier.cymais@%n.service
[Service]
Type=oneshot
ExecStart=/usr/bin/bash {{path_administrator_scripts}}mailu/deploy-letsencrypt-mailu.sh

View File

@ -1,4 +0,0 @@
#!/bin/sh
cp /etc/letsencrypt/live/{{domain}}/privkey.pem /etc/mailu/certs/key.pem || exit 1
cp /etc/letsencrypt/live/{{domain}}/fullchain.pem /etc/mailu/certs/cert.pem || exit 1
cd {{docker_compose_instance_directory}} && docker compose exec front nginx -s reload || exit 1

View File

@ -32,7 +32,7 @@ services:
- "{{ ip4_address }}:4190:4190"
volumes:
- "/etc/mailu/overrides/nginx:/overrides:ro"
- "/etc/mailu/certs:/certs"
- "{{cert_mount_directory}}:/certs:ro"
{% include 'templates/docker/container/depends-on-also-database.yml.j2' %}
resolver:
condition: service_started

View File

@ -1,3 +1,4 @@
docker_compose_project_name: "mailu"
database_password: "{{mailu_database_password}}"
database_type: "mariadb"
cert_mount_directory: "{{docker_compose_instance_directory}}/certs/"

View File

@ -0,0 +1,103 @@
# Nginx Docker Cert Deploy Role
🎉 **Author**: Kevin Veen-Birkenbach ([veen.world](https://www.veen.world))
This Ansible role simplifies the deployment of Let's Encrypt certificates into Docker Compose setups with Nginx. It ensures that certificates are copied, directories are created, and Nginx services are reloaded or restarted as needed.
---
## 🚀 **Features**
- Copies Let's Encrypt certificates to the target directory.
- Automatically reloads or restarts Nginx services in all Docker Compose containers.
- Configures and manages a `systemd` service for automated deployment.
- Supports periodic execution via a `systemd` timer.
- Handles dependent services like `systemd-notifier`.
---
## 🔧 **Variables**
The following variables can be customized:
| Variable | Description | Default Value |
|-----------------------------------|------------------------------------------------|-----------------------------------------|
| `cert_mount_directory` | Target directory to mount certificates. | `{{docker_compose_instance_directory}}/certs/` |
| `nginx_docker_cert_deploy_script` | Path to the deployment script. | `{{path_administrator_scripts}}nginx-docker-cert-deploy.sh` |
| `docker_compose_project_name` | Name of the Docker Compose project. | None (must be defined in playbook) |
| `on_calendar_deploy_certificates` | `systemd` timer schedule for certificate updates. | None (must be defined in playbook) |
---
## 📋 **Tasks Overview**
### Main Tasks
1. **Add Deployment Script**:
Copies the `nginx-docker-cert-deploy.sh` script to the administrator scripts directory.
2. **Create Certificate Directory**:
Ensures the `cert_mount_directory` exists with proper permissions.
3. **Configure Systemd Service**:
Deploys a `systemd` service file for the deployment process.
4. **Include `systemd-timer` Role**:
Schedules automatic deployment tasks using a `systemd` timer.
### Handlers
- **Restart Service**:
Restarts the `nginx-docker-cert-deploy` service when configuration changes.
---
## 📂 **File Structure**
```
roles/
nginx-docker-cert-deploy/
vars/
main.yml
handlers/
main.yml
files/
nginx-docker-cert-deploy.sh
tasks/
main.yml
templates/
nginx-docker-cert-deploy.service.j2
meta/
main.yml
```
---
## 📖 **Usage Example**
Here's an example of how to use this role in your playbook:
```yaml
- name: Deploy Let's Encrypt certificates to Docker Compose
hosts: all
roles:
- role: nginx-docker-cert-deploy
vars:
domain: "example.com"
docker_compose_instance_directory: "/home/administrator/docker-compose/nginx"
docker_compose_project_name: "nginx"
on_calendar_deploy_certificates: "daily"
```
---
## 🛠️ **Dependencies**
This role depends on:
- `systemd-notifier`: Notifies about failures in the `systemd` service.
---
Feel free to contribute, report issues, or suggest improvements! 😊

View File

@ -0,0 +1,46 @@
#!/bin/sh
# Check if the necessary parameters are provided
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <domain> <docker_compose_instance_directory>"
exit 1
fi
# Assign parameters
domain="$1"
docker_compose_instance_directory="$2"
# Copy certificates
cp -RvL "/etc/letsencrypt/live/$domain/"* "$docker_compose_instance_directory/certs" || exit 1
chmod a+r -v "$docker_compose_instance_directory/certs/"*
# Flag to track if any Nginx reload was successful
nginx_reload_successful=false
# Reload Nginx in all containers within the Docker Compose setup
cd "$docker_compose_instance_directory" || exit 1
# Iterate over all services
for service in $(docker compose ps --services); do
echo "Checking service: $service"
# Check if Nginx exists in the container
if docker compose exec -T "$service" which nginx > /dev/null 2>&1; then
echo "Reloading Nginx for service: $service"
if docker compose exec -T "$service" nginx -s reload; then
nginx_reload_successful=true
echo "Successfully reloaded Nginx for service: $service"
else
echo "Failed to reload Nginx for service: $service" >&2
fi
else
echo "Nginx not found in service: $service, skipping."
fi
done
# Restart all containers if no Nginx reload was successful
if [ "$nginx_reload_successful" = false ]; then
echo "No Nginx reload was successful. Restarting all Docker containers."
docker compose restart || exit 1
else
echo "At least one Nginx reload was successful. No restart needed."
fi

View File

@ -0,0 +1,7 @@
---
- name: "restart nginx-docker-cert-deploy.cymais.service"
systemd:
name: nginx-docker-cert-deploy.{{docker_compose_project_name}}.cymais.service
state: restarted
enabled: yes
daemon_reload: yes

View File

@ -0,0 +1,30 @@
- name: add nginx-docker-cert-deploy.sh
copy:
src: "nginx-docker-cert-deploy.sh"
dest: "{{nginx_docker_cert_deploy_script}}"
when: run_once_nginx_docker_cert_deploy is not defined
- name: run the nginx_docker_cert_deploy tasks once
set_fact:
run_once_backup_directory_validator: true
when: run_once_nginx_docker_cert_deploy is not defined
- name: "create {{cert_mount_directory}}"
file:
path: "{{cert_mount_directory}}"
state: directory
mode: 0755
- name: configure nginx-docker-cert-deploy.cymais.service
template:
src: "nginx-docker-cert-deploy.service.j2"
dest: "/etc/systemd/system/nginx-docker-cert-deploy.{{docker_compose_project_name}}.cymais.service"
notify: restart nginx-docker-cert-deploy.cymais.service
- name: "include role for systemd-timer for {{service_name}}"
include_role:
name: systemd-timer
vars:
on_calendar: "{{on_calendar_deploy_certificates}}"
service_name: "nginx-docker-cert-deploy.{{docker_compose_project_name}}"
persistent: "true"

View File

@ -0,0 +1,7 @@
[Unit]
Description=Let's Encrypt deploy to {{docker_compose_instance_directory}}
OnFailure=systemd-notifier.cymais@%n.service
[Service]
Type=oneshot
ExecStart=/usr/bin/bash {{path_administrator_scripts}}/nginx-docker-cert-deploy.sh {{domain}} {{docker_compose_instance_directory}}

View File

@ -0,0 +1 @@
nginx_docker_cert_deploy_script: "{{path_administrator_scripts}}nginx-docker-cert-deploy.sh"