# LDAP Gateway
# Preamble
The EE server supports esaqa's LDAP Gateway, a secure way to expose LDAP servers. In addition the LDAP server provides cryptographic that applications can use to decrypt data on login. The advantages are:
- Servers and applications authenticate eachother cryptographically.
- The whole transmission between application and gateway is encrypted by SSL and esaqa's transport encryption.
- User secrets will be encrypted by secrets provided by the gateway
- Encryption secrets are not stored in the server's
settings.yaml
. - Each user has one unique key that is not shared across users
- Encryption keys for user secrets are calculated based on LDAP parameters and not stored in the gateway itself.
- No modification to the structure of the LDAP directory is necessary.
- Multiple LDAP gateways can be configured for HA purposes to allow Active / Passive failover.
WARNING
All keys are protected by the LDAP gateway. If the settings.yaml
of the gateway is lost, all stored data in Psono
becomes inaccessible.
We assume that:
- you have a server with docker installed
- you use https://ldapgateway.example.com to host your ldapgateway
- you have a valid certificate for ldapgateway.example.com in /etc/ssl/ with fullchain_ldapgateway.pem and privkey_ldapgateway.pem
- An A-Record for ldapgateway.example.com exists, pointing to your server's ip address
# Installation with Docker
Generate keys
Execute the command below to generate your cryptographic keys which you need in the next step.
docker run --rm -ti esaqa/ldap-gateway:latest python3 ./ldapgw/manage.py generateserverkeys
Create a settings.yaml
Create a settings.yaml in e.g.
/opt/docker/ldapgateway/
with the following content. Replace the keys at the top with the keys that you just generated.# Replace the keys below with the one from the generateserverkeys command. # docker run --rm -ti esaqa/ldap-gateway:latest python3 ./ldapgw/manage.py generateserverkeys SECRET_KEY: 'SOME SUPER SECRET KEY THAT SHOULD BE RANDOM AND 32 OR MORE DIGITS LONG' DB_SECRET: 'SOME SUPER SECRET DB SECRET THAT SHOULD BE RANDOM AND 32 OR MORE DIGITS LONG' EMAIL_SECRET_SALT: '$2b$12$XUG.sKxC2jmkUvWQjg53.e' PRIVATE_KEY: '02...0b' PUBLIC_KEY: '02...0b' # Switch DEBUG to false if you go into production DEBUG: False # Adjust this according to Django Documentation # https://docs.djangoproject.com/en/2.2/ref/settings/ ALLOWED_HOSTS: ['*'] # Cache enabled without belows Redis may lead to unexpected behaviour # Cache with Redis # By default you should use something different than database 0 or 1, e.g. 13 # (default max is 16, can be configured in redis.conf) possible URLS are: # redis://[:password]@localhost:6379/0 # rediss://[:password]@localhost:6379/0 # unix://[:password]@/path/to/socket.sock?db=0 # CACHE_ENABLE: False # CACHE_REDIS: False # CACHE_REDIS_LOCATION: 'redis://127.0.0.1:6379/13' # The LDAP configuration # The syntax / feature follows the same approach as Psono server so please check the documentation # for alternative configurations / installation details # e.g. https://doc.psono.com/admin/configuration/ldap-ad.html LDAP: [ { 'LDAP_URL': 'ldap://dc01.example.com:389', 'LDAP_DOMAIN': 'example.com', 'LDAP_REQUIRED_GROUP': [], 'LDAP_BIND_DN': 'CN=LDAPPsono,OU=UsersTech,OU=example.com,DC=example,DC=com', 'LDAP_BIND_PASS': 'thePasswordForTheUserAbove', 'LDAP_SEARCH_USER_DN': 'OU=Users,OU=example.com,DC=example,DC=com', 'LDAP_SEARCH_GROUP_DN': 'DC=example,DC=com', 'LDAP_ATTR_USERNAME': 'sAMAccountName', 'LDAP_ATTR_EMAIL': 'mail', }, ]
Test your integration
To test the settings you can use the
testldap
command like shown belowdocker run --rm \ -v /opt/docker/ldapgateway/settings.yaml:/root/.ldapgw/settings.yaml \ -ti esaqa/ldap-gateway:latest python3 ./ldapgw/manage.py testldap username@something.com thePassWord
Create Client
You can create a client on the command line with the following command.
docker run --rm \ -v /opt/docker/ldapgateway/settings.yaml:/root/.ldapgw/settings.yaml \ -ti esaqa/ldap-gateway:latest python3 ./ldapgw/manage.py generateclient
The output will look similar to this:
# Add this content into your settings.yml of the ldap gateway CLIENTS: [ { 'CLIENT_ID': '6e983a0d-6a60-4d9f-9595-12416aec74da', 'CLIENT_PUBLIC_KEY': 'f0...61', 'CLIENT_VERIFY_KEY': 'bf...25', }, ] # And these are the parameters for your application CLIENT_ID: '6e983a0d-6a60-4d9f-9595-12416aec74da' CLIENT_PRIVATE_KEY: '76...ee' SERVER_PUBLIC_KEY: '02...0b'
Add
CLIENTS
tosettings.yaml
Add the
CLIENTS
-section of the last command to thesettings.yaml
of the gateway. Take note of the last three parameters (CLIENT_ID
,CLIENT_PRIVATE_KEY
,SEVER_PUBLIC_KEY
) as you will need them later for the configuration of the Psono EE Server.Run the gateway container and expose the server port
docker run --name ldap-gateway \ -v /opt/docker/ldapgateway/settings.yaml:/root/.ldapgw/settings.yaml \ -d --restart=unless-stopped -p 10109:80 esaqa/ldap-gateway:latest
This will start the LDAP gateway on port 10109. If you open now http://your-ip:10109/info/ you should see something like this:
{"info":"{\"version\": \"....}
If you don't, please make sure no firewall is blocking your request.
# Reverse Proxy with Nginx
Install Nginx
sudo apt-get install nginx
Create nginx config
Create
ldapgateway.example.com.conf
in/etc/nginx/sites-available
with the following content:server { listen 80; server_name ldapgateway.example.com; return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name ldapgateway.example.com; ssl_protocols TLSv1.2; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; ssl_stapling on; ssl_stapling_verify on; ssl_session_timeout 1d; resolver 8.8.8.8 8.8.4.4 valid=300s; resolver_timeout 5s; ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; # Comment this in if you know what you are doing # add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"; add_header Referrer-Policy same-origin; add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; # If you have the fileserver too, then you have to add your fileserver URL e.g. https://fs01.example.com as connect-src too: add_header Content-Security-Policy "default-src 'none'; manifest-src 'self'; connect-src 'self'; font-src 'self'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'self'"; ssl_certificate /etc/ssl/fullchain_ldapgateway.pem; ssl_certificate_key /etc/ssl/privkey_ldapgateway.pem; client_max_body_size 256m; gzip on; gzip_disable "msie6"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_min_length 256; gzip_types text/plain text/css application/json application/x-javascript application/javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon; root /var/www/html; location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; add_header Last-Modified $date_gmt; add_header Pragma "no-cache"; add_header Cache-Control "private, max-age=0, no-cache, no-store"; if_modified_since off; expires off; etag off; proxy_pass http://localhost:10109; } }
Enable nginx config
ln -s /etc/nginx/sites-available/ldapgateway.example.com.conf /etc/nginx/sites-enabled/
Test nginx config
sudo nginx -t
Restart nginx
sudo service nginx restart
If you open https://ldapgateway.example.com/info/ you should see the following:
{"info":"{\"version\": \"....}
# Configuration of Psono EE Server
Modify the
settings.yaml
of the Psono EE serverDuring the installation of Psono EE server you created a
settings.yaml
. Add these last three parameters (CLIENT_ID, CLIENT_PRIVATE_KEY, SEVER_PUBLIC_KEY) asLDAPGATEWAY
as shown below:LDAPGATEWAY: [ { 'CLIENT_ID': '8b02a601-d590-458d-b47c-45042b5a50b7', 'CLIENT_PRIVATE_KEY': '59...da', 'SERVER_PUBLIC_KEY': '02...0b', 'SERVER_URL': 'https://ldapgateway.example.com', }, ]
Replace
https://ldapgateway.example.com
with the URL that you you used before for the reverse proxy configuration.(optional) LDAP Gateway exclusive secrets
At the moment the server would still use the
DB_SECRET
to encrypt all user / group secrets. So you can switch out the LDAP config for the gateway and visa versa at any point. From a security standpoint you should use the secrets provided by the gateway. To do that you have to add the following line to your Psono's serversettings.yaml
LDAPGATEWAY_EXCLUSIVE_SECRETS: True
This will instruct Psono to use the secrets of the LDAP gateway to encrypt all user and group secrets.
WARNING
This process is irreversible. The server cannot decrypt any secrets without the help of the LDAP gateway.
WARNING
This setting is exclusive and cannot be used in combination with directly connected LDAP servers.
Test your integration
To test the settings you can use the
testldapgateway
command like shown belowdocker run --rm \ -v /opt/docker/psono/settings.yaml:/root/.psono_server/settings.yaml \ -ti psono/psono-combo-enterprise:latest python3 ./psono/manage.py testldapgateway username@something.com thePassWord
Finished
Whenever a user logs in with LDAP, the server will now contact the LDAP gateway to verify the provided credentials.
# Note: Installation behind Firewall
If you have put your installation behind a firewall, you have to whitelist some ports / adjust some settings, that all features work:
- Incoming TCP connections (usually Port 443) from servers to gateways
- Outgoing TCP / UDP 123 connection to time.google.com: The gateway requires a synced time for various reasons (Throttling, Replay protection, ...)
Therefore it has a healthcheck, to compare the local time to a time server (by default time.google.com). You can specify your own timeserver in the
settings.yaml
with theTIME_SERVER
parameter. - Outgoing TCP connection (usually 636) to your LDAP server
← LDAP Extras LDAP - AD →