docker-openldap icon indicating copy to clipboard operation
docker-openldap copied to clipboard

TLS with LetsEncrypt

Open tiredofit opened this issue 7 years ago • 15 comments

Has anyone been able to get LetsEncrypt certs to work properly with this?

I have mapped my certs to the cert.pem, and key.pem however there doesn't seem to be a proper CA.crt that I can use. My LDAP Client (JXplorer) states that it cannot authenticate because the CA certificate is missing from the chain.

I have tried copying fullchain.pem to ca.crt along with other steps I've found on the web, but no success. Hopefully someone has encountered this issue and knows how to resolve?

tiredofit avatar Apr 05 '17 02:04 tiredofit

This image (letsencrypt-nginx-proxy-companion) (despite its name) can be used for anything afaik. It creates certs in the volume or bind mount you specified and creates certificates for all the containers you specified the env variables LETSENCRYPT_HOST and LETSENCRYPT_EMAIL for.

I havent tried it with ldap yet (am about to test it out though), but it creates certs in the following formats: .chain.pem, .crt, dhparam.pem and .key. It SHOULD work, if not, you can always fork and adjust from their github.

I would love it if you could write an answer comment here if you get it to work, or even create a PR to adjust the readme and add a "using letsencrypt certificates" section <3

rjwestman avatar Jun 12 '17 19:06 rjwestman

Hi, We're using the letsencrypt-nginx-proxy-companion as well. So far, so such luck with getting the certificates to work, due to chain issues. Interested to hear how you make out.

tiredofit avatar Jun 13 '17 23:06 tiredofit

I tried to use let's encrypt certs to securise my server. Everytime I launch the container, the certificates aren't recognized and are overwrited by the defaults self-signed certs. I don't know what I'm doing wrong here. Symbolics links to the certificates are in the mounted folder /letsencrypt/live/ldap.domain.com, certificates themselves are in the /letsencrypt/archive/ldap.domain.com folder. LDAP is configured according to the arch linux wiki recommendations. I'm using the --copy-service command according to issue 59.

docker-compose.yaml

version: '2'
services:
  openldap:
    image: osixia/openldap:1.1.8
    container_name: openldap
    hostname: "ldap.domain.com"
    command: ["--copy-service"]
    restart: always
    environment:
      LDAP_ORGANISATION: domain
      LDAP_DOMAIN: domain.com
      LDAP_BASE_DN: dc=domain,dc=com
      LDAP_ADMIN_PASSWORD: password
      LDAP_CONFIG_PASSWORD: password
      LDAP_READONLY_USER: "false"
      LDAP_BACKEND: mdb
      LDAP_TLS: "true"
      LDAP_TLS_CRT_FILENAME: cert.pem
      LDAP_TLS_KEY_FILENAME: privkey.pem
      LDAP_TLS_CA_CRT_FILENAME: chain.pem
      LDAP_TLS_ENFORCE: "true"
      LDAP_TLS_CIPHER_SUITE: NORMAL:SECURE256:-VERS-SSL3.0
      LDAP_TLS_VERIFY_CLIENT: never
      LDAP_REPLICATION: "false"
      LDAP_REMOVE_CONFIG_AFTER_SETUP: "true"
      LDAP_SSL_HELPER_PREFIX: ldap
    tty: true
    stdin_open: true
    volumes:
       - ./ldap:/var/lib/ldap
       - ./slapd.d:/etc/ldap/slapd.d
       - ./letsencrypt/live/ldap.domain.com:/container/service/slapd/assets/certs
    ports:
      - "389:389"
      - "636:636"

log of the container

*** CONTAINER_LOG_LEVEL = 3 (info)
*** Copy /container/service to /container/run/service
*** Killing all processes...
Traceback (most recent call last):
  File "/container/tool/run", line 889, in <module>
    main(args)
  File "/container/tool/run", line 774, in main
    setup_run_directories(args)
  File "/container/tool/run", line 375, in setup_run_directories
    copy_service_to_run_dir()
  File "/container/tool/run", line 441, in copy_service_to_run_dir
    shutil.copytree(IMPORT_SERVICE_DIR, RUN_SERVICE_DIR)
  File "/usr/lib/python2.7/shutil.py", line 208, in copytree
    raise Error, errors
