LemonLDAP-NG in Podman

Ive managed to get LemonLDAP-NG mostly working here are the steps.

  1. Install scratchpad instance

  2. In ns8 http routes add auth.domain.tld as http://127.0.0.1:82 and manager.domain.tld http://127.0.0.1:82

  3. runagent -m scratchpad1 bash -l

  4. podman run --replace --name lemonldap -d -e SSODOMAIN=domain.tld -e PORTAL_HOSTNAME=auth.domain.tld -e MANAGER_HOSTNAME=manager.domain.tld -e HANDLER_HOSTNAME=handler.domain.tld -e FASTCGI_LISTEN_PORT=9000 -p 82:80 docker.io/coudot/lemonldap-ng

  5. run podman ps to get


I’ve figured out how to add files to the running container its a bit convuluted but it allows to upload logos and app logos.

You first have to copy the files you want to the scratchpad home folder (i.e., /home/scratchpad1 then you have to runagent -m scratchpad1 bash -l for example ill use mylam.webp (for the LAM web app) you then copy them directly into the container folder like so podman cp ~/mylam.webp <your containerid>:/usr/share/lemonldap-ng/portal/htdocs/static/common/apps/ and restart podman restart <your containerid> and it works


The directorys that are most used are:
:/usr/share/lemonldap-ng/portal/htdocs/static/common/apps/ for apps
:/usr/share/lemonldap-ng/portal/htdocs/static/common/logos/ for logos
:/usr/share/lemonldap-ng/portal/htdocs/static/common/backgrounds/ for backgrounds

NOTE* I havent got background working yet but I manual added the active directory details and saml and everything else seems to work

UPDATE* I had a power failure and when ns8 booted back up the container wasnt working so im guessing this is not persistant. I’m in the process of mapping the volumes (i.e., apps,logos and backgrounds) once I’ve worked out the specifics I’ll post an update. For now I know the volume is something like -v .apps/.:/usr/share/lemonldap-ng/portal/htdocs/static/common/apps:Z

5 Likes

UPDATE This now works with apps, backgrounds, logos, conf, logs and the lemonldap.ini file

  1. Install a scratchpad instance.

  2. In ns8 http routes add auth.domain.tld as http://127.0.0.1:82 and manager.domain.tld http://127.0.0.1:82

  3. Login from terminal.

[root@yourserver]$ runagent -m scratchpad1 bash -l
  1. Create the folders were going to mount
[scratchpad1@yourserver state]$ mkdir -p ./apps
[scratchpad1@yourserver state]$ mkdir -p ./conf
[scratchpad1@yourserver state]$ mkdir -p ./logos
[scratchpad1@yourserver state]$ mkdir -p ./backgrounds
[scratchpad1@yourserver state]$ mkdir -p ./logs
[scratchpad1@yourserver state]$ mkdir -p ./etc
[scratchpad1@yourserver state]$ mkdir -p ./cache
  1. Now create the mounts themselves
podman volume create \
      -o device=./apps \
      -o=o=bind \
      apps
podman volume create \
      -o device=./conf \
      -o=o=bind \
      conf
podman volume create \
      -o device=./etc \
      -o=o=bind \
      etc
podman volume create \
      -o device=./logos \
      -o=o=bind \
      logos
podman volume create \
      -o device=./backgrounds \
      -o=o=bind \
      backgrounds
podman volume create \
      -o device=./cache \
      -o=o=bind \
     cache
podman volume create \
      -o device=./logs \
      -o=o=bind \
      logs
  1. Run the following commands (make sure to change to suit your requirements)
podman run --detach --replace --name lemonldap --restart=unless-stopped \
    --volume=apps:/usr/share/lemonldap-ng/portal/htdocs/static/common/apps:z \
    --volume=backgrounds:/usr/share/lemonldap-ng/portal/htdocs/static/common/backgrounds:z \
    --volume=logos:/usr/share/lemonldap-ng/portal/htdocs/static/common/logos:z \
    --volume=conf:/var/lib/lemonldap-ng/conf:z \
    --volume=logs:/www/logs:z \
    --volume=etc:/etc/lemonldap-ng:z \
    --volume=cache:/var/cache/lemonldap-ng:z \
    -e SSODOMAIN=domain.tld \
    -e PORTAL_HOSTNAME=auth.domain.tld \
    -e MANAGER_HOSTNAME=manager.domain.tld \
    -e HANDLER_HOSTNAME=handler.domain.tld \
    -e TEST1_HOSTNAME=test1.domain.tld \
    -e TEST2_HOSTNAME=test2.domain.tld \
    -e LOGLEVEL=debug \
    -e TZ="Country/City" \
    -e FASTCGI_LISTEN_PORT=9000 \
    -p 82:80  \
    docker.io/coudot/lemonldap-ng:latest
4 Likes

I am at the capitole du libre today, and I met some developers of the lemonldap software. Really interesting :slight_smile:

They have made fusionIAM. A bundle of many tools

4 Likes

now the next step is to make it run at boot i tried following slide 38 Run any service on NS8 but it failed after Run any service on NS8 slide 41
if anyone has any sugestions that would be great

@davidep

the steps i took

podman generate systemd -f \
     --no-header \
     --container-prefix '' \
     --new \
     4e9c949c5638
mv -vf \
     /home/scratchpad18/.config/state/4e9c949c5638fd8f770ed214adc2002f7a459e9f9d9ec6f6909189481e117219.service \
     ../systemd/user/4e9c949c5638.service
systemctl \
     --user enable --now 4e9c949c5638

and the error

Ă— 4e9c949c5638.service - Podman 4e9c949c5638fd8f770ed214adc2002f7a459e9f9d9ec6f6909189481e117219.service
     Loaded: loaded (/home/scratchpad18/.config/systemd/user/4e9c949c5638.service; enabled; preset: disabled)
     Active: failed (Result: exit-code) since Sun 2024-11-17 13:04:54 AEST; 23s ago
       Docs: man:podman-generate-systemd(1)
    Process: 137016 ExecStart=/usr/bin/podman run --cidfile=/run/user/1020/4e9c949c5638.service.ctr-id --cgroups=no-conmon --rm --sdnotify=conmon --detach --replace --name lemon>
    Process: 137049 ExecStopPost=/usr/bin/podman rm -f --ignore -t 10 --cidfile=/run/user/1020/4e9c949c5638.service.ctr-id (code=exited, status=0/SUCCESS)
   Main PID: 137016 (code=exited, status=126)
        CPU: 384ms

On the plus side without using systemd, simply rerunning the podman run script brings the system back to how it was before the restart so maybe I could just have that run on reboot somehow

now i managed to get the systemd config working if i run the container as root not as scratchpad, however although it reboots fine it doesnt keep the config and starts as a fresh install (lemonldap)

–Update–
i just realised wht i did wrong

when issuing podman generate systemd --new --name lemonldap --new makes the system run the podman run script and replaces the old

so once i ran the cmd without --new i got it working ill post a how to soon

ill also try to see if i can replicate it in scratchpad as well

1 Like

when you are ready to go over a prototype you can start from GitHub - stephdl/ns8-kickstart-mariadb: NethServer 8 module template

or you could have here some examples on how to have a systemd service running from a pod

3 Likes

untill i get a working module I’ve created a script that creates the following folders under /opt/lemonldap:
backups, apps, logos, logs, conf, etc and cache.
It then mounts them for use in the podmain container, next it asks you what port is free along with your country and city to set timezone variables.

Then it creates the systemd files and moves it to /etc/systemd/system/ns8-lemonldap.service and reloads systemd and enables ns8-lemonldap.service.

It also creats a script called ~/lemon_setup.sh and makes it executable, this script purges the conf, cache, etc and logs folders along with the systemd service file leaving the apps, logos and backgrounds folders, recreates the conf, cache, logs and etc folders and remounts them.

Then it reruns the podman run script with the answers you gave during setup and recreates the systemd service file and reenables it so it the installation starts fresh but the apps logos and backgrounds remain.

you can then load a config file from a backup in the manager.

Default login is
User: dwho
Password: dwho

ns8-lemonldap.sh
#!/bin/bash

read -p "What is the unbound port to run LemonLDAP-NG on?" 'port'

read -p "What is your Country?" 'country'

read -p "What is your City?" 'city'

mkdir -p /opt/lemonldap /opt/lemonldap/backrounds /opt/lemonldap/apps /opt/lemonldap/logos /opt/lemonldap/logs /opt/lemonldap/cache /opt/lemonldap/conf /opt/lemonldap/etc 

# chown root:root -R /opt/lemonldap /opt/lemonldap/backrounds /opt/lemonldap/apps /opt/lemonldap/logos /opt/lemonldap/logs /opt/lemonldap/cache /opt/lemonldap/conf /opt/lemonldap/etc

podman volume create \
      -o device=/opt/lemonldap/backrounds \
      -o=o=bind \
      backgrounds

podman volume create \
      -o device=/opt/lemonldap/conf \
      -o=o=bind \
      conf

podman volume create \
      -o device=/opt/lemonldap/logos \
      -o=o=bind \
      logos

podman volume create \
      -o device=/opt/lemonldap/apps \
      -o=o=bind \
      apps

podman volume create \
      -o device=/opt/lemonldap/logs \
      -o=o=bind \
      logs

podman volume create \
      -o device=/opt/lemonldap/cache \
      -o=o=bind \
      cache

podman volume create \
      -o device=/opt/lemonldap/etc \
      -o=o=bind \
      etc

podman run --detach --replace --name ns8-lemonldap \
    --volume=apps:/usr/share/lemonldap-ng/portal/htdocs/static/common/apps:z \
    --volume=backgrounds:/usr/share/lemonldap-ng/portal/htdocs/static/common/backgrounds:z \
    --volume=logos:/usr/share/lemonldap-ng/portal/htdocs/static/common/logos:z \
    --volume=conf:/var/lib/lemonldap-ng/conf:z \
    --volume=logs:/www/logs:z \
    --volume=etc:/etc/lemonldap-ng:z \
    --volume=cache:/var/cache/lemonldap-ng:z \
    -e SSODOMAIN=$domain \
    -e PORTAL_HOSTNAME=auth.$(hostname -d) \
    -e MANAGER_HOSTNAME=mymanager.$(hostname -d) \
    -e HANDLER_HOSTNAME=handler.$(hostname -d) \
    -e TEST1_HOSTNAME=test1.$(hostname -d) \
    -e TEST2_HOSTNAME=test2.$(hostname -d) \
    -e LOGLEVEL=debug \
    -e TZ="$country/$city" \
    -e FASTCGI_LISTEN_PORT=9000 \
    -p $port:80 \
    docker.io/coudot/lemonldap-ng:latest
wait

cat <<EOF >>~/lemon_setup.sh
#!/bin/sh
# Created on $(date )
rm -Rf /etc/systemd/system/lemonldap.service  /opt/container-ns8-lemonldap.service
podman volume rm -f etc conf cache logs

rm -Rf /opt/lemonldap/cache /opt/lemonldap/conf /opt/lemonldap/etc /opt/lemonldap/logs

mkdir -p /opt/lemonldap/cache /opt/lemonldap/conf /opt/lemonldap/etc /opt/lemonldap/logs
# chown root:root -R /opt/lemonldap/logs /opt/lemonldap/cache /opt/lemonldap/conf /opt/lemonldap/etc

podman volume create \
      -o device=/opt/lemonldap/conf \
      -o=o=bind \
      conf

podman volume create \
      -o device=/opt/lemonldap/cache \
      -o=o=bind \
      cache

podman volume create \
      -o device=/opt/lemonldap/etc \
      -o=o=bind \
      etc

podman volume create \
      -o device=/opt/lemonldap/logs \
      -o=o=bind \
      logs

podman run --detach --replace --name ns8-lemonldap \
    --volume=apps:/usr/share/lemonldap-ng/portal/htdocs/static/common/apps:z \
    --volume=backgrounds:/usr/share/lemonldap-ng/portal/htdocs/static/common/backgrounds:z \
    --volume=logos:/usr/share/lemonldap-ng/portal/htdocs/static/common/logos:z \
    --volume=conf:/var/lib/lemonldap-ng/conf:z \
    --volume=logs:/www/logs:z \
    --volume=etc:/etc/lemonldap-ng:z \
    --volume=cache:/var/cache/lemonldap-ng:z \
    -e SSODOMAIN=$domain \
    -e PORTAL_HOSTNAME=auth.$(hostname -d) \
    -e MANAGER_HOSTNAME=mymanager.$(hostname -d) \
    -e HANDLER_HOSTNAME=handler.$(hostname -d) \
    -e TEST1_HOSTNAME=test1.$(hostname -d) \
    -e TEST2_HOSTNAME=test2.$(hostname -d) \
    -e LOGLEVEL=debug \
    -e TZ="$country/$city" \
    -e FASTCGI_LISTEN_PORT=9000 \
    -p $port:80 \
    docker.io/coudot/lemonldap-ng:latest

podman generate systemd --name ns8-lemonldap -f > /etc/systemd/system/lemonldap.service
mv -vf \
         /opt/container-ns8-lemonldap.service \
         /etc/systemd/system/ns8-lemonldap.service
wait
podman stop ns8-lemonldap
systemctl daemon-reload
systemctl enable ns8-lemonldap.service
wait
systemctl start ns8-lemonldap
EOF

chmod +x ~/lemon_setup.sh

rm -Rf /opt/container-ns8-lemonldap.service /etc/systemd/system/lemonldap.service

podman generate systemd --name ns8-lemonldap -f > /etc/systemd/system/lemonldap.service
mv -vf \
         /opt/container-ns8-lemonldap.service \
         /etc/systemd/system/ns8-lemonldap.service
wait
podman stop ns8-lemonldap
systemctl daemon-reload
systemctl enable ns8-lemonldap.service
wait
api-cli run set-route --agent module/traefik1 --data - <<EOF
{
  "instance": "ns8auth",
  "url": "http://127.0.0.1:$port",
  "host": "auth.$(hostname -d)",
  "lets_encrypt": true,
  "http2https": true,
  "skip_cert_verify": false
}
EOF
wait
api-cli run set-route --agent module/traefik1 --data - <<EOF
{
  "instance": "ns8manager",
  "url": "http://127.0.0.1:$port",
  "host": "manager.$(hostname -d)",
  "lets_encrypt": true,
  "http2https": true,
  "skip_cert_verify": false
}
EOF
wait
systemctl start ns8-lemonldap


echo "LemonLDAP-NG has been installed please dont forget to setup the folowing http routes in NS8 1. add auth.$(hostname -d) as http://127.0.0.1:$port and manager.$(hostname -d) http://127.0.0.1:$port also select the options for lets encrypt and http to https"

echo " Once you have setup the http routes you should be able to access the portal at https://auth.$(hostname -d) and the manager at https://manager.$(hostname -d) "

Next steps for this script is:

  • auto propagating the ad/ldap details
  • Automating the http routes and let’s encrypt certificate
  • Backup
2 Likes

A root container is workable like you discovered but in short it is better to be rootless. It could be sometime a bit challenging but in term of security it is better

Your container has been hacked…no problem the concerns are limited to the user linux area in his /home

Relevant to the volume creation i think podman is able to create them automatically. No need to do it manually before to start container

If you follow the way of nethserver kickstart the route to traefik is done automatically by the UI and propagated to the API but it is a rootless container

2 Likes

I agree completely and that is the goal plus the lemon_setup.sh could be a systemd file on its own.

its a bit convoluted but in order to understand how all the system works (ie, podman systemd etc) is to get it working then to get it working as rootless and finally as a module.

i think ive got it working now in rootless without volumes

Using volumes for some reason didn’t work with systemd but thanks to @davidep How do you get ldap or samba details - #2 by davidep I should be able to auto generate the ad/ldap config part

1 Like

available any time for help, ping me

2 Likes

Thank you I’ll definitely take you up on that offer once I get the ad/ldap config automation working what should be a simple mater of a bash script with an api-cli cmd piped to sed cmds similar to the original lemon_config.sh

1 Like

I think we have something really simpler with some python libraries

Check also line 27 to 28

You need them in a rootless container to allow the bind to the ldapproxy port. In a rootfull container you do not need it

1 Like

Once the prototype or the proof of concept is done you should go to the module it will ease your life…for example to start the container, to write the route to traefik.

With the script you need to do each step. Obviously it could be done.

Do not be afraid of the UI stack it is not so hard and we have tons of example…for the backend you can start by writing directly the variables to the state/environment file and your container will get magically your settings

1 Like

This where we strore the environment vars to store the settings to the container

And this is where we trigger the script to autodiscover the ldap settings

And this is where we pass the file with the ldap settings

After that you need to send each variables in the container with --env LDAP_* or each vatiable if you prefer (sometimes i prefer a systemd a bit longer but easy to understand)

In this example I did not need it because i build configuration files on the fly but it is particular

4 Likes