522 lines
14 KiB
HCL
522 lines
14 KiB
HCL
job "lemonldap-ng" {
|
|
|
|
|
|
datacenters = ["dc1"]
|
|
region = "global"
|
|
priority = 60
|
|
|
|
|
|
constraint {
|
|
operator = "distinct_hosts"
|
|
value = "true"
|
|
}
|
|
|
|
|
|
|
|
group "lemonldap-ng" {
|
|
|
|
count = 1
|
|
shutdown_delay = "6s"
|
|
|
|
|
|
|
|
constraint {
|
|
operator = "distinct_hosts"
|
|
value = "true"
|
|
}
|
|
|
|
|
|
network {
|
|
mode = "bridge"
|
|
}
|
|
|
|
service {
|
|
name = "lemonldap-ng"
|
|
port = 8080
|
|
|
|
meta {
|
|
alloc = "${NOMAD_ALLOC_INDEX}"
|
|
datacenter = "${NOMAD_DC}"
|
|
group = "${NOMAD_GROUP_NAME}"
|
|
job = "${NOMAD_JOB_NAME}"
|
|
namespace = "${NOMAD_NAMESPACE}"
|
|
node = "${node.unique.name}"
|
|
region = "${NOMAD_REGION}"
|
|
}
|
|
|
|
connect {
|
|
sidecar_service {
|
|
proxy {
|
|
upstreams {
|
|
destination_name = "postgres"
|
|
local_bind_port = 5432
|
|
# Work arround, see https://github.com/hashicorp/nomad/issues/18538
|
|
destination_type = "service"
|
|
}
|
|
}
|
|
}
|
|
sidecar_task {
|
|
config {
|
|
args = [
|
|
"-c",
|
|
"${NOMAD_SECRETS_DIR}/envoy_bootstrap.json",
|
|
"-l",
|
|
"${meta.connect.log_level}",
|
|
"--concurrency",
|
|
"${meta.connect.proxy_concurrency}",
|
|
"--disable-hot-restart"
|
|
]
|
|
}
|
|
|
|
resources {
|
|
cpu = 50
|
|
memory = 64
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
tags = [
|
|
|
|
"traefik.http.routers.lemonldap-ng-portal.rule=Host(`sso.example.org`) && !PathRegexp(`^/index\\.psgi/(config|sessions)`)",
|
|
|
|
"traefik.enable=true",
|
|
"traefik.http.routers.lemonldap-ng-portal.entrypoints=https",
|
|
"traefik.http.routers.lemonldap-ng-portal.middlewares=security-headers@file,rate-limit-std@file,forward-proto@file,inflight-std@file,hsts@file,compression@file",
|
|
|
|
|
|
|
|
"traefik.enable=true",
|
|
"traefik.http.routers.lemonldap-ng-manager.entrypoints=https",
|
|
"traefik.http.routers.lemonldap-ng-manager.rule=Host(`manager.example.org`)",
|
|
"traefik.http.routers.lemonldap-ng-manager.middlewares=security-headers@file,rate-limit-std@file,forward-proto@file,inflight-std@file,hsts@file,compression@file",
|
|
|
|
|
|
"traefik.http.routers.lemonldap-ng-api.rule=Host(`sso.example.org`) && PathRegexp(`^/index\\.psgi/(config|sessions)`)",
|
|
|
|
|
|
|
|
]
|
|
}
|
|
|
|
# wait for required services tp be ready before starting the main task
|
|
task "wait-for" {
|
|
|
|
driver = "docker"
|
|
user = 1053
|
|
|
|
config {
|
|
image = "danielberteaud/wait-for:24.3-1"
|
|
readonly_rootfs = true
|
|
pids_limit = 20
|
|
}
|
|
|
|
lifecycle {
|
|
hook = "prestart"
|
|
}
|
|
|
|
env {
|
|
SERVICE_0 = "postgres.service.consul"
|
|
}
|
|
|
|
resources {
|
|
cpu = 10
|
|
memory = 10
|
|
memory_max = 30
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
task "lemonldap-ng" {
|
|
driver = "docker"
|
|
|
|
config {
|
|
image = "danielberteaud/lemonldap-ng:2.18.2-2"
|
|
readonly_rootfs = true
|
|
pids_limit = 200
|
|
volumes = [
|
|
"secrets/lemonldap-ng.ini:/etc/lemonldap-ng/lemonldap-ng.ini:ro",
|
|
"local/init-db.sh:/entrypoint.d/20-initdb.sh:ro",
|
|
"local/minit.d/lemonldap-ng.yml:/etc/minit.d/lemonldap-ng.yml:ro"
|
|
]
|
|
mount {
|
|
type = "tmpfs"
|
|
target = "/tmp"
|
|
tmpfs_options {
|
|
size = 5000000
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
vault {
|
|
policies = ["lemonldap-ng"]
|
|
env = false
|
|
disable_file = true
|
|
change_mode = "noop"
|
|
}
|
|
|
|
|
|
|
|
artifact {
|
|
source = "git::https://git.lapiole.org/nomad/lemonldap-ng.git//files/assets"
|
|
destination = "local/assets/static/common"
|
|
}
|
|
|
|
|
|
env {
|
|
LLNG_NGINX_LISTEN = "127.0.0.1:8080"
|
|
LLNG_LISTEN = "unix:/tmp/llng.sock"
|
|
LLNG_MANAGER_VHOST = "manager.example.org"
|
|
LLNG_PORTAL_VHOST = "sso.example.org"
|
|
LLNG_CUSTOM_ASSETS_DIR = "/local/assets"
|
|
}
|
|
|
|
|
|
|
|
# Use a template block instead of env {} so we can fetch values from vault
|
|
template {
|
|
data = <<_EOT
|
|
LANG=fr_FR.utf8
|
|
LLNG_WORKERS=6
|
|
TZ=Europe/Paris
|
|
_EOT
|
|
destination = "secrets/.env"
|
|
perms = 400
|
|
env = true
|
|
}
|
|
|
|
|
|
# Main Lemonldap::NG configuration
|
|
template {
|
|
data = <<_EOT
|
|
[all]
|
|
logLevel = notice
|
|
localSessionStorage = Cache::FileCache
|
|
localSessionStorageOptions = { \
|
|
'namespace' => 'sessions', \
|
|
'default_expires_in' => '60', \
|
|
'directory_umask' => '007', \
|
|
'cache_root' => '/tmp', \
|
|
'cache_depth' => 3 \
|
|
}
|
|
globalStorage = Apache::Session::Browseable::PgJSON
|
|
globalStorageOptions = { \
|
|
'DataSource' => 'DBI:Pg:', \
|
|
'TableName' => 'sessions', \
|
|
'generateModule' => 'Lemonldap::NG::Common::Apache::Session::Generate::SHA256', \
|
|
'Commit' => 1 \
|
|
}
|
|
persistentStorage = Apache::Session::Browseable::PgJSON
|
|
persistentStorageOptions = { \
|
|
'DataSource' => 'DBI:Pg:', \
|
|
'TableName' => 'psessions', \
|
|
'generateModule' => 'Lemonldap::NG::Common::Apache::Session::Generate::SHA256', \
|
|
'Commit' => 1 \
|
|
}
|
|
samlStorage = Apache::Session::Browseable::PgJSON
|
|
samlStorageOptions = { \
|
|
'DataSource' => 'DBI:Pg:', \
|
|
'TableName' => 'samlsessions', \
|
|
'generateModule' => 'Lemonldap::NG::Common::Apache::Session::Generate::SHA256', \
|
|
'Commit' => 1 \
|
|
}
|
|
oidcStorage = Apache::Session::Browseable::PgJSON
|
|
oidcStorageOptions = { \
|
|
'DataSource' => 'DBI:Pg:', \
|
|
'TableName' => 'oidcsessions', \
|
|
'generateModule' => 'Lemonldap::NG::Common::Apache::Session::Generate::SHA256', \
|
|
'Commit' => 1 \
|
|
}
|
|
casStorage = Apache::Session::Browseable::PgJSON
|
|
casStorageOptions = { \
|
|
'DataSource' => 'DBI:Pg:', \
|
|
'TableName' => 'cassessions', \
|
|
'generateModule' => 'Lemonldap::NG::Common::Apache::Session::Generate::SHA256', \
|
|
'Commit' => 1 \
|
|
}
|
|
|
|
notificationStorage = DBI
|
|
notificationStorageOptions = { \
|
|
'dbiChain' => 'DBI:Pg:', \
|
|
'dbiTable' => 'notifications', \
|
|
'type' => 'CDBI', \
|
|
}
|
|
|
|
status = 1
|
|
|
|
[configuration]
|
|
useServerEnv = 1
|
|
type = CDBI
|
|
dbiChain = DBI:Pg:
|
|
localStorage = Cache::FileCache
|
|
localStorageOptions = { \
|
|
'namespace' => 'config', \
|
|
'default_expires_in' => '60', \
|
|
'directory_umask' => '007', \
|
|
'cache_root' => '/tmp', \
|
|
'cache_depth' => 0 \
|
|
}
|
|
|
|
[manager]
|
|
protection = manager
|
|
enabledModules = conf, sessions, notifications, 2ndFA
|
|
staticPrefix = /static
|
|
templateDir = /usr/share/lemonldap-ng/manager/htdocs/templates
|
|
languages = en
|
|
|
|
[portal]
|
|
staticPrefix = /static
|
|
templateDir = /usr/share/lemonldap-ng/portal/templates
|
|
languages = en, fr, es, it, de
|
|
forceGlobalStorageUpgradeOTT = 1
|
|
|
|
|
|
_EOT
|
|
destination = "secrets/lemonldap-ng.ini"
|
|
uid = 100048
|
|
gid = 100048
|
|
perms = 440
|
|
}
|
|
|
|
# This is a striped down config, just used to migrate file based config to database on first start
|
|
template {
|
|
data = <<_EOT
|
|
[all]
|
|
|
|
[configuration]
|
|
type = File
|
|
dirName = /local
|
|
|
|
|
|
_EOT
|
|
destination = "local/init.ini"
|
|
}
|
|
|
|
# Database settings
|
|
template {
|
|
data = <<_EOT
|
|
PGHOST=127.0.0.1
|
|
PGDATABASE=lemonldap-ng
|
|
PGSSLMODE=disable
|
|
PGPORT=5432
|
|
PGUSER={{ with secret "database/creds/lemonldap-ng" }}{{ .Data.username }}{{ end }}
|
|
PGPASSWORD={{ with secret "database/creds/lemonldap-ng" }}{{ .Data.password }}{{ end }}
|
|
_EOT
|
|
destination = "secrets/.db.env"
|
|
uid = 100000
|
|
gid = 100000
|
|
perms = 400
|
|
env = true
|
|
}
|
|
|
|
# A small script to handle initialization (create tables, indexes, load initial config in the DB)
|
|
template {
|
|
data = <<_EOT
|
|
#!/bin/sh
|
|
|
|
set -euo pipefail
|
|
|
|
echo "Create tables if needed"
|
|
psql -f /usr/share/lemonldap-ng/ressources/lemonldap-ng.postgres.sql
|
|
|
|
if [ "$(psql -qAtc 'SELECT COUNT(1) FROM lmConfig')" = "0" ]; then
|
|
echo "Load initial configuration in database"
|
|
/usr/libexec/lemonldap-ng/bin/convertConfig \
|
|
--current=/local/init.ini \
|
|
--new=/etc/lemonldap-ng/lemonldap-ng.ini
|
|
fi
|
|
|
|
_EOT
|
|
destination = "local/init-db.sh"
|
|
perms = 755
|
|
}
|
|
|
|
# Custom file based config, which will be migrated to the database
|
|
template {
|
|
data = <<_EOT
|
|
{
|
|
"applicationList" : {
|
|
"2administration" : {
|
|
"catname" : "Administration",
|
|
"manager" : {
|
|
"options" : {
|
|
"description" : "Configure LemonLDAP::NG WebSSO",
|
|
"display" : "auto",
|
|
"logo" : "configure.png",
|
|
"name" : "WebSSO Manager",
|
|
"uri" : "https://manager.example.org/manager.html"
|
|
},
|
|
"type" : "application"
|
|
},
|
|
"notifications" : {
|
|
"options" : {
|
|
"description" : "Explore WebSSO notifications",
|
|
"display" : "auto",
|
|
"logo" : "database.png",
|
|
"name" : "Notifications Explorer",
|
|
"uri" : "https://manager.example.org/notifications.html"
|
|
},
|
|
"type" : "application"
|
|
},
|
|
"sessions" : {
|
|
"options" : {
|
|
"description" : "Explore WebSSO sessions",
|
|
"display" : "auto",
|
|
"logo" : "database.png",
|
|
"name" : "Sessions Explorer",
|
|
"uri" : "https://manager.example.org/sessions.html"
|
|
},
|
|
"type" : "application"
|
|
},
|
|
"type" : "category"
|
|
},
|
|
"3documentation" : {
|
|
"catname" : "Documentation",
|
|
"localdoc" : {
|
|
"options" : {
|
|
"description" : "Documentation supplied with LemonLDAP::NG",
|
|
"display" : "on",
|
|
"logo" : "help.png",
|
|
"name" : "Local documentation",
|
|
"uri" : "https://manager.example.org/doc/"
|
|
},
|
|
"type" : "application"
|
|
},
|
|
"officialwebsite" : {
|
|
"options" : {
|
|
"description" : "Official LemonLDAP::NG Website",
|
|
"display" : "on",
|
|
"logo" : "network.png",
|
|
"name" : "Official Website",
|
|
"uri" : "https://lemonldap-ng.org/"
|
|
},
|
|
"type" : "application"
|
|
},
|
|
"type" : "category"
|
|
}
|
|
},
|
|
"authentication" : "Demo",
|
|
"cfgAuthor" : "Daniel Berteaud",
|
|
"cfgDate" : "1627287638",
|
|
"cfgNum" : 1,
|
|
"cfgVersion" : "2.18.0",
|
|
"cookieName" : "lemonldap",
|
|
"demoExportedVars" : {
|
|
"cn" : "cn",
|
|
"mail" : "mail",
|
|
"uid" : "uid"
|
|
},
|
|
"domain" : "example.com",
|
|
"exportedHeaders" : {
|
|
"test1.example.com" : {
|
|
"Auth-Groups" : "$groups",
|
|
"Auth-User" : "$uid"
|
|
},
|
|
"test2.example.com" : {
|
|
"Auth-Groups" : "$groups",
|
|
"Auth-User" : "$uid"
|
|
}
|
|
},
|
|
"exportedVars" : {},
|
|
"groups" : {},
|
|
"localSessionStorage" : "Cache::FileCache",
|
|
"localSessionStorageOptions" : {
|
|
"cache_depth" : 3,
|
|
"cache_root" : "/tmp",
|
|
"default_expires_in" : 600,
|
|
"directory_umask" : "007",
|
|
"namespace" : "sessions"
|
|
},
|
|
"globalStorage" : "Apache::Session::Browseable::PgJSON",
|
|
"globalStorageOptions" : {
|
|
"DataSource" : "DBI:Pg:",
|
|
"TableName" : "sessions",
|
|
"generateModule" : "Lemonldap::NG::Common::Apache::Session::Generate::SHA256",
|
|
"Commit" : 1
|
|
},
|
|
"locationRules" : {
|
|
"sso.example.org" : {
|
|
"(?#checkUser)^/checkuser" : "inGroup(\"timelords\")",
|
|
"(?#errors)^/lmerror/" : "accept",
|
|
"default" : "accept"
|
|
},
|
|
"manager.example.org" : {
|
|
"(?#Configuration)^/(.*?\\.(fcgi|psgi)/)?(manager\\.html|confs|prx/|$)" : "inGroup(\"timelords\")",
|
|
"(?#Notifications)/(.*?\\.(fcgi|psgi)/)?notifications" : "inGroup(\"timelords\") or $uid eq \"rtyler\"",
|
|
"(?#Sessions)/(.*?\\.(fcgi|psgi)/)?sessions" : "inGroup(\"timelords\") or $uid eq \"rtyler\"",
|
|
"default" : "inGroup(\"timelords\") or $uid eq \"rtyler\""
|
|
}
|
|
},
|
|
"loginHistoryEnabled" : 1,
|
|
"macros" : {
|
|
"UA" : "$ENV{HTTP_USER_AGENT}",
|
|
"_whatToTrace" : "$_auth eq 'SAML' ? lc($_user.'@'.$_idpConfKey) : $_auth eq 'OpenIDConnect' ? lc($_user.'@'.$_oidc_OP) : lc($_user)"
|
|
},
|
|
"notification" : 1,
|
|
"oidcServiceIgnoreScopeForClaims" : 1,
|
|
"passwordDB" : "Demo",
|
|
"portal" : "https://sso.example.org/",
|
|
"portalSkin" : "bootstrap",
|
|
"portalSkinBackground" : "1280px-Cedar_Breaks_National_Monument_partially.jpg",
|
|
"registerDB" : "Demo",
|
|
"reloadUrls" : {
|
|
"localhost" : "http://localhost:8080/reload"
|
|
},
|
|
"securedCookie" : 0,
|
|
"sessionDataToRemember" : {},
|
|
"timeout" : 72000,
|
|
"userDB" : "Same",
|
|
"whatToTrace" : "_whatToTrace"
|
|
}
|
|
|
|
_EOT
|
|
destination = "local/lmConf-1.json"
|
|
}
|
|
|
|
# Configure minit to start uwsgi, nginx, cron tasks
|
|
template {
|
|
data = <<_EOT
|
|
---
|
|
kind: daemon
|
|
name: lemonldap
|
|
command: ["lemonldap-ng"]
|
|
|
|
---
|
|
kind: daemon
|
|
name: nginx
|
|
command: ["nginx", "-c", "${LLNG_NGINX_CONF}"]
|
|
|
|
---
|
|
kind: cron
|
|
name: local_cache
|
|
command: ["/usr/libexec/lemonldap-ng/bin/purgeLocalCache"]
|
|
cron: "@every 1h"
|
|
|
|
{{- if eq (env "NOMAD_ALLOC_INDEX") "0" }}
|
|
|
|
---
|
|
kind: cron
|
|
name: clean_global_cache
|
|
cron: "@every 10m"
|
|
command: ["/usr/libexec/lemonldap-ng/bin/purgeCentralCache"]
|
|
{{- end }}
|
|
|
|
_EOT
|
|
destination = "local/minit.d/lemonldap-ng.yml"
|
|
}
|
|
|
|
|
|
resources {
|
|
cpu = 500
|
|
memory = 512
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|