shutil.Error: [('/container/service/slapd/assets/certs/chain.pem', '/container/run/service/slapd/assets/certs/chain.pem', "[Errno 2] No such file or directory: '/container/service/slapd/assets/certs/chain.pem'"), ('/container/service/slapd/assets/certs/privkey.pem', '/container/run/service/slapd/assets/certs/privkey.pem', "[Errno 2] No such file or directory: '/container/service/slapd/assets/certs/privkey.pem'"), ('/container/service/slapd/assets/certs/fullchain.pem', '/container/run/service/slapd/assets/certs/fullchain.pem', "[Errno 2] No such file or directory: '/container/service/slapd/assets/certs/fullchain.pem'"), ('/container/service/slapd/assets/certs/cert.pem', '/container/run/service/slapd/assets/certs/cert.pem', "[Errno 2] No such file or directory: '/container/service/slapd/assets/certs/cert.pem'")]
*** CONTAINER_LOG_LEVEL = 3 (info)
*** Copy /container/service to /container/run/service ignored
*** /container/run/service already exists
*** Search service in CONTAINER_SERVICE_DIR = /container/service :
*** link /container/service/:ssl-tools/startup.sh to /container/run/startup/:ssl-tools
*** link /container/service/slapd/startup.sh to /container/run/startup/slapd
*** link /container/service/slapd/process.sh to /container/run/process/slapd/run
*** Set environment for startup files
*** Environment files will be proccessed in this order : 
Caution: previously defined variables will not be overriden.
/container/environment/99-default/default.startup.yaml
/container/environment/99-default/default.yaml

To see how this files are processed and environment variables values,
run this container with '--loglevel debug'
*** Running /container/run/startup/:ssl-tools...
*** Running /container/run/startup/slapd...
No certificate file and certificate key provided, generate:
/container/service/slapd/assets/certs/cert.pem and /container/service/slapd/assets/certs/privkey.pem
2017/06/27 14:52:56 [INFO] generate received request
2017/06/27 14:52:56 [INFO] received CSR
2017/06/27 14:52:56 [INFO] generating key: ecdsa-384
2017/06/27 14:52:56 [INFO] encoded CSR
2017/06/27 14:52:56 [INFO] signed certificate with serial number 353108601774684456276929086277369460834475219239
Link /container/service/:ssl-tools/assets/default-ca/default-ca.pem to /container/service/slapd/assets/certs/chain.pem
Start OpenLDAP...
Waiting for OpenLDAP to start...
Add TLS config...
Add enforce TLS...
Disable replication config...
Stop OpenLDAP...
Remove config files...
First start is done...
*** Set environment for container process
*** Remove file /container/environment/99-default/default.startup.yaml
*** Environment files will be proccessed in this order : 
Caution: previously defined variables will not be overriden.
/container/environment/99-default/default.yaml

