lemonldap-ng/example/lemonldap-ng.nomad.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
}
}
}
}