To see how this files are processed and environment variables values,
run this container with '--loglevel debug'
*** Running /container/run/process/slapd/run...
59525529 @(#) $OpenLDAP: slapd  (Jan 16 2016 23:00:08) $
	root@chimera:/tmp/buildd/openldap-2.4.40+dfsg/debian/build/servers/slapd
TLS: warning: ignoring dhfile
59525529 slapd starting

tailtwo avatar Jun 27 '17 14:06 tailtwo

I swear I had a complete legit environnement running openldap and phpldapadmin with TLS encryption using lets encrypt some days ago. But there came the renewals of certs ...

Did them, did a docker-compose to update the files in containers, and now, it's not working anymore. My config was :

version: '2'
services:
  openldap:
    image: osixia/openldap:1.1.8
    container_name: openldap
    volumes:
      - ldapData:/var/lib/ldap
      - ldapConf:/etc/ldap/slapd.d
      - /etc/letsencrypt/live/DOMAIN:/container/service/slapd/assets/certs/
    environment:
      LDAP_LOG_LEVEL: "256"
      LDAP_ORGANISATION: "organisation"
      LDAP_DOMAIN: "domain"
      LDAP_BASE_DN: "******"
      LDAP_ADMIN_PASSWORD: "******"
      LDAP_CONFIG_PASSWORD: "*******"
      LDAP_READONLY_USER: "false"
      LDAP_BACKEND: "hdb"
      LDAP_TLS: "true"
      LDAP_TLS_CRT_FILENAME: "cert.pem"
      LDAP_TLS_KEY_FILENAME: "privkey.pem"
      LDAP_TLS_CA_CRT_FILENAME: "fullchain.pem"

      LDAP_TLS_VERIFY_CLIENT: "try"
      LDAP_TLS_ENFORCE: "false"

      LDAP_REPLICATION: "false"
      LDAP_REMOVE_CONFIG_AFTER_SETUP: "true"
      LDAP_SSL_HELPER_PREFIX: "ldap"
    stdin_open: true
    ports:
      - "636:636"
    hostname: "*******"
  phpldapadmin:
    image: osixia/phpldapadmin:latest
    container_name: phpldapadmin
    volumes:
      - /etc/letsencrypt/live/DOMAIN:/container/service/phpldapadmin/assets/apache2/certs
    environment:
      PHPLDAPADMIN_LDAP_HOSTS: "openldap"
      PHPLDAPADMIN_HTTPS: "true"
      PHPLDAPADMIN_HTTPS_CRT_FILENAME: "cert.pem"
      PHPLDAPADMIN_HTTPS_KEY_FILENAME: "privkey.pem"
      PHPLDAPADMIN_HTTPS_CA_CRT_FILENAME: "fullchain.pem"
      PHPLDAPADMIN_LDAP_CLIENT_TLS: "false"
    ports:
      - "443:443"
    depends_on:
      - openldap
    hostname: "*******"
volumes:
    ldapData:
       external: true
    ldapConf:
       external: true

Now everytime I build it again from scratch, openldap is destroying the simlynk of the fullchain.pem to his container (which was a symlink to the archive folder of letsencrypt), then it tries to generate a DH parameter, fail and crash. Then phpldapadmin tries to access the fullchain.pem file which is now linked to the openldap container, so it doesn't find it and create is own ...

aferreol avatar Aug 22 '17 08:08 aferreol

Managed to make it work. The main problem is using the live folder of letsencrypt which is using symlinks. By pointing to the archive one, everything worked fine...

aferreol avatar Aug 30 '17 08:08 aferreol

Thank you @zeiitoun , your example appears to be working just fine pointing to archive and using the files there.

cintiadr avatar Dec 06 '17 00:12 cintiadr

Guys pointing it to archive makes it complicated with renewal. This is much better approach This is just important part of compose what has been mentioned already above

environment:
  - LDAP_TLS_CRT_FILENAME=live/host.domain.com/cert.pem
  - LDAP_TLS_KEY_FILENAME=live/host.domain.com/privkey.pem
  - LDAP_TLS_CA_CRT_FILENAME=live/host.domain.com/fullchain.pem
volumes:
  - /etc/letsencrypt:/container/service/slapd/assets/certs``

chladic avatar Feb 09 '18 10:02 chladic

You're right, pointing to the upper directory of lets encrypt is working ... My bad !

aferreol avatar Feb 16 '18 09:02 aferreol

@chladic are you recommending to generate the certs on the host instead of within the container?\

I want to use ldaps and ldap+tls with letsencrypt. I am concerned by slapd requiring a restart on certificate change. How did you guys manage to send the signal and renew the certs? would be nice to know if some people use this without hassle in produciton.

kopax avatar Dec 10 '19 13:12 kopax

@kopax I use it with letsencrypt generated on host outside of container and reload it in post hook. But I would like to change it to have some SSL termination in front so ldap does not have to be touched

chladic avatar Dec 10 '19 13:12 chladic

@chladic I was just analyzing the situation and thought about solving it with traefik v2.1. The problem if you do that is that ldap+tls won't start because the certificate needs to be available to slapd itself

Unless there's a way to export it from traefik and copy it over... which feel a little too manual to me.

Also, if you use a network volume, slapd must be reloaded on certificate change. Do you know how to sent the reload signal to https://github.com/osixia/docker-openldap container?

ldaps is the only proto capable of handling ssl termination in front. I personnaly need both so that's not an option for me. What post hook are you referring to?

kopax avatar Dec 10 '19 13:12 kopax

@kopax Solution with traefik would be great in case ldap is running without TLS and traefik does SSL termination. Traefik can store certs in shared storage or consul, but importing it to slapd would be complicated and doesnt solve your problem. I dont send any signal, I restart container with: docker restart ldap

chladic avatar Dec 10 '19 13:12 chladic

With nginx as SSL termination is possible and it can proxy any TCP/UDP traffic:

https://docs.nginx.com/nginx/admin-guide/load-balancer/tcp-udp-load-balancer/

Traefik has TCP services what might do the job, but I never tried.

chladic avatar Dec 10 '19 13:12 chladic

One problem which we faced using Letsencrypt: Different LE intermediate certificates used on nodes when using master-master replication. Replication of one of the master nodes broke with ldap_sasl_bind_s failed (-1) Reason: This host used the "ISRG Root X1" intermediate cert in chain.pem. All other nodes used the "DST Root CA X3" intermediate cert. Therefore, cert validation to/from the node using the X1 cert broke.

A forced LE renewal and Osixia OpenLdap 1.4.0 container rebuild on all nodes using the old X3 cert fixed the issue.

robertoschwald avatar May 13 '21 12:05 robertoschwald

Currently evaluating doing that using a similar approach we did for mariadb.

Fetching the certificate using

  • https://github.com/KontextWork/docker-database-cluster/blob/main/docker-compose-mariadb.yml#L21
  • maintaining it with https://github.com/KontextWork/docker-database-cluster/blob/main/docker-compose-mariadb.yml#L44

Also considering adding this to our help chart, where CertManager would take care of the LE management, just not sure if we could incorporate a "deploy hook" with that yet.

Just wanted to share the above, because running a custom LE fetcher without using Traefik or similar is always pain in docker, with the above, it works neatly

EugenMayer avatar Dec 04 '22 19:12 EugenMayer